Should all member variables be initialized in __init__ - python

Maybe this is more of a style question than a technical one but I have a class with several member variables and I want to have it work so that some of the member variables are initialized when the user first creates an instance of the class (i.e. in the __init__ function) and I want the other member variables to be defined from arguments of member functions that will be called later on. So my question is should I initialize all member variables in the __init__ function (and set the ones that will be defined later on to dummy values) or initialize some in the __init__ function and some in later functions. I realize this might be difficult to understand so here are a couple of examples.
This example has var3 set to 0 initially in the __init__ function, then set to the desired value later on in the my_funct function.
class myClass(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
self.var3=0
def my_funct(self,var3):
self.var3=var3
and in this example, var3 is not defined at all in the __init__ function
class myClass(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
def my_funct(self,var3):
self.var3=var3
I don't think either way would make a big difference (maybe a slight difference in memory usage). But I was wondering if one of these is preferred over the other for some reason.

In object-oriented programming it's up to the developer to ensure an object is always in a consistent state after instantiation and after a method finishes. Other than that you're free to develop the class as you wish (keeping in mind certain principles with subclassing / overriding and so on).
A tool such as Pylint will warn when you're setting instance variables outside __init__. It can be argued that setting all instance variables in the __init__ is cleaner but it's not a rule that must be abided by at all times.

I would actually discourage initializing variables you don't always need in __init__ to an arbitrary default value.
I do question your use of OO if this is the case, but I'm sure there is a valid and understandable case where __init__ will not do everything, and the class will want to further modify itself by adding additional attributes with other methods.
The proper way in my opinion to test if a variable was set while running a method that may want to use it would be to use hasattr. This is in the case that this is a valid way to use the method and the test just switches behavior in a sensible way.
Another way would be to try and use it and handle the exception and provide some user friendly information about what the user of your class is doing wrong. This is in the case the method needs the attribute to be set before running.
i.e. Hey man, you did initialize the class, but you need to make sure the z attribute exists by calling the z_init method before running the z_run method.
Another, arguably the more pythonic way, would be to just document how to use the method in the docstring and then let the exception fly when it is used improperly. This is good enough for the first implementation of something and you can then focus on the next task. This is in the same situation as above, the method needs the attribute to be set.
The reason I do not like the idea of initializing variables to arbitrary defaults is this can be confusing (because it is arbitrary) and is line noise.
If the value is not arbitrary and simply a default value that can be changed you should be using a default value in the __init__ method that can be overridden. It can also actually be a valid initial state, which is also not arbitrary and you should set it in the __init__ method.
So the real answer is it depends, and you should probably avoid it and question your use of OO if you are doing this either by adding attributes in other methods or initializing attributes to arbitrary values.
While Simeon Visser is saying to keep your object in a consistent state, he has no basis for what consistency is based on your abstract example. While Pylint warns on this kind of thing, warnings from lint programs are simply so a high level reviewer can be alerted of things that usually indicate code smell. I say high level reviewer because a real reviewer should be reading and understanding all of your code, and thus not really need Pylint.
An example that breaks the rule of thumb:
class Mutant(object):
"""A mutant!"""
def __init__(self):
"""A mutant is born with only 1 eye and 1 mouth"""
self.eyes = 1
self.mouth = 1
self.location = 'Montana'
def roll_to(self, location):
"""If they have limbs, running is less dangerous"""
if hasattr(self, 'limbs'):
print 'Your mutant broke its limbs off!!'
del self.limbs
self.location = location
def run_to(self, location):
"""If they don't have limbs, running is not effective"""
if not hasattr(self, 'limbs'):
print 'Your mutant tries to run but he has no limbs.'
else:
self.location = location
def grow_limbs(self, number_of_limbs):
"""Ah, evolution!"""
assert number_of_limbs > 0, 'Cannot grow 0 or less limbs...'
if hasattr(self, 'limbs'):
self.limbs += number_of_limbs
else:
self.limbs = number_of_limbs

Here is an excerpt from sololearn.com (a free site to learn python)
"Properties provide a way of customizing access to instance attributes.
They are created by putting the property decorator above a method, which means when the instance attribute with the same name as the method is accessed, the method will be called instead.
One common use of a property is to make an attribute read-only."
Example (also from sololearn.com):
class Pizza:
def __init__(self, toppings):
self.toppings = toppings
#property
def pineapple_allowed(self):
return False
pizza = Pizza(["cheese", "tomato"])
print(pizza.pineapple_allowed)
pizza.pineapple_allowed = True
Result:
>>>
False
AttributeError: can't set attribute
>>>
If var3 depends on var1 and var2 you could do
class myClass:
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
#property
def var3(self):
return(self.var1+self.var2) #var3 depends on var1 and var2
m1=myClass(1,2)
print(m1.var3) # var3 is 3
var3 can also be set to whatever you want using a setter function. Note that you can avoid setting var3 to an arbitrary value by using None.
class myClass2(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
self._var3=None # None or an initial value that makes sense
#property
def var3(self):
return(self._var3)
#var3.setter
def var3(self,value):
self._var3=value
m2=myClass(1,2)
print(m2.var3) # var3 is none
print(m2.var3(10)) # var3 is set to 10

Related

What is the point of setting an attribute of class equal to output of a method of the same class?

This question should pertain to all OOP languages, though I'm only familiar with C++ and Python. I've seen this in several codebases and have seen this in Python and I think also in C++. I will illustrate in Python:
class sim:
def __init__(self, name="sim_today"):
self.name = name
self.properties = self.compute_properties()
def compute_properties(self):
# <insert logic to compute properties>
return properties
I don't understand this type of design. Why not just set properties directly within compute_properties like:
class sim:
def __init__(self, name="sim_today"):
self.name = name
self.compute_properties()
def compute_properties(self):
self.properties = <insert logic to compute properties>
Separation of concerns suggests that a method should generally return a value or mutate the object but not both. The constructor is the obvious place to initialize the object’s attributes, and this design makes it clear that what is conditional is what value is assigned and not anything more general like selecting an attribute or not assigning anything.
Of course, when the value can be computed from other attributes, that makes the one assigned a cache; recall that cache invalidation is one of the two hard things in computer science (along with naming things and off-by-one errors), so this would be justified only if the value were expensive to compute.

Python: Are these default values being passed to the __init__ function necessary?

Here is a screenshot from a lecture that I am going through at school:
My question is, if the class data fields are already being defined:
slices=16
temperature=75.0
Do those values (16 and 75.0) also need to be passed to the __init__ method or can you just pass the variables names, because they are already assigned to those values?
Not sure why/if you would need to pass the default values when they are the exact same as what the variables are already set to? so instead of:
def __init__(self, slices=16, temperature=75.0)
Could you just do:
def __init__(self, slices, temperature)
Updated new question
If you removed the initial class-level variables at the top, and are only defining them in the constructor class, are they only scoped to the constructor class? Or are they available throughout the entire class, even though you didn't define them at the very top (class-level)?? Example:
Class Pizza(object):
# no class-level slice or temp variables
def __init__(self, slices=16, temperature=75.0):
self.slices = slices
self.temperature = temperature
Or, because you are defining them as "self.slices", they are by default passed to all of the other methods when you pass (self) into the other methods?
If you use:
def __init__(self, slices, temperature)
Then slices and temperature are parameters that must be specified.
What you can do is create a variable, and then use that as the default for the function parameter.
a = "foo"
def b(c=a):
print(c)
Just keep in mind that if you redefine that variable, it does not affect the default value for the function.
>>> a = "foo"
>>> def b(c=a):
... print(c)
...
>>> b()
foo
>>> a = 42
>>> b()
foo
The class defined in your lecture is dumb (not very dumb, just pointless and misleading, as you've clearly been misled by it). There is zero reason to define class attributes that happen to share the same value as the default arguments to the initializer. The only thing doing that accomplishes is:
You can do Pizza.slices and Pizza.temperature and see that the abstract concept of a pizza (not a specific pizza) somehow has a known number of slices and a known temperature, and
If someone using the class, for whatever reason, does del mypizza.slices, then future access to mypizza.slices will still "work", but will retrieve the value from the class attribute (since the instance attribute was blown away). Sane code should almost never do this.
In all other ways, there is no relationship between the class level attributes and the defaults defined for the __init__ initializer method; the moment __init__ assigns to self.slices and self.temperature, it shadows the class level attributes so they cannot be directly accessed from that instance of the class (without deleting the instance attributes or bypassing the instance to look at the values on the class itself).
So no, you can't do:
def __init__(self, slices, temperature):
self.slices = slices
self.temperatue = temperature
because the arguments named slices and temperature have nothing to do with the class attributes. By removing their defaults, the user of your class is forced to provide their own values, and there is no default that will be provided (they could, I suppose, do Pizza(Pizza.slices, Pizza.temperature), but that's an insane way to handle defaults).
To your updated question, even without the class variables,
class Pizza:
# no class-level slice or temp variables
def __init__(self, slices=16, temperature=75.0):
self.slices = slices
self.temperature = temperature
works just fine. Outside of any methods of the class, slices and temperature won't exist, but any other methods you define on Pizza will be able to access that instance's slice and temperature attributes by looking them up on self, just like __init__ did when it assigned to them (with self.slices or self.temperature), and anyone who creates an instance of Pizza, say, with mypizza = Pizza(12, 140), can do mypizza.slices to see the attribute for the instance they hold.
A note on the class attributes: In normal cases, they're stupid and nonsensical. There is an exception for dataclasses though, where you define them at class level for the express purpose of helping the dataclasses module dynamically generate your code, removing the need to write a __init__ with separate defaults entirely. For example:
from dataclasses import dataclass
#dataclass
class Pizza:
slices: int = 16
temperature: float = 75.0
is a perfectly reasonable way to write the baseline class, and it uses those annotations and defaulted assignments to generate as __init__ for you (along with reasonable default implementations of __repr__ and __eq__, and other special methods if you pass specific arguments to the #dataclass decorator, saving you a ton of boilerplate required for minimal expected class functionality). It does leave the class attributes in place, which is arguably a bad idea, but at least you're getting something useful out of the deal, it's not just repeating the same defaults in two essentially unrelated places, one of which is completely useless.

Is it a good practice to define unchanged public variables in Python?

Suppose that we had a class that at a certain point after creation will need to get assigned a value:
class ProcStatus:
def __init__(self, name):
self.name = name
self._status_code = None
def set_status_code(self, value):
self._status_code = value
def print_proc_status(self): # Some function that does something with the status code
print(f'{self.name} returned code {self._status_code}')
status = ProcStatus('ls')
# Some code in between
status.set_status_code(1)
status.print_proc_status()
Using this design, it's clear by the interface that the caller can (and is encouraged to) explicitly set the status code. However, the more pythonic approach would be using an attribute:
class ProcStatus:
def __init__(self, name):
self.name = name
self.status_code = None
def print_proc_status(self): # Some function that does something with the status code
print(f'{self.name} returned code {self.status_code}')
status = ProcStatus('ls')
# Some code in between
status.status_code = 1
status.print_proc_status()
Is the second one a better design, despite looking a little misleading since status_code is never updated within the class? Alternatively, would a property setter and getter assigning to a private field be the right approach?
The utility of having setters and getters for a variable is that they may enforce some constraints or maintain class invariants on user-set values to the field - in other words, they allow you to "sanitize" an otherwise potentially arbitrary value.
The most pythonic way to achieve the best of both worlds (your example #1 and #2) would be to use the #property decorator, which would look something like:
class ProcStatus:
def __init__(self, name):
self.name = name
self._status_code = None
#property
def status_code(self):
print("Getting")
return self._status_code
#property.setter
def status_code(self, value):
print("Setting")
# maybe apply constraints, check `value` for validity
self._status_code = value
Now you have the additional benefit of setters and getters and the beauty of status.status_code = 1 or print(status.status_code)
I think, in the end, this really depends on your situation. There are two scenarios:
#1 - Not using getters/setters (preferred)
In terms of using a getter/setter (Java style) vs an attribute, an attribute is always preferred as the more pythonic way of doing this. Whenever the user needs the status_code to have a value, they can just overwrite the attribute's value with a simple assignment operation:
status.status_code = 1
What is important is that the user understands how your class works and what fields are important for what. If status_code is needed for a function, you should either request it from the user as a parameter or let them know in the documentation that the function depends on a previously set status_code value.
#2 - When to use getters/setters
The only reason you would want a getter/setter type scenario is when you want to format the output created from accessing your attribute and to check the value's of what is assigned to it (_status_code in this case). So, basically, when you don't want your user to directly interact with the variable. This can be done the pythonic way and here I think Skrino's answer comes into play.
In terms of calling it a "private" variable, python does not really have any of those. This SO post goes into length about this. But in these cases, when you want to let your user be able to change a variable's value with some constraints, then using a getter/setter with a "private" variable is a good idea.

advantage and disadvantage of #property in a Python Object [duplicate]

This question already has answers here:
What's the pythonic way to use getters and setters?
(8 answers)
Closed 4 months ago.
What advantages does the #property notation hold over the classic getter+setter? In which specific cases/situations should a programmer choose to use one over the other?
With properties:
class MyClass(object):
#property
def my_attr(self):
return self._my_attr
#my_attr.setter
def my_attr(self, value):
self._my_attr = value
Without properties:
class MyClass(object):
def get_my_attr(self):
return self._my_attr
def set_my_attr(self, value):
self._my_attr = value
Prefer properties. It's what they're there for.
The reason is that all attributes are public in Python. Starting names with an underscore or two is just a warning that the given attribute is an implementation detail that may not stay the same in future versions of the code. It doesn't prevent you from actually getting or setting that attribute. Therefore, standard attribute access is the normal, Pythonic way of, well, accessing attributes.
The advantage of properties is that they are syntactically identical to attribute access, so you can change from one to another without any changes to client code. You could even have one version of a class that uses properties (say, for code-by-contract or debugging) and one that doesn't for production, without changing the code that uses it. At the same time, you don't have to write getters and setters for everything just in case you might need to better control access later.
In Python you don't use getters or setters or properties just for the fun of it. You first just use attributes and then later, only if needed, eventually migrate to a property without having to change the code using your classes.
There is indeed a lot of code with extension .py that uses getters and setters and inheritance and pointless classes everywhere where e.g. a simple tuple would do, but it's code from people writing in C++ or Java using Python.
That's not Python code.
Using properties lets you begin with normal attribute accesses and then back them up with getters and setters afterwards as necessary.
The short answer is: properties wins hands down. Always.
There is sometimes a need for getters and setters, but even then, I would "hide" them to the outside world. There are plenty of ways to do this in Python (getattr, setattr, __getattribute__, etc..., but a very concise and clean one is:
def set_email(self, value):
if '#' not in value:
raise Exception("This doesn't look like an email address.")
self._email = value
def get_email(self):
return self._email
email = property(get_email, set_email)
Here's a brief article that introduces the topic of getters and setters in Python.
[TL;DR? You can skip to the end for a code example.]
I actually prefer to use a different idiom, which is a little involved for using as a one off, but is nice if you have a more complex use case.
A bit of background first.
Properties are useful in that they allow us to handle both setting and getting values in a programmatic way but still allow attributes to be accessed as attributes. We can turn 'gets' into 'computations' (essentially) and we can turn 'sets' into 'events'. So let's say we have the following class, which I've coded with Java-like getters and setters.
class Example(object):
def __init__(self, x=None, y=None):
self.x = x
self.y = y
def getX(self):
return self.x or self.defaultX()
def getY(self):
return self.y or self.defaultY()
def setX(self, x):
self.x = x
def setY(self, y):
self.y = y
def defaultX(self):
return someDefaultComputationForX()
def defaultY(self):
return someDefaultComputationForY()
You may be wondering why I didn't call defaultX and defaultY in the object's __init__ method. The reason is that for our case I want to assume that the someDefaultComputation methods return values that vary over time, say a timestamp, and whenever x (or y) is not set (where, for the purpose of this example, "not set" means "set to None") I want the value of x's (or y's) default computation.
So this is lame for a number of reasons describe above. I'll rewrite it using properties:
class Example(object):
def __init__(self, x=None, y=None):
self._x = x
self._y = y
#property
def x(self):
return self.x or self.defaultX()
#x.setter
def x(self, value):
self._x = value
#property
def y(self):
return self.y or self.defaultY()
#y.setter
def y(self, value):
self._y = value
# default{XY} as before.
What have we gained? We've gained the ability to refer to these attributes as attributes even though, behind the scenes, we end up running methods.
Of course the real power of properties is that we generally want these methods to do something in addition to just getting and setting values (otherwise there is no point in using properties). I did this in my getter example. We are basically running a function body to pick up a default whenever the value isn't set. This is a very common pattern.
But what are we losing, and what can't we do?
The main annoyance, in my view, is that if you define a getter (as we do here) you also have to define a setter.[1] That's extra noise that clutters the code.
Another annoyance is that we still have to initialize the x and y values in __init__. (Well, of course we could add them using setattr() but that is more extra code.)
Third, unlike in the Java-like example, getters cannot accept other parameters. Now I can hear you saying already, well, if it's taking parameters it's not a getter! In an official sense, that is true. But in a practical sense there is no reason we shouldn't be able to parameterize an named attribute -- like x -- and set its value for some specific parameters.
It'd be nice if we could do something like:
e.x[a,b,c] = 10
e.x[d,e,f] = 20
for example. The closest we can get is to override the assignment to imply some special semantics:
e.x = [a,b,c,10]
e.x = [d,e,f,30]
and of course ensure that our setter knows how to extract the first three values as a key to a dictionary and set its value to a number or something.
But even if we did that we still couldn't support it with properties because there is no way to get the value because we can't pass parameters at all to the getter. So we've had to return everything, introducing an asymmetry.
The Java-style getter/setter does let us handle this, but we're back to needing getter/setters.
In my mind what we really want is something that capture the following requirements:
Users define just one method for a given attribute and can indicate there
whether the attribute is read-only or read-write. Properties fail this test
if the attribute writable.
There is no need for the user to define an extra variable underlying the function, so we don't need the __init__ or setattr in the code. The variable just exists by the fact we've created this new-style attribute.
Any default code for the attribute executes in the method body itself.
We can set the attribute as an attribute and reference it as an attribute.
We can parameterize the attribute.
In terms of code, we want a way to write:
def x(self, *args):
return defaultX()
and be able to then do:
print e.x -> The default at time T0
e.x = 1
print e.x -> 1
e.x = None
print e.x -> The default at time T1
and so forth.
We also want a way to do this for the special case of a parameterizable attribute, but still allow the default assign case to work. You'll see how I tackled this below.
Now to the point (yay! the point!). The solution I came up for for this is as follows.
We create a new object to replace the notion of a property. The object is intended to store the value of a variable set to it, but also maintains a handle on code that knows how to calculate a default. Its job is to store the set value or to run the method if that value is not set.
Let's call it an UberProperty.
class UberProperty(object):
def __init__(self, method):
self.method = method
self.value = None
self.isSet = False
def setValue(self, value):
self.value = value
self.isSet = True
def clearValue(self):
self.value = None
self.isSet = False
I assume method here is a class method, value is the value of the UberProperty, and I have added isSet because None may be a real value and this allows us a clean way to declare there really is "no value". Another way is a sentinel of some sort.
This basically gives us an object that can do what we want, but how do we actually put it on our class? Well, properties use decorators; why can't we? Let's see how it might look (from here on I'm going to stick to using just a single 'attribute', x).
class Example(object):
#uberProperty
def x(self):
return defaultX()
This doesn't actually work yet, of course. We have to implement uberProperty and
make sure it handles both gets and sets.
Let's start with gets.
My first attempt was to simply create a new UberProperty object and return it:
def uberProperty(f):
return UberProperty(f)
I quickly discovered, of course, that this doens't work: Python never binds the callable to the object and I need the object in order to call the function. Even creating the decorator in the class doesn't work, as although now we have the class, we still don't have an object to work with.
So we're going to need to be able to do more here. We do know that a method need only be represented the one time, so let's go ahead and keep our decorator, but modify UberProperty to only store the method reference:
class UberProperty(object):
def __init__(self, method):
self.method = method
It is also not callable, so at the moment nothing is working.
How do we complete the picture? Well, what do we end up with when we create the example class using our new decorator:
class Example(object):
#uberProperty
def x(self):
return defaultX()
print Example.x <__main__.UberProperty object at 0x10e1fb8d0>
print Example().x <__main__.UberProperty object at 0x10e1fb8d0>
in both cases we get back the UberProperty which of course is not a callable, so this isn't of much use.
What we need is some way to dynamically bind the UberProperty instance created by the decorator after the class has been created to an object of the class before that object has been returned to that user for use. Um, yeah, that's an __init__ call, dude.
Let's write up what we want our find result to be first. We're binding an UberProperty to an instance, so an obvious thing to return would be a BoundUberProperty. This is where we'll actually maintain state for the x attribute.
class BoundUberProperty(object):
def __init__(self, obj, uberProperty):
self.obj = obj
self.uberProperty = uberProperty
self.isSet = False
def setValue(self, value):
self.value = value
self.isSet = True
def getValue(self):
return self.value if self.isSet else self.uberProperty.method(self.obj)
def clearValue(self):
del self.value
self.isSet = False
Now we the representation; how do get these on to an object? There are a few approaches, but the easiest one to explain just uses the __init__ method to do that mapping. By the time __init__ is called our decorators have run, so just need to look through the object's __dict__ and update any attributes where the value of the attribute is of type UberProperty.
Now, uber-properties are cool and we'll probably want to use them a lot, so it makes sense to just create a base class that does this for all subclasses. I think you know what the base class is going to be called.
class UberObject(object):
def __init__(self):
for k in dir(self):
v = getattr(self, k)
if isinstance(v, UberProperty):
v = BoundUberProperty(self, v)
setattr(self, k, v)
We add this, change our example to inherit from UberObject, and ...
e = Example()
print e.x -> <__main__.BoundUberProperty object at 0x104604c90>
After modifying x to be:
#uberProperty
def x(self):
return *datetime.datetime.now()*
We can run a simple test:
print e.x.getValue()
print e.x.getValue()
e.x.setValue(datetime.date(2013, 5, 31))
print e.x.getValue()
e.x.clearValue()
print e.x.getValue()
And we get the output we wanted:
2013-05-31 00:05:13.985813
2013-05-31 00:05:13.986290
2013-05-31
2013-05-31 00:05:13.986310
(Gee, I'm working late.)
Note that I have used getValue, setValue, and clearValue here. This is because I haven't yet linked in the means to have these automatically returned.
But I think this is a good place to stop for now, because I'm getting tired. You can also see that the core functionality we wanted is in place; the rest is window dressing. Important usability window dressing, but that can wait until I have a change to update the post.
I'll finish up the example in the next posting by addressing these things:
We need to make sure UberObject's __init__ is always called by subclasses.
So we either force it be called somewhere or we prevent it from being implemented.
We'll see how to do this with a metaclass.
We need to make sure we handle the common case where someone 'aliases'
a function to something else, such as:
class Example(object):
#uberProperty
def x(self):
...
y = x
We need e.x to return e.x.getValue() by default.
What we'll actually see is this is one area where the model fails.
It turns out we'll always need to use a function call to get the value.
But we can make it look like a regular function call and avoid having to use e.x.getValue(). (Doing this one is obvious, if you haven't already fixed it out.)
We need to support setting e.x directly, as in e.x = <newvalue>. We can do this in the parent class too, but we'll need to update our __init__ code to handle it.
Finally, we'll add parameterized attributes. It should be pretty obvious how we'll do this, too.
Here's the code as it exists up to now:
import datetime
class UberObject(object):
def uberSetter(self, value):
print 'setting'
def uberGetter(self):
return self
def __init__(self):
for k in dir(self):
v = getattr(self, k)
if isinstance(v, UberProperty):
v = BoundUberProperty(self, v)
setattr(self, k, v)
class UberProperty(object):
def __init__(self, method):
self.method = method
class BoundUberProperty(object):
def __init__(self, obj, uberProperty):
self.obj = obj
self.uberProperty = uberProperty
self.isSet = False
def setValue(self, value):
self.value = value
self.isSet = True
def getValue(self):
return self.value if self.isSet else self.uberProperty.method(self.obj)
def clearValue(self):
del self.value
self.isSet = False
def uberProperty(f):
return UberProperty(f)
class Example(UberObject):
#uberProperty
def x(self):
return datetime.datetime.now()
[1] I may be behind on whether this is still the case.
I think both have their place. One issue with using #property is that it is hard to extend the behaviour of getters or setters in subclasses using standard class mechanisms. The problem is that the actual getter/setter functions are hidden in the property.
You can actually get hold of the functions, e.g. with
class C(object):
_p = 1
#property
def p(self):
return self._p
#p.setter
def p(self, val):
self._p = val
you can access the getter and setter functions as C.p.fget and C.p.fset, but you can't easily use the normal method inheritance (e.g. super) facilities to extend them. After some digging into the intricacies of super, you can indeed use super in this way:
# Using super():
class D(C):
# Cannot use super(D,D) here to define the property
# since D is not yet defined in this scope.
#property
def p(self):
return super(D,D).p.fget(self)
#p.setter
def p(self, val):
print 'Implement extra functionality here for D'
super(D,D).p.fset(self, val)
# Using a direct reference to C
class E(C):
p = C.p
#p.setter
def p(self, val):
print 'Implement extra functionality here for E'
C.p.fset(self, val)
Using super() is, however, quite clunky, since the property has to be redefined, and you have to use the slightly counter-intuitive super(cls,cls) mechanism to get an unbound copy of p.
Using properties is to me more intuitive and fits better into most code.
Comparing
o.x = 5
ox = o.x
vs.
o.setX(5)
ox = o.getX()
is to me quite obvious which is easier to read. Also properties allows for private variables much easier.
I feel like properties are about letting you get the overhead of writing getters and setters only when you actually need them.
Java Programming culture strongly advise to never give access to properties, and instead, go through getters and setters, and only those which are actually needed.
It's a bit verbose to always write these obvious pieces of code, and notice that 70% of the time they are never replaced by some non-trivial logic.
In Python, people actually care for that kind of overhead, so that you can embrace the following practice :
Do not use getters and setters at first, when if they not needed
Use #property to implement them without changing the syntax of the rest of your code.
I would prefer to use neither in most cases. The problem with properties is that they make the class less transparent. Especially, this is an issue if you were to raise an exception from a setter. For example, if you have an Account.email property:
class Account(object):
#property
def email(self):
return self._email
#email.setter
def email(self, value):
if '#' not in value:
raise ValueError('Invalid email address.')
self._email = value
then the user of the class does not expect that assigning a value to the property could cause an exception:
a = Account()
a.email = 'badaddress'
--> ValueError: Invalid email address.
As a result, the exception may go unhandled, and either propagate too high in the call chain to be handled properly, or result in a very unhelpful traceback being presented to the program user (which is sadly too common in the world of python and java).
I would also avoid using getters and setters:
because defining them for all properties in advance is very time consuming,
makes the amount of code unnecessarily longer, which makes understanding and maintaining the code more difficult,
if you were define them for properties only as needed, the interface of the class would change, hurting all users of the class
Instead of properties and getters/setters I prefer doing the complex logic in well defined places such as in a validation method:
class Account(object):
...
def validate(self):
if '#' not in self.email:
raise ValueError('Invalid email address.')
or a similiar Account.save method.
Note that I am not trying to say that there are no cases when properties are useful, only that you may be better off if you can make your classes simple and transparent enough that you don't need them.
I am surprised that nobody has mentioned that properties are bound methods of a descriptor class, Adam Donohue and NeilenMarais get at exactly this idea in their posts -- that getters and setters are functions and can be used to:
validate
alter data
duck type (coerce type to another type)
This presents a smart way to hide implementation details and code cruft like regular expression, type casts, try .. except blocks, assertions or computed values.
In general doing CRUD on an object may often be fairly mundane but consider the example of data that will be persisted to a relational database. ORM's can hide implementation details of particular SQL vernaculars in the methods bound to fget, fset, fdel defined in a property class that will manage the awful if .. elif .. else ladders that are so ugly in OO code -- exposing the simple and elegant self.variable = something and obviate the details for the developer using the ORM.
If one thinks of properties only as some dreary vestige of a Bondage and Discipline language (i.e. Java) they are missing the point of descriptors.
In complex projects I prefer using read-only properties (or getters) with explicit setter function:
class MyClass(object):
...
#property
def my_attr(self):
...
def set_my_attr(self, value):
...
In long living projects debugging and refactoring takes more time than writing the code itself. There are several downsides for using #property.setter that makes debugging even harder:
1) python allows creating new attributes for an existing object. This makes a following misprint very hard to track:
my_object.my_atttr = 4.
If your object is a complicated algorithm then you will spend quite some time trying to find out why it doesn't converge (notice an extra 't' in the line above)
2) setter sometimes might evolve to a complicated and slow method (e.g. hitting a database). It would be quite hard for another developer to figure out why the following function is very slow. He might spend a lot of time on profiling do_something() method, while my_object.my_attr = 4. is actually the cause of slowdown:
def slow_function(my_object):
my_object.my_attr = 4.
my_object.do_something()
Both #property and traditional getters and setters have their advantages. It depends on your use case.
Advantages of #property
You don't have to change the interface while changing the implementation of data access. When your project is small, you probably want to use direct attribute access to access a class member. For example, let's say you have an object foo of type Foo, which has a member num. Then you can simply get this member with num = foo.num. As your project grows, you may feel like there needs to be some checks or debugs on the simple attribute access. Then you can do that with a #property within the class. The data access interface remains the same so that there is no need to modify client code.
Cited from PEP-8:
For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.
Using #property for data access in Python is regarded as Pythonic:
It can strengthen your self-identification as a Python (not Java) programmer.
It can help your job interview if your interviewer thinks Java-style getters and setters are anti-patterns.
Advantages of traditional getters and setters
Traditional getters and setters allow for more complicated data access than simple attribute access. For example, when you are setting a class member, sometimes you need a flag indicating where you would like to force this operation even if something doesn't look perfect. While it is not obvious how to augment a direct member access like foo.num = num, You can easily augment your traditional setter with an additional force parameter:
def Foo:
def set_num(self, num, force=False):
...
Traditional getters and setters make it explicit that a class member access is through a method. This means:
What you get as the result may not be the same as what is exactly stored within that class.
Even if the access looks like a simple attribute access, the performance can vary greatly from that.
Unless your class users expect a #property hiding behind every attribute access statement, making such things explicit can help minimize your class users surprises.
As mentioned by #NeilenMarais and in this post, extending traditional getters and setters in subclasses is easier than extending properties.
Traditional getters and setters have been widely used for a long time in different languages. If you have people from different backgrounds in your team, they look more familiar than #property. Also, as your project grows, if you may need to migrate from Python to another language that doesn't have #property, using traditional getters and setters would make the migration smoother.
Caveats
Neither #property nor traditional getters and setters makes the class member private, even if you use double underscore before its name:
class Foo:
def __init__(self):
self.__num = 0
#property
def num(self):
return self.__num
#num.setter
def num(self, num):
self.__num = num
def get_num(self):
return self.__num
def set_num(self, num):
self.__num = num
foo = Foo()
print(foo.num) # output: 0
print(foo.get_num()) # output: 0
print(foo._Foo__num) # output: 0
Here is an excerpts from "Effective Python: 90 Specific Ways to Write Better Python" (Amazing book. I highly recommend it).
Things to Remember
✦ Define new class interfaces using simple public attributes and avoid
defining setter and getter methods.
✦ Use #property to define special behavior when attributes are
accessed on your objects, if necessary.
✦ Follow the rule of least surprise and avoid odd side effects in your
#property methods.
✦ Ensure that #property methods are fast; for slow or complex
work—especially involving I/O or causing side effects—use normal
methods instead.
One advanced but common use of #property is transitioning what was
once a simple numerical attribute into an on-the-fly calculation. This
is extremely helpful because it lets you migrate all existing usage of
a class to have new behaviors without requiring any of the call sites
to be rewritten (which is especially important if there’s calling code
that you don’t control). #property also provides an important stopgap
for improving interfaces over time.
I especially like #property because it lets you make incremental
progress toward a better data model over time.
#property is a tool to
help you address problems you’ll come across in real-world code. Don’t
overuse it. When you find yourself repeatedly extending #property
methods, it’s probably time to refactor your class instead of further
paving over your code’s poor design.
✦ Use #property to give existing instance attributes
new functionality.
✦ Make incremental progress toward better data
models by using #property.
✦ Consider refactoring a class and all call
sites when you find yourself using #property too heavily.

Classes in python, how to set an attributes

When I write class in python, most of the time, I am eager to set variables I use, as properties of the object. Is there any rule or general guidelines about which variables should be used as class/instance attribute and which should not?
for example:
class simple(object):
def __init(self):
a=2
b=3
return a*b
class simple(object):
def __init(self):
self.a=2
self.b=3
return a*b
While I completely understand the attributes should be a property of the object. This is simple to understand when the class declaration is simple but as the program goes longer and longer and there are many places where the data exchange between various modules should be done, I get confused on where I should use a/b or self.a/self.b. Is there any guidelines for this?
Where you use self.a you are creating a property, so this can be accessed from outside the class and persists beyond that function. These should be used for storing data about the object.
Where you use a it is a local variable, and only lasts while in the scope of that function, so should be used where you are only using it within the function (as in this case).
Note that __init is misleading, as it looks like __init__ - but isn't the constructor. If you intended them to be the constructor, then it makes no sense to return a value (as the new object is what is returned).
class Person(object):
def __init__(self, name):
# Introduce all instance variables on __init__
self.name = name
self.another = None
def get_name(self):
# get_name has access to the `instance` variable 'name'
return self.name
So if you want a variable to be available on more than one method, make
it an instance variable.
Notice my comment on introducing all instance vars on __init__.
Although the example below is valid python don't do it.
class Person(object):
def __init__(self):
self.a = 0
def foo(self):
self.b = 1 # Whoa, introduced new instance variable
Instead initialize all your instance variables on __init__ and set
them to None if no other value is appropriate for them.
I try to imagine what I want the API of my class to look like prior to implementing it. I think to myself, If I didn't write this class, would I want to read the documentation about what this particular variable does? If reading that documentation would simply waste my time, then it should probably be a local variable.
Occasionally, you need to preserve some information, but you wouldn't necessarily want that to be part of the API, which is when you use the convention of appending an underscore. e.g. self._some_data_that_is_not_part_of_the_api.
The self parameter refers to the object itself. So if you need to use on of the class attributes outside of the class you would it call it as the name of class instance and the attribute name. I don't think there is any guideline on when to use self, it all depends on your need. When you are building a class you should try to think about what you will use the variables you creating for. If you know for sure that you will need that specific attribute in the program you are importing your class, then add self.

Categories