5

Python in a Nutshell describes:

How is the __getattribute__ method involved in the above lookup procedures?

  • Is the __getattribute__ method called somewhere in the lookup procedures?

  • Or, are the lookup procedures started by calling __getattribute__, which then does all the work in the two links?

Thanks.

Tim
  • 1
  • 141
  • 372
  • 590
  • With all these attribute lookup questions you've been asking, I figured you'd want to hear about this part eventually. – user2357112 Jul 08 '17 at 23:12
  • [Relevant](https://stackoverflow.com/questions/39043912/python-3-getattribute-vs-dot-access-behaviour), though with a focus on different details than the ones you're looking at. – user2357112 Jul 08 '17 at 23:22

1 Answers1

2

TLDR: Attribute lookup starts with calling __getattribute__ and it does all the work mentioned in the links. Based on the type of the object either object.__getattribute__ or type.__getattribute__ is called.


Any attribute lookup results in LOAD_ATTR bytecode internally.

>>> import dis    
>>> dis.dis(lambda: foo.x)
  1           0 LOAD_GLOBAL              0 (foo)
              2 LOAD_ATTR                1 (x)
              4 RETURN_VALUE

LOAD_ATTR then calls PyObject_GetAttr.

PyObject_GetAttr now looks for either tp_getattro or tp_getattr(deprecated) slot on the object's type.

PyObject *

PyObject_GetAttr(PyObject *v, PyObject *name)
{
    PyTypeObject *tp = Py_TYPE(v);
    ...
    if (tp->tp_getattro != NULL)
        return (*tp->tp_getattro)(v, name);
    if (tp->tp_getattr != NULL) {
        const char *name_str = PyUnicode_AsUTF8(name);
        if (name_str == NULL)
            return NULL;
        return (*tp->tp_getattr)(v, (char *)name_str);
    }
    ...
}

Now if an object has its own implementation of __getattribute__ then that is used else it falls back to either object.__getattribute__ or type.__getattribute__ based on the type. tp_getattro slot in case of object points to PyObject_GenericGetAttr and for type it points to type_getattro.

PyObject_GenericGetAttr and type_getattro basically do all the work of checking for descriptors, dictionary, slots etc(based on the type) and try to return a value. If they fail to find it even after everything then AttributeError is raised and if the object's type defined __getattr__ then it will be invoked.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504