Search attribute from instance

Python in a nutshell

Getting attribute from instance

When you use the x.name syntax to denote the instance attribute x class C , the search is performed in three steps:

  • When name is in C (or in one of C s ancestor classes) as the name of the overriding descriptor v (i.e. type(v) provides the __get__ and __set__ )

    • The value of x.name is the result of type(v).__get__(v, x, C)

  • Otherwise, when name is the key in x.__dict__

    x.name retrieves and returns the value in x.__dict__['name']

  • Otherwise, x.name delegates the search to the class x s (according to the same two-step search used for C.name as soon as detailed)

    • When the descriptor v found, the general result is an attribute search, again, type(v).__get__(v, x, C)

    • When the found value of v not defined, the total attribute search result is simply v

When these search steps find no attribute, Python throws an AttributeError exception. However, to search for x.name when C defines or inherits the special __getattr__ method, Python calls C.__getattr__(x,'name') instead of raising an exception. Then, before __getattr__ either return the appropriate value or raise the corresponding exception, usually an AttributeError .

  • Are steps 1 and the first part of step 3 the same? If so, why does the same step appear twice?

  • They both occur "when name is in C (or in one of C s ancestor classes) as the name of the overriding descriptor v "?


 __getattribute__(self, name) 

For every request to access the xy attribute, calls Python x.__getattribute__('y') , which should receive and return the attribute value, or raise an AttributeError . The normal semantics of attribute access (using x.__dict__ , C.__slots__ , C s class attributes, x.__getattr__ ) are associated with object.__getattribute__ . When the C class overrides __getattribute__ , it must implement all the attribute access semantics that it wants to offer. Most often, the most convenient way to implement delegation access semantics is delegating (for example, calling object.__getattribute__(self, ...) as part of your override of __getattribute__ ).

+1
source share
1 answer

Are steps 1 and the first part of step 3 the same? If so, why does the same step appear twice?

Step 1 requires both __get__ and __set__ (although in fact it is either running __set__ or __delete__ , as well as __get__ ). Step 3 is performed unconditionally if the attribute is not found using steps 1 or 2.

They both occur "when the name is found in C (or in one of the Cs ancestor classes) as the name of the overriding descriptor v"?

No. The "redefinition descriptor" starts step 1; another kind of descriptor or non-descriptor will be considered only in step 3. (Python docs do not use the term “overriding descriptor”, they refer to a descriptor with __set__ or __delete__ as a “data descriptor”, and if the data descriptor has __get__ , __get__ will take precedence over an object found in a dict instance.)

+2
source

Source: https://habr.com/ru/post/1269643/


All Articles