I’ve been successfully using Python properties, but I don’t see how they could work. If I dereference a property outside of a class, I just get an object of type
@property def hello(): return "Hello, world!" hello # <property object at 0x9870a8>
But if I put a property in a class, the behavior is very different:
class Foo(object): @property def hello(self): return "Hello, world!" Foo().hello # 'Hello, world!'
I’ve noticed that unbound
Foo.hello is still the
property object, so class instantiation must be doing the magic, but what magic is that?
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.
On the other hand, if it is accessed through the class, then
instance is None and only
owner is passed. The
property object recognizes this and returns
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
Properties are descriptors, and descriptors behave specially when member of a class instance. In short, if
a is an instance of type
A.foo is a descriptor, then
a.foo is equivalent to
property object just implements the descriptor protocol: http://docs.python.org/howto/descriptor.html