使用 Python C-API 定义内部 class
Defining an inner class using the Python C-API
在Python中直接定义一个内层class:
class MyClass(object):
class MyInnerClass(object):
pass
… 可以像预期的那样访问内部 class,例如通过 MyClass.MyInnerClass
.
我正在尝试使用扩展模块设置类似的东西。通常,一个人将自己定义的扩展类型添加到模块的 <modulename>init()
函数中的扩展模块对象,代码如下:
/// …
if (PyType_Ready(&BufferModel_Type) < 0) { return; }
/// Add the BufferModel type object to the module
Py_INCREF(&BufferModel_Type);
PyModule_AddObject(module,
"Buffer",
(PyObject*)&BufferModel_Type);
/// …
为了设置内部 class,我改变了这种方法来尝试添加一个 PyTypeObject*
作为另一个 PyTypeObject*
的属性,如下所示:
/// …
if (PyType_Ready(&ImageBufferModel_Type) < 0) { return; }
if (PyType_Ready(&ImageModel_Type) < 0) { return; }
/// Add the ImageBufferModel type object to im.Image
Py_INCREF(&ImageBufferModel_Type);
PyObject_SetAttrString((PyObject*)&ImageModel_Type,
"ImageBuffer",
(PyObject*)&ImageBufferModel_Type);
PyType_Modified((PyTypeObject*)&ImageModel_Type);
/// Add the ImageModel type object to the module
Py_INCREF(&ImageModel_Type);
PyModule_AddObject(module,
"Image",
(PyObject*)&ImageModel_Type);
/// …
…我认为 PyObject_SetAttrString()
会起作用,因为 introduction to “Type Objects” in the C-API docs 具体说:
Type objects can be handled using any of the PyObject_*()
or
PyType_*()
functions […]
… 我在 its description in the docs 的基础上添加了调用 PyType_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'
…我想我的做法是错误的;我应该尝试什么?
为此你需要直接使用tp_dict
:
This field should normally be initialized to NULL before PyType_Ready
is called; it may also be initialized to a dictionary containing initial attributes for the type. Once PyType_Ready()
has initialized the type, extra attributes for the type may be added to this dictionary only if they don’t correspond to overloaded operations (like __add__()
).
除了使用 PyObject_SetAttrString()
你还可以
PyDict_SetItemString(ImageModel_Type.tp_dict, "ImageBuffer", (PyObject*) &ImageModel_Type);
但在这种情况下,文档中的警告适用:
It is not safe to use PyDict_SetItem()
on or otherwise modify tp_dict
with the dictionary C-API.
所以也许在 ImageModel_Type
上调用 PyType_Ready
之前初始化 tp_dict
:
/// Initialize tp_dict with empty dictionary
ImageModel_Type.tp_dict = PyDict_New();
if (!ImageModel_Type.tp_dict) { return; }
/// Add the ImageBufferModel type object to im.Image
if (PyType_Ready(&ImageBufferModel_Type) < 0) { return; }
Py_INCREF(&ImageBufferModel_Type);
PyDict_SetItemString(ImageModel_Type.tp_dict,
"ImageBuffer",
(PyObject*)&ImageBufferModel_Type);
/// Add the ImageModel type object to the module
if (PyType_Ready(&ImageModel_Type) < 0) { return; }
Py_INCREF(&ImageModel_Type);
PyModule_AddObject(module,
"Image",
(PyObject*)&ImageModel_Type);
在Python中直接定义一个内层class:
class MyClass(object):
class MyInnerClass(object):
pass
… 可以像预期的那样访问内部 class,例如通过 MyClass.MyInnerClass
.
我正在尝试使用扩展模块设置类似的东西。通常,一个人将自己定义的扩展类型添加到模块的 <modulename>init()
函数中的扩展模块对象,代码如下:
/// …
if (PyType_Ready(&BufferModel_Type) < 0) { return; }
/// Add the BufferModel type object to the module
Py_INCREF(&BufferModel_Type);
PyModule_AddObject(module,
"Buffer",
(PyObject*)&BufferModel_Type);
/// …
为了设置内部 class,我改变了这种方法来尝试添加一个 PyTypeObject*
作为另一个 PyTypeObject*
的属性,如下所示:
/// …
if (PyType_Ready(&ImageBufferModel_Type) < 0) { return; }
if (PyType_Ready(&ImageModel_Type) < 0) { return; }
/// Add the ImageBufferModel type object to im.Image
Py_INCREF(&ImageBufferModel_Type);
PyObject_SetAttrString((PyObject*)&ImageModel_Type,
"ImageBuffer",
(PyObject*)&ImageBufferModel_Type);
PyType_Modified((PyTypeObject*)&ImageModel_Type);
/// Add the ImageModel type object to the module
Py_INCREF(&ImageModel_Type);
PyModule_AddObject(module,
"Image",
(PyObject*)&ImageModel_Type);
/// …
…我认为 PyObject_SetAttrString()
会起作用,因为 introduction to “Type Objects” in the C-API docs 具体说:
Type objects can be handled using any of the
PyObject_*()
orPyType_*()
functions […]
… 我在 its description in the docs 的基础上添加了调用 PyType_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'
…我想我的做法是错误的;我应该尝试什么?
为此你需要直接使用tp_dict
:
This field should normally be initialized to NULL before
PyType_Ready
is called; it may also be initialized to a dictionary containing initial attributes for the type. OncePyType_Ready()
has initialized the type, extra attributes for the type may be added to this dictionary only if they don’t correspond to overloaded operations (like__add__()
).
除了使用 PyObject_SetAttrString()
你还可以
PyDict_SetItemString(ImageModel_Type.tp_dict, "ImageBuffer", (PyObject*) &ImageModel_Type);
但在这种情况下,文档中的警告适用:
It is not safe to use
PyDict_SetItem()
on or otherwise modifytp_dict
with the dictionary C-API.
所以也许在 ImageModel_Type
上调用 PyType_Ready
之前初始化 tp_dict
:
/// Initialize tp_dict with empty dictionary
ImageModel_Type.tp_dict = PyDict_New();
if (!ImageModel_Type.tp_dict) { return; }
/// Add the ImageBufferModel type object to im.Image
if (PyType_Ready(&ImageBufferModel_Type) < 0) { return; }
Py_INCREF(&ImageBufferModel_Type);
PyDict_SetItemString(ImageModel_Type.tp_dict,
"ImageBuffer",
(PyObject*)&ImageBufferModel_Type);
/// Add the ImageModel type object to the module
if (PyType_Ready(&ImageModel_Type) < 0) { return; }
Py_INCREF(&ImageModel_Type);
PyModule_AddObject(module,
"Image",
(PyObject*)&ImageModel_Type);