When i say "python attribute lookup proccess" i mean: what python does when you write x.foo??
Searching the web i didn't found to much docs about this, one of the best papers i found resumed the proccess to the following steps (you can see the full article here)
- If attrname is a special (i.e. Python-provided) attribute for objectname, return it.
- Check objectname._class_._dict_ for attrname. If it exists and is a data-descriptor, return the descriptor result. Search all bases of objectname._class_ for the same case.
- Check objectname._dict_ for attrname, and return if found. If objectname is a class, search its bases too. If it is a class and a descriptor exists in it or its bases, return the descriptor result.
- Check objectname._class_._dict_ for attrname. If it exists and is a non-data descriptor, return the descriptor result. If it exists, and is not a descriptor, just return it. If it exists and is a data descriptor, we shouldn't be here because we would have returned at point 2. Search all bases of objectname._class_ for same case.
- Raise AttributeError.
At first this might seem right, but the attribute lookup process is a little bit more complicated, for example for x.foo, it doesn't behave the same if x is a class or an instance.
I have a found some samples that can't be explained by this way. Consider the following python code:
class Meta(type): def __getattribute__(self, name): print("Metaclass getattribute invoked:", self) return type.__getattribute__(self, name) def __getattr__(self, item): print('Metaclass getattr invoked: ', item) return None class C(object, metaclass=Meta): def __getattribute__(self, name): print("Class getattribute invoked:", args) return object.__getattribute__(self, name) c=C() Now check the following lines with the corresponding output:
>> C.__new__ Metaclass getattribute invoked: <class '__main__.C'> <built-in method __new__ of type object at 0x1E1B80B0> >> C.__getattribute__ Metaclass getattribute invoked: <class '__main__.C'> <function __getattribute__ at 0x01457F18> >> C.xyz Metaclass getattribute invoked: <class '__main__.C'> Metaclass getattr invoked: xyz None >> c.__new__ Class getattribute invoked: (<__main__.C object at 0x013E7550>, '__new__') <built-in method __new__ of type object at 0x1E1B80B0> >> c.__getattribute__ Class getattribute invoked: (<__main__.C object at 0x01438DB0>, '__getattribute__') Metaclass getattribute invoked: <class '__main__.C'> <bound method C.__getattribute__ of <__main__.C object at 0x01438DB0>> >> The conclusions i have been are (considering we're searching for x.foo):
- _getattribute_ is different for instances of < type 'type' > and < type 'object' >. For C.foo(), 'foo' is searched first on C._dict_ and returned if found (instead of searching type(C)) and for x.foo() 'foo' is searched on type(x)._dict_ and on x._dict_.
- _getattribute_ method is always resolved on type(x), what i don't understand here is the last case: c._getattribute_, isn't object contains a method _getattribute_ (and C inherits from object), so why does metaclass getattribute method gets called.
Can someone explain this please?? or at less tell me where can i find some documentation about this, thanks.
See also: Why don't methods have reference equality?.