On Tue, 30 Sep 2003 20:15:10 +0400 (MSD), "Denis S. Otkidach" <od*@strana.ru> wrote:
I've noticed that the order of attribute lookup is inconsistent
when descriptor is used. property instance takes precedence of
instance attributes:
class A(object):... def _get_attr(self):
... return self._attr
... attr = property(_get_attr)
... a=A()
a.__dict__{} a.__dict__['attr']=1
a.__dict__{'attr': 1} a.attrTraceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in _get_attr
AttributeError: 'A' object has no attribute '_attr'
But it doesn't when I use custom class of descriptor:
class descr(object):... def __get__(self, inst, cls):
... return inst._attr
... class B(object):... attr = descr()
... b=B()
b.__dict__{} b.__dict__['attr']=1
b.__dict__{'attr': 1} b.attr1
Subclasses of property behave like property itself:
class descr2(property):... def __get__(self, inst, cls):
... return inst._attr
... class C(object):... attr = descr2()
... c=C()
c.__dict__{} c.__dict__['attr']=1
c.__dict__{'attr': 1} c.attr
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in __get__
AttributeError: 'C' object has no attribute '_attr'
Is it an undocumented feature or I have to submit a bug report?
I think (not having read the above carefully) that it's all documented in
http://users.rcn.com/python/download/Descriptor.htm
(thanks to Raymond Hettinger).
excerpt:
"""
The details of invocation depend on whether obj is an object or a class.
Either way, descriptors only work for new style objects and classes. A
class is new style if it is a subclass of object.
For objects, the machinery is in object.__getattribute__ which
transforms b.x into type(b).__dict__['x'].__get__(b, type(b)). The
implementation works through a precedence chain that gives data
descriptors priority over instance variables, instance variables
priority over non-data descriptors, and assigns lowest priority to
__getattr__ if provided. The full C implementation can be found in
PyObject_GenericGetAttr() in Objects/object.c.
For classes, the machinery is in type.__getattribute__ which transforms
B.x into B.__dict__['x'].__get__(None, B). In pure Python, it looks
like:
def __getattribute__(self, key):
"Emulate type_getattro() in Objects/typeobject.c"
v = object.__getattribute__(self, key)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
The important points to remember are:
descriptors are invoked by the __getattribute__ method
overriding __getattribute__ prevents automatic descriptor calls
__getattribute__ is only available with new style classes and objects
object.__getattribute__ and type.__getattribute__ make different calls to __get__.
data descriptors always override instance dictionaries.
non-data descriptors may be overridden by instance dictionaries.
"""
Regards,
Bengt Richter