Обычно это происходит в PyObject_Init
(или PyObject_InitVar
, о котором я больше не буду упоминать, но есть эквивалентные варианты по всем направлениям), или в макросе PyObject_INIT
(который делает то же самое в более быстром способе, но тот, который не гарантированно является двоично-совместимым с другими интерпретаторами, построен на той же платформе). Документы для PyObject_Init
говорят:
Инициализировать вновь выделенный объект op с его типом и начальной ссылкой. Возвращает инициализированный объект. Если тип указывает, что объект участвует в циклическом детекторе мусора, он добавляется в набор обнаруженных объектов детектора. Другие поля объекта не затрагиваются.
Вы можете видеть источник в object.c
:
PyObject *
PyObject_Init(PyObject *op, PyTypeObject *tp)
{
if (op == NULL)
return PyErr_NoMemory();
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
Py_TYPE(op) = tp;
_Py_NewReference(op);
return op;
}
Подробнее см. в комментариях objimpl.h
.
Когда объект создается из Python (или с помощью высокоуровневого C API):
- Вызывается метод типа
__new__
или слот tp_new
.
- Это обычно наследуется от или
super
s до object_new
, что вызывает PyType_GenericNew
.
- … или он делегирует другому конструктору (который в конечном итоге возвращает вас сюда)
- … или возвращает какой-то уже существующий объект
- … но если нет, он должен вызвать
tp_alloc
вручную.
PyType_GenericNew
вызывает слот типа tp_alloc
(для этого нет специального метода Python).
- Обычно он наследуется от или
super
с до PyType_GenericAlloc
, что вызывает макрос PyObject_INIT
.
- … но если нет,
tp_alloc
должен вызвать одну из функций или макросов PyObject_Init
-семейства или сделать то же самое сам.
Код в модулях расширения C и внутренний код интерпретатора могут:
- Используйте тот же API высокого уровня
- … или вызовите
PyObject_New
, который выделяет объект и вызывает PyObject_Init
на нем и приводит указатель результата
- … или просто позвоните
PyObject_Init
напрямую (когда он знает тип, который он создает, он не настраивает tp_new
, tp_alloc
или tp_init
)
- … или создавать объекты вручную, но в какой-то момент он должен прямо или косвенно вызывать одно из семейства
PyObject_Init
, или делать то же самое сам, как с обычным tp_alloc
- … или размещать константные объекты статически, а не в куче, как
PyNone
и множество встроенных и расширенных типов объектов, в этом случае тип (который также должен быть статической константой, конечно же, ) просто указывается в инициализаторе структуры.