I've read several tutorials, articles and questions here on stackoverflow, including the python doc, but all of them are using a single instance variable in their examples, making it difficult to see how python properties would work if you have more than one.
At first i thought the property function was created to be able to set or get any property so you could only create one get and one set method and then any number of instance variables which would use these, but this doesnt seem to be the case(?)
If I have the following code (taken straight from the official doc on property()):
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
You have one method "getx" and one method "setx" in addition to the deleter method "delx". What if i also need a couple of more instances variables like y and z, do i then need to write the following code:
class C(object):
def __init__(self, x, y, z):
self._x = None
self._y = 2
self._z = 4
def getx(self):
return self._x
def gety(self):
return self._y
def getz(self):
return self._z
def setx(self, value):
self._x = value
def sety(self, value):
self._y = value
def setz(self, value):
self._z = value
def delx(self):
del self._x
def dely(self):
del self._y
def delz(self):
del self._z
x = property(getx, setx, delx, "I'm the 'x' property.")
y = property(gety, sety, dely, "I'm the 'y' property.")
z = property(getz, setz, delz, "I'm the 'z' property.")
The above code looks a lot like java setters/getters, and the reason for using property in python seems to be exactly to avoid this, so are you meant to be using some sort og general getter/setter instead ?
Please dont bash me with tons of -1, im just trying to understand this and i have read quite a bit to try to avoid posting this people often get annoyed it seems when people arent a master in python.
The getters and setters in your example are useless, just skip them. All you need is:
class C(object):
def __init__(self, x, y, z):
self.x = None
self.y = 2
self.z = 4
Getters and setters are only needed if you want to do something unusual. Merely getting an attribute and setting an attribute can be done simply with an attribute.
Related
I was comparing three slightly different implementations of #property in python. Python documentation and "Source 1" initialize the private variable, _var_name. Furthermore, the code from Source 1 has a bug; it doesn't access .setter when initializing. By contrast, the third example correctly initializes the public variable x.
Is there a good reason to initialize _x in place of x in __init__? Are there any additional differences between these that I haven't described?
From the docs:
class C:
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
return self._x
#x.setter
def x(self, value):
self._x = value
#x.deleter
def x(self):
del self._x
Source 1:
class Celsius:
def __init__(self, temperature = 0):
self._temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
#property
def temperature(self):
print("Getting value")
return self._temperature
#temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self._temperature = value
Source 2:
class P:
def __init__(self,x):
self.x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
Is there a good reason to initialize __x or _x in place of x in __init__?
Properties are often used to transform the input in some way. An internal method (including __init__) often already has the transformed data, and doesn't want it to get transformed again. For example, consider this somewhat silly but obvious example:
class C:
# ...
def __init__(self):
f = open(C.default_filename, 'rb')
# ...
self._file = f
#property
def file(self):
return self._file.__name__
#file.setter
def file(self, filename):
self._file = open(f, 'rb')
Even when you're not doing anything that would be wrong to pass through the setter, internal code often knows about the class invariants, so the checks done by setters may be extra overhead for no benefit. For example, if you wanted a method to set the temperature to 0°C, it could just set self._x = 0 instead of self.x = 0, because you know that 0 doesn't need to be checked.
On the other hand, some internal methods may want to see x the same way the public does. In that case, it should use the property rather than the underlying attribute. In fact, your Source 1 is a perfect example—__init__ just saves its parameter directly to _temperature, allowing you to construct temperatures below absolute 0 (which is bad, because that's actually hotter than infinity, and CPUs like to be cold). And it would be silly to repeat the same precondition test in __init__ that you already wrote in temperature.setter; in this case, just set self.temperature instead.
There is additional difference in whether a single or double underscore is used.
A single underscore makes the attribute "private by convention"; a double underscore goes further and mangles the name, which means it can't be accidentally accessed from outside your class's code.
Using obj._x works on your instances; obj.__x raises AttributeError. But it only prevents accidental access—they can still use obj._C__x if they really want to get at it. The main reason to do this is to protect subclasses or superclasses from accidentally using the same names.
Property wrapper methods is a nice feature to have in python, this question is not the subject of such question, I need to know if it is possible to use it with python destructor __del__, a practical example could be a database connection, for simplification purposes let's say we have the following class:
class Point(object):
"""docstring for Point"""
def __init__(self, x, y):
self.x = x
self.y = y
#property
def x(self):
print('x getter got called')
return self._x
#x.setter
def x(self, x):
print('x setter got called')
self._x = x
def __str__(self):
return '[%s:%s]' % (self.x, self.y)
def __del__(self):
print('destructor got called')
del self.x
del self.y
as a test case let's say we have:
a = Point(4, 5)
del a
The output is:
Exception AttributeError: "can't delete attribute" in <bound method Point.__del__ of <__main__.Point object at 0x7f8bcc7e5e10>> ignored
if we deleted the property part, everything goes smooth.
can someone show where's the problem?
Add a deleter to your property x that does the clean up. By default, if no fdel is defined for the property, the AttributeError you see is raised:
#x.deleter
def x(self):
print("x deleter got called")
del self._x
If you don't use #x.deleter to define the delete behavior (like you did with #x.setter) then it's impossible to delete the property.
I used to initialize private attributes in __init__ like below (this way of initializing is also commonly seen),
class Duck():
def __init__(self, input_name):
self.__name = input_name
#property
def name(self):
return self.__name
#name.setter
def name(self, input_name):
self.__name = input_name
# Use private attribute __name internally for other purposes below...
But I just want to make sure if it is actually safer to just use property at the very beginning __init__, for example, in next example, for input greater than 1000 or less than 0, I want to evaluate to 1000 and 0, respectively, rather than the original input value. It seems I can't use self.__x = x,
class P:
def __init__(self,x):
# If self.__x = x, not desirable
self.x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
I assume you work with python2. Properties are not supported for old-style classes. Just change the first line to
class P(object):
And whether you use self._x or self.__x for the attribute behind does not matter. Just do it consistent, i.e. change the constructor line back to
self.__x = x
Just don't call that self.x as the property.
Edit:
There was a misunderstanding I think. Here the complete code I propose:
class P(object):
def __init__(self,x):
self.__x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
p = P(3)
p.x = 1001
print p.x
Edit 2 - The actual question:
I apologize, did simply not grasp the heading and actual question here, but was focused on making your class work. My distraction was that if you are in python2 and use old-style classes, the setter would not really get called.
Then like indicated in the comment-conversation below, I don't have a definite answer on whether to initialize the attribute or the property, but I (personally) would say:
a. If the initialisation deserves the same validation as performed in
the setter, then use the property, as else you'd need to copy the
setter code.
b. If however the value to initialise doesn't need validation (for
instance, you set it to an a priori validated constant default
value), then there is no reason to use the property.
I want to be able to create a concrete instance of a class that inherits from another concrete class, which in turn inherits from an abstract class.
The basic pattern is:
from abc import ABCMeta, abstractproperty
class Foo(object):
__metaclass__ = ABCMeta
#abstractproperty
def x(self):
pass
#abstractproperty
def y(self):
pass
class Bar(Foo):
x = None
y = None
def __init__(self, x, y):
self.x = x
self.y = y
#property
def x(self):
return self.x
#x.setter
def x(self, value):
self.x = value
#property
def y(self):
return self.y
#y.setter
def y(self, value):
self.y = value
class Baz(Bar):
def __init__(self):
super().__init__(x=2, y=6)
a = Baz()
When I try to create the instance of Baz I get a RecursionError: maximum recursion depth exceeded error. (As well as a pylint warning telling me that the signatures of the setter methods don't match the signatures of the base class)
However, if I remove the setters, I get an error self.x = x AttributeError: can't set attribute
What's the correct pattern to do this?
You need to change names for your x() / y() methods or for your x / y properties, for example rename
class Bar(Foo):
x = None
y = None
To:
class Bar(Foo):
x_val = None
y_val = None
And rename the references to x / y as well.
What you did is basically:
def x():
return x()
It happened because your def x overridden the x = None, so x is a function(property) that is calling itself. Avoid this by using another attribute(named differently) for storing the actual value of x.
Example from python docs (https://docs.python.org/3.5/library/functions.html#property):
class C:
def __init__(self):
self._x = None
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
Note: attribute names starting with underscore should be considered "private" and should not be directly accessed outside of the class. But it's only a convention for programmers, technically they are just normal attributes and you can do whatever you want, but it's nice to follow some convention, isn't it?
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the benefit to using a ‘get function’ for a python class?
I just started to read Python, but I wonder why does Python need setter and getter at all? it already have object variables which act like property
Consider
class C(object):
def _init_(self):
self._x = None
def get_x(self):
return self._x
def set_x(self, value):
self._x = valu
x = property(get_x, set_x)
Can we just use C.x = "value" to do what we want to do here? what is the benefit of property?
BTW, creating property/setter/getter in this way is cumbersome to me, is there any way to simplify this? like
class C()
has_attributes("x", "y", "z")
You can use a property to obtain what you want:
class C(object):
def _init_(self):
self._x = None
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
Then you can access the attribute with the usual attribute syntax:
c = C()
c.x = 10 #calls the setter
print(c.x) #calls the getter
There are some reasons to use a property instead of a plain data attribute:
You can document the attribute
You can control the access to the attribute, either by making it read-only or by checking the type/value being set
You do not break backwards compatibility: if something was a plain instance attribute and then you decide to transform it into a property the code that worked with the attribute will still work. If you used get/set explicit methods all the code that used the old API would have to change
It's more readable then using explicit get/set methods.
Use plain attributes:
class C(object):
def __init__(self):
self.x = None
Later, when and if it would be necessary, x can be changed to a property. The beauty of "#property" it that is allows developer not to use getters, setters and "#property".
class C(object):
def _init_(self):
self._x = None
def get_x(self):
return self._x
def set_x(self, value):
self._x = value
x = property(get_x, set_x)
now you can use c.x = "foo" with the set and gets, transparently.
The purpose of a set and getter is don't expose the class internals.
Imagine that in the future
self._x
changes to
sql.save(id(self), value)
and get_x to:
value= sql.sql(id(self))
return convertFromDbFormatToExpectedApiFormat(value)
You will only have to change the code of getter and setters in only that class, not change
all the classes that communicates with it.
class C(object):
def _init_(self):
self.sql = DDBB()
def get_x(self):
dbregistry = self.sql.fetch(id(self))
return convertFromDbFormatToExpectedApiFormat(dbregistry)
def set_x(self, value):
self.sql.save(id(self), value)
x = property(get_x, set_x)