我正在调查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 的线索?
答案 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扩展模块中的代码和内部解释器代码可以:
PyObject_New
,它分配对象并在其上调用PyObject_Init
,并转换结果指针PyObject_Init
(当它知道其构建的类型不会自定义tp_new
,tp_alloc
或tp_init
)时PyObject_Init
系列,或者自己做同样的事情,就像使用自定义tp_alloc
PyNone
和许多内置和扩展类型对象,在这种情况下,类型(当然也必须是静态常量)才被指定在struct initializer中。