PyObject.ob_type如何在CPython 2.7中初始化/设置

时间:2018-05-17 02:05:29

标签: python cpython

我正在调查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

结果打印:正确

然后我深入研究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 :(得分:2)

通常情况下,这种情况发生在PyObject_Init(或PyObject_InitVar,我不会再提及,但整体上有相同的变化)或PyObject_INIT宏(它以更快的方式执行相同的操作,但是不能保证与同一平台上的其他解释器构建二进制兼容)。 PyObject_Init的文档说:

  

使用其类型和初始引用初始化新分配的对象op。返回初始化对象。如果type指示对象参与循环垃圾检测器,则将其添加到检测器的一组观察对象中。对象的其他字段不受影响。

您可以看到the source in 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;
}

有关详细信息,请参阅the comments in objimpl.h

当从Python(或通过高级C API)构造对象时:

  • 调用类型的__new__方法或tp_new广告位。
    • 这通常会从super继承到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_newtp_alloctp_init)时
  • ...或手动构建对象,但在某些时候它必须直接或间接调用其中一个PyObject_Init系列,或者自己做同样的事情,就像使用自定义tp_alloc
  • 一样
  • ...或静态分配常量对象而不是堆,例如PyNone和许多内置和扩展类型对象,在这种情况下,类型(当然也必须是静态常量)才被指定在struct initializer中。