Inconsistent behavior of descriptors
Bengt Richter
bokr at oz.net
Wed Oct 1 08:26:54 EDT 2003
More information about the Python-list mailing list
Wed Oct 1 08:26:54 EDT 2003
- Previous message (by thread): Inconsistent behavior of descriptors
- Next message (by thread): Inconsistent behavior of descriptors
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Tue, 30 Sep 2003 20:15:10 +0400 (MSD), "Denis S. Otkidach" <ods at 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.attr >Traceback (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.attr >1 > >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
- Previous message (by thread): Inconsistent behavior of descriptors
- Next message (by thread): Inconsistent behavior of descriptors
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Python-list mailing list