More than you ever wanted to know about objects [was: Is everything a refrence or isn't it]

Bengt Richter bokr at oz.net
Fri Jan 13 01:38:12 EST 2006


On Fri, 13 Jan 2006 03:12:00 +0000, Steve Holden <steve at holdenweb.com> wrote:
[...]
>Note to nitpickers
>------------------
>Please note that I *am* oversimplifying here, and the nitpickers will 
>undoubtedly find many threadsworth of valuable material here. The point 
>is to develop an understanding of the *principles*. Once someone has 
>that they can pick up the details as they need them, which 98% of Python 
>users don't feel the need to. I don't even claim to know the whole 
>story, but I *do* know enough to explain it in principle. So by all 
>means correct me where I am demonstrably wring, but *please* don't just 
                                          ^^^^^-- spelling is "wring" ;-)
>add complexity that doesn't aid understanding.
[...]
>When you write
>
>   foo = instance.method(arg1, arg2)
>
>you are almost always calling a function defined inside the instance 
>type's class definition (though this being Python there's absolutely 
>nothing to stop instances having callable attributes of their own too: 
>we are discussing "beginners' Python" here).
>
>Under the hood the interpreter looks for an attribute called "method" in 
>the instance. Failing to find it, it then looks in the instance's type.
UIAM,  for new-style classes this is wrongly putting the instance attribute
lookup before the mro logic. For new-style, the interpreter goes down the
type(instance).mro() chain looking for the attribute called "method"
until it finds a "method" attribute whose value has __get__ method AND a __set__ method
(which makes it a data descriptor, and not overridable by an instance attribute). If
found, it will call the method.__get__ method with the instance as an argument. The __get__ method
then returns (normally) the bound method. If it finds "method" without __get__ and __set__ methods,
it will ignore it, except that it may revisit it if after the whole mro chain fails, and there isn't
any "method" attribute on the instance either. In that case, it will look for "method" again along the
mro, and if it has a __get__ method, it will form a bound method (this is the typical "method" attribute
in the form of a function, which has a __get__ method), or if there is no __get__ method, it will
return the value as ordinary class variable. The re-scan of mro is not literal, hopefully. I'm just
trying to express the logic. Also special shortcuts apply for methods of builtins, I believe.

Old-style classes live alongside new ones -- I suspect -- by virtue of type(someinstance) being
<type 'instance'> and type(someinstance).__getattribute__ thus implementing old-style stuff instead
of the type(someinstance).__getattribute__ of new-style instances, which inherit their __getattribute__
either from object.__getattribute__ or type.__getattribute__, or a user definition.

>
>Of course it can fail to find it there, too. If the type is defined as a 
>specialisation of some other type (a "subclass" of the other type - 
>"type2 is like type1 but with the following differences") then the 
>interpreter will consult the other type, and so on and so on. I am 
>deliberately ignoring multiple inheritance ("typeC is like typeB, and 
>it's also like typeA") here, but the essentials are the same. We say the 
>subclass "inherits" the attributes of the superclass.
>
>If the interpreter keeps walking up the inheritance tree in this way 
>without finding the attribute it's looking for, it will eventually 
>arrive at the type "object", because ultimately every object in Python 
>is defined as a subclass of (a subclass of (a subclass of ...)) object.
Unless the attribute access started on a type, in which case it will check
for type.method before object.method, UIAM. BTW, in order to find either
kind of attribute, there will first be a search for type(instance).__getattribute__,
which is found as object.__getattribute__ or type.__getattribute__ unless overridden
(or instance is of an old-style class as mentioned above).
I suspect these then implement the check for __getattr__, which can be user defined
to intercept attribute access on particular objects in the search chain, after
higher-priority stuff fails.

[... Can't ... keep .. eyes ... open ... for ... rest ...]
(not the fault of your prose, had a beer ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list