【发布时间】:2021-11-23 13:31:43
【问题描述】:
我正在开发一个自定义 Python 加载器,它可以从特定类型的非 Python 文件创建 Python 模块,我们称之为“奶酪文件”。我将我的项目编写为 C 扩展模块,因为这些“奶酪文件”需要由相当复杂的 C 库处理(其次,作为了解 Python/C API 的一种方式)。
在处理奶酪文件时,C 库会分配一些数据结构,这些数据结构需要在删除 Python 模块对象后释放。我的问题是,我如何/应该将这些 C 数据结构与 Python 模块对象一起存储?
我的一些想法:
-
我认为最干净的选择是从 C 中继承 Python 的
ModuleType并在子类中添加一个字段来存储数据结构。 extension types tutorial 显然很清楚如何在 C 中对内置 Python 类型进行子类化,所以我希望能够做这样的事情:typedef struct { PyModuleObject module; struct cheese_data* data; } PyCheeseModule; static PyTypeObject PyCheeseModule_Type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_basicsize = sizeof(PyCheeseModule), .tp_flags = Py_TPFLAGS_DEFAULT, .tp_base = &PyModule_Type, /* other fields */ };但是
PyModuleObject没有作为 Python/C API 的一部分公开,所以我不能以这种方式使用它。 -
我还考虑为每个奶酪模块动态分配
PyModuleDef,并使用PyModule_FromDefAndSpec()和PyModule_ExecDef()来创建和执行实际模块。但是我不确定PyModuleDef是否应该以这种方式使用,因为文档仅使用静态定义的C 扩展模块演示它,无论如何我都必须释放PyModuleDef对象本身带来的那种我回到同样的问题。 -
另一种方法是将 C 数据结构包装在 Python 对象中,然后将其添加到模块的字典中。但是,Python 代码可能会更改或取消设置该属性。我想我可以找到解决此问题的方法,但这似乎很不优雅。
-
也许我应该在这个项目中使用 Cython。但即便如此,如果这个问题在 Cython 中是可以解决的,也应该可能使用普通的旧 Python/C API 来解决,至少对于教育价值我想知道如何。
如有必要,我可以用一些额外的代码来扩展这些尝试。
【问题讨论】:
标签: python c python-3.x python-c-api