Где это сообщение об ошибке атрибута реализовано в CPython?

#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 и теперь я могу его найти ( здесь ).