Last active
August 28, 2017 11:28
-
-
Save justdoit0823/e72a5d3a41a34bc63c0209b8a7ae3435 to your computer and use it in GitHub Desktop.
How Python resolves type attribute access
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This is similar to PyObject_GenericGetAttr(), | |
but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ | |
static PyObject * | |
type_getattro(PyTypeObject *type, PyObject *name) | |
{ | |
PyTypeObject *metatype = Py_TYPE(type); | |
PyObject *meta_attribute, *attribute; | |
descrgetfunc meta_get; | |
if (!PyUnicode_Check(name)) { | |
PyErr_Format(PyExc_TypeError, | |
"attribute name must be string, not '%.200s'", | |
name->ob_type->tp_name); | |
return NULL; | |
} | |
/* Initialize this type (we'll assume the metatype is initialized) */ | |
if (type->tp_dict == NULL) { | |
if (PyType_Ready(type) < 0) | |
return NULL; | |
} | |
/* No readable descriptor found yet */ | |
meta_get = NULL; | |
/* Look for the attribute in the metatype */ | |
meta_attribute = _PyType_Lookup(metatype, name); | |
if (meta_attribute != NULL) { | |
meta_get = Py_TYPE(meta_attribute)->tp_descr_get; | |
if (meta_get != NULL && PyDescr_IsData(meta_attribute)) { | |
/* Data descriptors implement tp_descr_set to intercept | |
* writes. Assume the attribute is not overridden in | |
* type's tp_dict (and bases): call the descriptor now. | |
*/ | |
return meta_get(meta_attribute, (PyObject *)type, | |
(PyObject *)metatype); | |
} | |
Py_INCREF(meta_attribute); | |
} | |
/* No data descriptor found on metatype. Look in tp_dict of this | |
* type and its bases */ | |
attribute = _PyType_Lookup(type, name); | |
if (attribute != NULL) { | |
/* Implement descriptor functionality, if any */ | |
descrgetfunc local_get = Py_TYPE(attribute)->tp_descr_get; | |
Py_XDECREF(meta_attribute); | |
if (local_get != NULL) { | |
/* NULL 2nd argument indicates the descriptor was | |
* found on the target object itself (or a base) */ | |
return local_get(attribute, (PyObject *)NULL, | |
(PyObject *)type); | |
} | |
Py_INCREF(attribute); | |
return attribute; | |
} | |
/* No attribute found in local __dict__ (or bases): use the | |
* descriptor from the metatype, if any */ | |
if (meta_get != NULL) { | |
PyObject *res; | |
res = meta_get(meta_attribute, (PyObject *)type, | |
(PyObject *)metatype); | |
Py_DECREF(meta_attribute); | |
return res; | |
} | |
/* If an ordinary attribute was found on the metatype, return it now */ | |
if (meta_attribute != NULL) { | |
return meta_attribute; | |
} | |
/* Give up */ | |
PyErr_Format(PyExc_AttributeError, | |
"type object '%.50s' has no attribute '%U'", | |
type->tp_name, name); | |
return NULL; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment