#python #attributeerror #cpython #python-internals
Вопрос:
Я думаю, что AttributeError
сообщение в этом сеансе Python
>>> class A: pass
...
>>> A().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'x'
реализована в функции _PyObject_GenericGetAttrWithDict
в этих строках в CPython:
if (!suppress) {
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%U'",
tp->tp_name, name);
}
Однако я не могу найти, где AttributeError
находится сообщение в этом сеансе Python
>>> class A: __slots__ = ('x',)
...
>>> A().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: x
реализован в CPython. Не могли бы вы предоставить ссылку на точные строки в репозитории GitHub?
Ответ №1:
Это здесь:
case T_OBJECT_EX:
v = *(PyObject **)addr;
if (v == NULL)
PyErr_SetString(PyExc_AttributeError, l->name);
Py_XINCREF(v);
break;
Это отрывок из PyMember_GetOne
, в котором реализована большая часть логики __get__
метода дескриптора слота.
Вас также может заинтересовать, как туда попадает этот дескриптор. type.__new__
внутренне преобразуется __slots__
в массив PyMemberDef
структур, один из механизмов, которые классы, написанные на C, используют для определения доступа к своим внутренним данным. Все PyMemberDef
структуры , созданные таким образом, помечены T_OBJECT_EX
, что означает, что они соответствуют a PyObject *
в макете памяти экземпляра, и если указатель равен нулю, доступ должен вызвать ошибку атрибута. PyType_Ready
затем генерирует дескрипторы слотов на основе PyMemberDef
массива.
Комментарии:
1. Потрясающе, спасибо! Я также искал реализацию
AttributeError: x
сообщения, поднятого,del A().x
и теперь я могу его найти ( здесь ).