Python: the __getattribute__ method and descriptors

瘦欲@ 提交于 2019-11-30 16:25:28

Actually, in CPython the default __getattribute__ implementation is not a Python method, but is instead implemented in C. It can access object slots (entries in the C structure representing Python objects) directly, without bothering to go through the pesky attribute access routine.

Just because your Python code has to do this, doesn't mean the C code has to. :-)

If you do implement a Python __getattribute__ method, just use object.__getattribute__(self, attrname), or better still, super(YourClassName, self).__getattribute__(attrname) to access attributes on self. That way you won't hit recursion either.

In the CPython implementation, the attribute access is actually handled by the tp_getattro slot in the C type object, with a fallback to the tp_getattr slot. That way you can avoid recursing.

To be exhaustive and to fully expose what the C code does, when you use attribute access on an instance, here is the full set of functions called:

  • Python translates attribute access to a call to the PyObject_GetAttr() C function. The implementation for that function looks up the tp_getattro or tp_getattr slot for your class.

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

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

  • _PyType_Lookup looks up attributes on the class (and superclasses). The code uses direct pointers to cl_dict (custom Python classes) and tp_dict to reference class and type dictionaries.

  • If a descriptor is found by _PyType_Lookup it is returned to _PyObject_GenericGetAttrWithDict and it calls the tp_descr_get function on that object (the __get__ hook).

When you access an attribute on the class itself, instead of _PyObject_GenericGetAttrWithDict, the type->tp_getattro slot is instead serviced by the type_getattro() function, which takes meta classes into account too. This version calls __get__ too, but leaves the instance parameter set to None.

Nowhere does this code have to recursively call __getattribute__ to access the __dict__ attribute, as it can simply reach into the C structures directly.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!