Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How python attribute lookup process works?

Tags:

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)

  1. If attrname is a special (i.e. Python-provided) attribute for objectname, return it.
  2. 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.
  3. 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.
  4. 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.
  5. 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.

like image 941
Ariel Avatar asked Jun 26 '12 15:06

Ariel


People also ask

How do you access the attributes of an object in Python?

getattr() – This function is used to access the attribute of object. hasattr() – This function is used to check if an attribute exist or not. setattr() – This function is used to set an attribute.

What is __ class __ in Python?

__class__ is an attribute on the object that refers to the class from which the object was created. a. __class__ # Output: <class 'int'> b. __class__ # Output: <class 'float'> After simple data types, let's now understand the type function and __class__ attribute with the help of a user-defined class, Human .

What is Python __ slots __?

__slots__ is a class variable. If you have more than one instance of your class, any change made to __slots__ will show up in every instance. You cannot access the memory allocated by the __slots__ declaration by using subscription. You will get only what is currently stored in the list.

What is __ module __ in Python?

A module in Python is a file (ending in .py ) that contains a set of definitions (variables and functions) that you can use when they are imported. Modules are considered as objects, just as everything else is in Python.


1 Answers

If you added print("Metaclass getattribute invoked:", self, name) you'd see:

>>> c.__getattribute__ Class getattribute invoked: <__main__.C object at 0x2acdbb1430d0> __getattribute__ Metaclass getattribute invoked: <class '__main__.C'> __name__ <bound method C.__getattribute__ of <__main__.C object at 0x2acdbb1430d0>> 

The metaclass __getattribute__ is getting invoked in order to build the repr of the expression c.__getattribute__, so that it can print C's __name__.

btw, __getattribute__ works the same for classes and metaclasses; the attribute is looked up first on the instance then on the instance's type.

>>> Meta.foo = 1 >>> C.foo ('Metaclass getattribute invoked:', <class '__main__.C'>, 'foo') 1 >>> c.foo ('Class getattribute invoked:', <__main__.C object at 0x2acdbb1430d0>, 'foo') Traceback (most recent call last):   File "<stdin>", line 1, in <module>   File "<stdin>", line 5, in __getattribute__ AttributeError: 'C' object has no attribute 'foo' >>> C.bar = 2 >>> c.bar ('Class getattribute invoked:', <__main__.C object at 0x2acdbb1430d0>, 'bar') 2 
like image 192
ecatmur Avatar answered Nov 08 '22 20:11

ecatmur