Python: __getattribute__ method and descriptors

according to this python descriptor guide https://docs.python.org/2/howto/descriptor.html

Method Objects

new classes of classes are implemented using descriptors to avoid special fairings in the search for attributes.

as I understand it, that there is a type of method object that implements __get__ and returns an object of the associated method when called with an instance and an unrelated method object when called without an instance and only a class. the article also says that this logic is implemented in the method method .__ getattribute__. So:

def __getattribute__(self, key): "Emulate type_getattro() in Objects/typeobject.c" v = object.__getattribute__(self, key) if hasattr(v, '__get__'): return v.__get__(None, self) return v 

however the .__ getattribute__ object itself is a method! so how is this related to the object (without infinite recursion)? if this is a special look in the attribute search, then this will not lead to victory in the goal of removing the old style of the old style?

+3
source share
1 answer

In fact, in CPython, the default implementation of __getattribute__ not a Python method, but is instead implemented in C. It can directly access object slots (entries in the C structure representing Python objects), without worrying about going through an annoying procedure access to attributes.

Just because your Python code needs to do this does not mean that C code should. :-)

If you implement the Python __getattribute__ method, just use object.__getattribute__(self, attrname) or better yet, super(YourClassName, self).__getattribute__(attrname) to access the attributes on self . This way you will not remove recursion either.

In the CPython implementation, attribute access is actually handled by the tp_getattro slot in an object of type C with a departure from the tp_getattr slot . This way you can avoid recursion.

To be comprehensive and to fully reveal what C code does when you use attribute access in an instance, here is a complete set of functions:

  • Python translates access to the call attribute of the PyObject_GetAttr() C function . The implementation for this function looks at the tp_getattro or tp_getattr for your class.

  • The type object has tp_getattr populated with _PyObject_GenericGetAttrWithDict . This function is your object.__getattribute__ (a special table displays between the name and slot).

  • This function can access the __dict__ object __dict__ via tp_dict slot , but for descriptors (including methods), the _PyType_Lookup function is used .

  • _PyType_Lookup looks at class attributes (and superclasses). The code uses direct pointers to cl_dict (custom Python classes) and tp_dict to refer to type and type dictionaries.

  • If the handle is found using _PyType_Lookup , it returns to _PyObject_GenericGetAttrWithDict and calls the tp_descr_get function on this object ( __get__ hook).

When accessing the attribute of the class itself instead of _PyObject_GenericGetAttrWithDict slot type->tp_getattro served by the type_getattro() function , which also takes meta classes into account. This version also calls __get__ , but the instance parameter is set to None .

Nowhere should this code recursively call __getattribute__ to access the __dict__ attribute, because it can just go directly to C.

+6
source

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


All Articles