How do Python properties work?
Solution 1:
As others have noted, they use a language feature called descriptors.
The reason that the actual property object is returned when you access it via a class Foo.hello
lies in how the property implements the __get__(self, instance, owner)
special method:
- If a descriptor is accessed on an instance, then that instance is passed as the appropriate argument, and
owner
is the class of that instance. - When it is accessed through the class, then
instance
is None and onlyowner
is passed. Theproperty
object recognizes this and returnsself
.
Besides the Descriptors howto, see also the documentation on Implementing Descriptors and Invoking Descriptors in the Language Guide.
Solution 2:
In order for @properties to work properly the class needs to be a subclass of object. when the class is not a subclass of object then the first time you try access the setter it actually makes a new attribute with the shorter name instead of accessing through the setter.
The following does not work correctly.
class C(): # <-- Notice that object is missing
def __init__(self):
self._x = None
@property
def x(self):
print 'getting value of x'
return self._x
@x.setter
def x(self, x):
print 'setting value of x'
self._x = x
>>> c = C()
>>> c.x = 1
>>> print c.x, c._x
1 0
The following will work correctly
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
print 'getting value of x'
return self._x
@x.setter
def x(self, x):
print 'setting value of x'
self._x = x
>>> c = C()
>>> c.x = 1
setting value of x
>>> print c.x, c._x
getting value of x
1 1
Solution 3:
Properties are descriptors, and descriptors behave specially when member of a class instance. In short, if a
is an instance of type A
, and A.foo
is a descriptor, then a.foo
is equivalent to A.foo.__get__(a)
.