从C创建一个实现__dict__的Python类型?
- 根据“正常”类创建的
__dict__
类型是如何在Python中定义的? - 有没有
__dict__
s的非动态类型的例子? - 通过Python的
type_new
定义的类型是否通过type_new
?
tp_dict
有一个tp_dict
成员,但我找不到有关如何使用它的信息。 在typeobject.c
的type_new
似乎也有一些事情发生,但我无法清楚地解读它。
以下是我发现的一些相关信息:
- inheritance自C扩展模块的类中的
__dict__
- 如何在Python中实现__slots__?
以下代码将生成一个在Python 2.x中实现__dict__
的类:
typedef struct { PyObject_HEAD PyObject* dict; } BarObject; static PyTypeObject BarObject_Type = { PyObject_HEAD_INIT(NULL) }; PyMODINIT_FUNC initFoo(void) { PyObject *m; m = Py_InitModule("Foo", NULL); if (m == NULL) return; BarObject_Type.tp_new = PyType_GenericNew; BarObject_Type.tp_name = "Foo.Bar"; BarObject_Type.tp_basicsize = sizeof(BarObject); BarObject_Type.tp_getattro = PyObject_GenericGetAttr; BarObject_Type.tp_setattro = PyObject_GenericSetAttr; BarObject_Type.tp_flags = Py_TPFLAGS_DEFAULT; BarObject_Type.tp_dictoffset = offsetof(BarObject,dict); BarObject_Type.tp_doc = "Doc string for class Bar in module Foo."; if (PyType_Ready(&BarObject_Type) < 0) return; Py_INCREF(&BarObject_Type); PyModule_AddObject(m, "Bar", (PyObject*)&BarObject_Type); }
重要的一点是tp_dictoffset
结构的tp_dictoffset
成员( http://docs.python.org/c-api/typeobj.html ):
如果此类型的实例具有包含实例变量的字典,则此字段为非零并包含实例变量字典类型实例中的偏移量; PyObject_GenericGetAttr()使用此偏移量。
不要将此字段与tp_dict混淆; 这是类型对象本身的属性的字典。
首先回答最后一个问题:不, type_new
仅用于在运行时动态定义的“堆类型”(例如,通过类语句)。 静态定义的类型使用PyType_Ready()
进行初始化。
回答第一个问题:要创建带有__dict__
描述符的扩展类型,您需要以与解释器对类定义相同的方式动态分配类型。
获得示例的一种方法是按照John建议并使用Cython生成一些您自己的示例。
对于CPython 2.x,您可以查看CPython源代码中的build_class
方法( http://svn.python.org/view/python/trunk/Python/ceval.c?view=markup )以了解涉及完全通用解决方案的步骤。
如果您正在使用Python 3,那么这个问题可能会引起关注: Python的内置__build_class__做什么?
也就是说,作为CPython 3.x特定解决方案,最简单的方法是通过C API使用适当的参数调用builtins.__build_class__
。
我还没有这样做,我对使用C-API感到尴尬,但根据文档,使用PyObject_GenericGetAttr
和PyObject_GenericSetAttr
来获取getattro
和setattro
方法就足够了。 当然,您还需要一个名为__dict__
的PyObject属性。
你试过吗?
如何编写定义一个类和一个或两个方法的Python代码,用Cython编译它并检查生成的C代码?