Properties are just one application of Python ubiquitous proxying. The properties are created as wrappers over get/set methods:
class C(object):
def __init__(self, value):
self._value = value
def _get_value(self):
return self._value
value = property(_get_value)
# all is fine, value calls C._get_value:
assert C(10).value == 10
Here is what's happening: an instance of a property class is created and a reference to C._get_value is stored in it. Next time c.value is referenced, the property calls the original method.
The problem is, the reference is bound to the particular class C, and so if you inherit from it, you should not expect the property to be rebound to the ancestor class'es method:
class D(C):
def _get_value(self):
return self._value + 1
# now, this still calls C._get_value:
assert D(10).value != 11
The properties are thus non-polymorphic. There is one way to make them such by introducing late binding,
class C(object):
...
value = property(lambda self: self._get_value())
but I personally find it cumbersome.