使用Python C-API定义内部类

使用Python C-API定义内部类,python,python-c-api,setattribute,setattr,pyobject,Python,Python C Api,Setattribute,Setattr,Pyobject,在Python中,定义内部类非常简单: 类MyClass(对象): 类MyInnerClass(对象): 通过 …可以按预期访问内部类,例如通过执行MyClass.MyInnerClass 我正在尝试设置类似的扩展模块。通常,在modules'init()函数中将定义的扩展类型添加到扩展模块对象中,代码如下: //… if(PyType_Ready(&BufferModel_Type)

在Python中,定义内部类非常简单:

类MyClass(对象):
类MyInnerClass(对象):
通过
…可以按预期访问内部类,例如通过执行
MyClass.MyInnerClass

我正在尝试设置类似的扩展模块。通常,在modules'
init()
函数中将定义的扩展类型添加到扩展模块对象中,代码如下:

//…
if(PyType_Ready(&BufferModel_Type)<0){return;}
///将BufferModel类型对象添加到模块
Py_增量(&BufferModel_类型);
PyModule_AddObject(模块,
“缓冲区”,
(PyObject*)和BufferModel_类型);
/// …
为了设置内部类,我改变了这种方法,尝试添加一个
PyTypeObject*
作为另一个
PyTypeObject*
的属性,如下所示:

//…
if(PyType_Ready(&ImageBufferModel_Type)<0){return;}
if(PyType_Ready(&ImageModel_Type)<0){return;}
///将ImageBufferModel类型对象添加到im.Image
Py_增量(&ImageBufferModel_类型);
PyObject_SetAttrString((PyObject*)和ImageModel_类型,
“图像缓冲区”,
(PyObject*)和ImageBufferModel_类型);
PyType_-Modified((PyTypeObject*)和ImageModel_-Type);
///将ImageModel类型对象添加到模块
Py_增量(&ImageModel_类型);
PyModule_AddObject(模块,
“图像”,
(PyObject*)和ImageModel_类型);
/// …
…我想,
PyObject\u SetAttrString()
将按照

类型对象可以使用
PyObject_*()
PyType_*()
函数[…]

…我根据添加了调用
PyType\u Modified()
。但是,当我编译所有内容并尝试加载扩展时,会出现以下错误:

>>> import im
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    import im
  File "im/__init__.py", line 2, in <module>
    from im import (
TypeError: can't set attributes of built-in/extension type 'im.Image'
导入im 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 导入即时消息 文件“im/\uuuu init\uuuuu.py”,第2行,在 从im导入( TypeError:无法设置内置/扩展类型“im.Image”的属性 …我想我是走错了路;我应该试试什么?

为此,您需要直接使用:

在调用
PyType\u Ready
之前,此字段通常应初始化为NULL;也可以将其初始化为包含该类型初始属性的字典。一旦
PyType\u Ready()
已初始化该类型,只有当该类型的额外属性与重载操作(如
\uuuuu add\uuu()
)不对应时,才能将其添加到此字典中

您不必使用
PyObject\u SetAttrString()
只需

PyDict_SetItemString(ImageModel_Type.tp_dict, "ImageBuffer", (PyObject*) &ImageModel_Type);
但在这种情况下,文件中的警告适用:

在字典C-API上使用
PyDict_SetItem()
或以其他方式修改
tp_dict
是不安全的

因此,在调用
ImageModel\u Type
上的
PyType\u Ready
之前,可以初始化
tp\u dict

///使用空字典初始化tp\u dict
ImageModel_Type.tp_dict=PyDict_New();
如果(!ImageModel_Type.tp_dict){return;}
///将ImageBufferModel类型对象添加到im.Image
if(PyType_Ready(&ImageBufferModel_Type)<0){return;}
Py_增量(&ImageBufferModel_类型);
PyDict_SetItemString(ImageModel_Type.tp_dict,
“图像缓冲区”,
(PyObject*)和ImageBufferModel_类型);
///将ImageModel类型对象添加到模块
if(PyType_Ready(&ImageModel_Type)<0){return;}
Py_增量(&ImageModel_类型);
PyModule_AddObject(模块,
“图像”,
(PyObject*)和ImageModel_类型);
为此,您需要直接使用:

在调用
PyType\u Ready
之前,此字段通常应初始化为NULL;也可以将其初始化为包含该类型初始属性的字典。一旦
PyType\u Ready()
已初始化该类型,只有当该类型的额外属性与重载操作(如
\uuuuu add\uuu()
)不对应时,才能将其添加到此字典中

您不必使用
PyObject\u SetAttrString()
只需

PyDict_SetItemString(ImageModel_Type.tp_dict, "ImageBuffer", (PyObject*) &ImageModel_Type);
但在这种情况下,文件中的警告适用:

在字典C-API上使用
PyDict_SetItem()
或以其他方式修改
tp_dict
是不安全的

因此,在调用
ImageModel\u Type
上的
PyType\u Ready
之前,可以初始化
tp\u dict

///使用空字典初始化tp\u dict
ImageModel_Type.tp_dict=PyDict_New();
如果(!ImageModel_Type.tp_dict){return;}
///将ImageBufferModel类型对象添加到im.Image
if(PyType_Ready(&ImageBufferModel_Type)<0){return;}
Py_增量(&ImageBufferModel_类型);
PyDict_SetItemString(ImageModel_Type.tp_dict,
“图像缓冲区”,
(PyObject*)和ImageBufferModel_类型);
///将ImageModel类型对象添加到模块
if(PyType_Ready(&ImageModel_Type)<0){return;}
Py_增量(&ImageModel_类型);
PyModule_AddObject(模块,
“图像”,
(PyObject*)和ImageModel_类型);

Wow,谢谢!类型对象文档有时会让人困惑,我很欣赏这个直接的答案,这完全有效。我还应该补充一点,在Python方面,对PyTypeObject的
tp_dict
数据成员进行更改可以实现许多通常使用元类实现的相同目的(例如,合成基于类的描述符ála Django的ORM等).Wow,谢谢!类型对象文档有时会让人困惑,我很欣赏这个直接的答案,这完全有效。我还应该补充一点,在Python方面,对PyTypeObject的
tp_dict
数据成员进行更改可以实现许多通常使用元类实现的相同目的(例如,合成基于类的描述符ála Django的ORM等)。