Как PyObject.ob_type инициализируется / устанавливается в CPython 2.7 - PullRequest
0 голосов
/ 17 мая 2018

Я изучаю, как функция isinstance () работает для CPython 2.7

Теперь у меня есть пример с двумя файлами Python: lib1.py lib2.py

In lib1.py:
from a.b import lib2
def func_h():
  ob = lib2.X()
  print(isinstance(ob, lib2.X))

In lib2.py:
class X(object):
  a = 1

Результаты выводятся на печать:True

Затем я копаюсь в исходном коде CPython в https://github.com/python/cpython/blob/ad65d09fd02512b2ccf500f6c11063f705c9cd28/Objects/abstract.c#L2945

, где CPython сделал эту проверку:

if (Py_TYPE(inst) == (PyTypeObject *)cls)
        return 1;

, где Py_TYPE () - макрос

#define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)

Кто-нибудь знает, как CPython запускает или устанавливает ob_type во время запуска программы?

1 Ответ

0 голосов
/ 17 мая 2018

Обычно это происходит в 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 и множество встроенных и расширенных типов объектов, в этом случае тип (который также должен быть статической константой, конечно же, ) просто указывается в инициализаторе структуры.
...