Your descriptor returns None
because it is also invoked for classes (the instance
attribute is set to None
when __get__
is called for that scenario).
You need to retrieve it without invoking the descriptor protocol, reaching into the class __dict__
attribute is the most direct path:
A.__dict__['p']
See the Python Descriptor HOWTO for more details on how and when descriptors are invoked.
Alternatively, do as the property
object does and return self
when instance
is set to None
(so when accessed on a class):
class Property(object):
_value = None
def __get__(self, instance, owner):
if instance is None:
return self
return self._value
def __set__(self, instance, value):
self._value = value * 2
Also see How does the @property decorator work?
Demo:
>>> class Property(object):
... def __get__(self, instance, owner):
... return self._value
... def __set__(self, instance, value):
... self._value = value * 2
...
>>> class A(object):
... b = Property()
...
>>> A.__dict__['b']
<__main__.Property object at 0x103097910>
>>> type(A.__dict__['b'])
<class '__main__.Property'>
>>> class Property(object):
... _value = None
... def __get__(self, instance, owner):
... if instance is None:
... return self
... return self._value
... def __set__(self, instance, value):
... self._value = value * 2
...
>>> class A(object):
... b = Property()
...
>>> A.b
<__main__.Property object at 0x10413d810>