At 09:58 PM 5/18/03 -0400, Aahz wrote: >[Normally I send my corrections to Brett privately, but since I'm taking >a whack at attribute lookup, I figured this ought to be public.] > >On Sun, May 18, 2003, Brett C. wrote: > > > > The only thing I would like help with this summary is if someone knows > > the attribute lookup order (instance, class, class descriptor, ...) off > > the top of their heads, can you let me know? If not I can find it out > > by going through the docs but I figure someone out there has to know it > > by heart and any possible quirks (like whether descriptors take > > precedence over non-descriptor attributes). > >This gets real tricky. For simple attributes of an instance, the order >is instance, class/type, and base classes of the class/type (but *not* >the metaclass). However, method resolution of the special methods goes >straight to the class. Finally, if an attribute is found on the >instance, a search goes through the hierarchy to see whether a set >descriptor overrides (note specifically that it's a set descriptor; >methods are implemented using get descriptors). > >I *think* I have this right, but I'm sure someone will correct me if I'm >wrong. Here's the algorithm in a bit more detail: 1. First, the class/type and its bases are searched, checking dictionaries only. 2. If the object found is a "data descriptor" (i.e. has a type with a non-null tp_descr_set pointer, which is closely akin to whether the descriptor has a '__set-_' attribute), then the data descriptor's __get__ method is invoked. 3. If the object is not found, or not a data descriptor, the instance dictionary is checked. If the attribute isn't in the instance dictionary, then the descriptor's __get__ method is invoked (assuming a descriptor was found). 4. Invoke __getattr__ if present. (Note that replacing __getattribute__ *replaces* this entire algorithm.) Also note that special methods are *not* handled specially here. The behavior Aahz is referring to is that slots (e.g. tp_call) on new-style types do not retrieve an instance attribute; they are based purely on class-level data. So, although you *can* override the values in an instance, they have no effect on the class behavior. E.g.: >>> class Foo(object): def __call__(self,*args): print "foo",args >>> f=Foo() >>> f.__call__ = 'spam' >>> f.__call__ 'spam' >>> f() foo () >>> Notice that the behavior of the instance '__call__' attribute does not affect the class-level definition of '__call__'. To recast the algorithm as a precedence order: 1. Data descriptors (ones with tp_descr_set/__set__) found in the type __mro__ (note that this includes __slots__, property(), and custom descriptors) 2. Instance attributes found in ob.__dict__ 3. Non-data descriptors, such as methods, or any other object found in the type __mro__ under that name 4. __getattr__
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4