从C创建一个实现__dict__的Python类型?

  • 根据“正常”类创建的__dict__类型是如何在Python中定义的?
  • 有没有__dict__ s的非动态类型的例子?
  • 通过Python的type_new定义的类型是否通过type_new

tp_dict有一个tp_dict成员,但我找不到有关如何使用它的信息。 在typeobject.ctype_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_GenericGetAttrPyObject_GenericSetAttr来获取getattrosetattro方法就足够了。 当然,您还需要一个名为__dict__的PyObject属性。

你试过吗?

如何编写定义一个类和一个或两个方法的Python代码,用Cython编译它并检查生成的C代码?