如何拥有在Python C / C ++扩展之间共享的全局C / C ++变量?

我几乎完全用C ++编写了一个Python包。这样做的原因是因为我想手动包装现有的C ++库,但这与此处无关。

这个Python软件包包含许多不同的扩展模块,我用distutils在“ setup.py”脚本中对所有这些扩展模块进行了编译。这些扩展模块可以相互关联,在这种情况下,我通过将共享库传递给Extension构造函数来链接它们。为了清楚起见,假设我有两个Python C ++模块A和B,其中B使用A中定义的函数。这些函数通常编译为A.so和B.so。由于B使用A中定义的函数,因此我照常编译A模块,然后将':A.so'作为库传递给B模块的Extension构造函数中的librarys关键字。(“:”使g ++处理该库不是以通常的“ lib”前缀开头的事实。)这对于链接函数和类是很好的。

我的问题如下:我在A中定义了一些全局C ++变量。虽然我所做的描述允许B访问A中的函数,但实际上似乎为A中定义的任何全局数据创建了COPY。这是一个实际的问题。为了我。

在我看来,此问题本质上类似于在共享库中使用全局变量,如此处和其他地方所讨论。该解决方案以及我在网上找到的其他解决方案似乎都无法解决问题。


慕村225694
浏览 237回答 3
3回答

红糖糍粑

我猜想pythonic的方法是让不同的扩展通过C API进行交互。尽管我对c ++不太了解,但我想它与C中的解决方案并没有太大区别。我可以通过以下方式做到这一点:在模块A中定义全局变量为模块A定义一个C API,其中包含指向全局变量的指针(如果需要,还可以包含一个宏,以方便使用)。在模块B中加载C API并通过指针访问全局变量。编写用于python C扩展的C API涉及到一些工作。(如果您不熟悉Python C API,请阅读python文档。)我建议的解决方案的最小示例如下所示:A.h/* Header file for A module */#ifndef A_MODULE_H#define A_MODULE_H#ifdef __cplusplusextern "C" {#endif#define PyA_GET_X() (*x_ptr)#define PyA_SET_X(x) (*x_ptr = x)#ifdef A_MODULE/* do nothing for this minimal example */#elsestatic void **PyA_API;#define x_ptr ((long *)PyA_API[0])static int import_A(void){&nbsp; &nbsp; PyA_API = (void **)PyCapsule_Import("A._C_API", 0);&nbsp; &nbsp; return (PyA_API != NULL) ? 0 : -1;}#endif /* !defined(A_MODULE) */#ifdef __cplusplus}#endif#endif /* !defined(A_MODULE_H) */A.c#include <Python.h>#define A_MODULE#include "A.h"long x = 0; /* here is the global variable */static PyObject*&nbsp;set_x(PyObject *self, PyObject *args){&nbsp; &nbsp; if (!PyArg_ParseTuple(args, "l", &x)) return NULL;&nbsp; &nbsp; Py_RETURN_NONE;}static PyObject*&nbsp;get_x(PyObject *self, PyObject *args){&nbsp; &nbsp; return PyInt_FromLong(x);}static PyMethodDef methods[] = {&nbsp; &nbsp; {"set_x", (PyCFunction)set_x, METH_VARARGS, ""},&nbsp; &nbsp; {"get_x", (PyCFunction)get_x, METH_NOARGS, ""},&nbsp; &nbsp; {NULL, NULL, 0, NULL}&nbsp; &nbsp; };#ifndef PyMODINIT_FUNC&nbsp; /* declarations for DLL import/export */#define PyMODINIT_FUNC void#endifPyMODINIT_FUNC initA(void){&nbsp; &nbsp; PyObject *m = Py_InitModule3("A", methods, "");&nbsp; &nbsp; static void *PyA_API[1];&nbsp; &nbsp; PyA_API[0] = (void *)&x;&nbsp; &nbsp; PyObject *c_api_object = PyCapsule_New((void *)PyA_API, "A._C_API", NULL);&nbsp; &nbsp; if (c_api_object != NULL) PyModule_AddObject(m, "_C_API", c_api_object);}B.c#include <Python.h>#define B_MODULE#include "A.h"static PyObject*&nbsp;set_x(PyObject *self, PyObject *args){&nbsp; &nbsp; long y;&nbsp; &nbsp; if (!PyArg_ParseTuple(args, "l", &y)) return NULL;&nbsp; &nbsp; PyA_SET_X(y);&nbsp; &nbsp; Py_RETURN_NONE;}static PyObject*&nbsp;get_x(PyObject *self, PyObject *args){&nbsp; &nbsp; return PyInt_FromLong(PyA_GET_X());}static PyMethodDef methods[] = {&nbsp; &nbsp; {"set_x", (PyCFunction)set_x, METH_VARARGS, ""},&nbsp; &nbsp; {"get_x", (PyCFunction)get_x, METH_NOARGS, ""},&nbsp; &nbsp; {NULL, NULL, 0, NULL}&nbsp; &nbsp; };#ifndef PyMODINIT_FUNC&nbsp; /* declarations for DLL import/export */#define PyMODINIT_FUNC void#endifPyMODINIT_FUNC initB(void){&nbsp; &nbsp; import_A();&nbsp; &nbsp; Py_InitModule3("B", methods, "");}setup.pyfrom numpy.distutils.core import setup, Extensionsetup(&nbsp; &nbsp; name="AB",&nbsp; &nbsp; ext_modules = [Extension('A', ['A.c']), Extension('B', ['B.c'])],&nbsp; &nbsp; )最后,您将能够x从两个模块(C级或python)读取和修改。在python中,它看起来像:>>> import A, B>>> A.set_x(1)>>> B.get_x()&nbsp; &nbsp; 1>>> B.set_x(2)>>> A.get_x()&nbsp; &nbsp; 2要从C级访问,请使用宏PyA_GET_X()和PyA_SET_X(x)。

呼啦一阵风

如果可以从python代码调用c ++函数,则只需创建一个将访问全局变量的函数即可。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python