使用Python/C API传递C指针

2024-05-29 03:53:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Python/C API新手。。。我正在尝试向我的C程序添加新的功能,其中我可以将python嵌入其中,同时扩展功能,以便嵌入式解释器可以执行一个脚本,该脚本将与作为C程序一部分编写的扩展python模块交互。我的C程序没有全局变量。我希望保持这种方式;同时,为了向python公开C功能,扩展C函数似乎至少需要访问全局变量来访问程序的状态。我该怎么解决这个问题?

例如,下面是我计划如何嵌入从main调用PYINTERFACE_Initialize的地方

void PYINTERFACE_Initialize(State *ptr, FILE *scriptFile, const char* scriptFileName)
{
    Py_Initialize();
    PyObject *module = Py_InitModule("CInterface", CInterfaceMethods);
    if (PyRun_SimpleFileEx(scriptFile, scriptFileName, 1) != 0)
    {
        printf("PYINTERFACE script execution failed!\n");
    }
    **//ADD State *ptr TO module**      
}

下面是扩展函数:

static PyObject*
CInterface_GetStateInfo(PyObject *self, PyObject *args)
{
    const char *printStr;
    double stateInfo;
    State *ptr;

    if(!PyArg_ParseTuple(args, "s", &printStr))
    {
        return NULL;
    }
    printf("Received %s\n", printStr);

    **//RETRIEVE State *ptr FROM self**      

    stateInfo = ptr->info;
    return Py_BuildValue("d", currentTime);
}

这是最干净的方式来传递州警吗?我当然不认为有必要将内部状态公开给python。我考虑过使用胶囊,但胶囊似乎并不支持这种行为。

提前谢谢! 五


Tags: 函数py程序功能脚本状态方式pyobject
2条回答

胶囊基本上是python不透明的空指针,您可以将其传递或与模块关联。他们是解决你问题的“方法”。

下面是一个使用不必是静态的实例x的示例。首先将指针附加到模块,如下所示(删除错误检查…)。。。

// wrap the methods to be exposed to python in a module
// i.e. this is a list of method descriptions for the module
static PyMethodDef InitializeTurkeyMethods[] = {

    // this block describes one method.. turkey.do_something()
    {"do_something", 
     turkey_do_something, // fn pointer to wrap (defined below)
     METH_VARARGS, 
     "do something .. return an int."},

    {NULL, NULL, 0, NULL} // sentinel.
};


int init(X * x) { 

    // initialize embedded python scripting .. 
    // (this method a no-op on second or later calls).
    Py_Initialize();

    // initialize the turkey python module 
    PyObject * module = Py_InitModule("turkey", InitializeTurkeyMethods);

    // Create a capsule containing the x pointer 
    PyObject * c_api_object = PyCapsule_New((void *)x, "turkey._X_C_API", NULL);

    // and add it to the module
    PyModule_AddObject(module, "_X_C_API", c_api_object);
}

然后,在要向python公开以使X指针返回的函数中,执行以下操作(在开始在上面的代码中引用它之前,必须执行此操作):

static PyObject* turkey_do_something(PyObject *self, PyObject *args) {    

    if(!PyArg_ParseTuple(args, ":turkey_do_something"))
        return NULL;

    // get the x pointer back from the capsule
    X * x = (X*)PyCapsule_Import("turkey._X_C_API", 0);    

    // call some fn on x 
    return Py_BuildValue("i", x->some_fn_that_returns_an_int());
}

这里的“turkey.\uxC\uAPI”只是一些附加类型检查的名称-在这里为你的应用程序输入一些有意义的名称。土耳其是一个演示模块的名字,我刚才编的。

现在假设,并且取决于如何导出turkey_do_something fn,当调用Py_InitModule()时,可以从python脚本中这样调用:

import turkey

print turkey.do_something()

检查这个:http://docs.python.org/2/c-api/arg.html了解如何格式化元组和这个。。http://docs.python.org/3.1/c-api/capsule.html胶囊上的doco

假设您想要一些向后兼容性,那么您需要使用PyCObjects: http://docs.python.org/c-api/cobject.html

如果只想使用python 3,可以使用PyCapsule: http://docs.python.org/c-api/capsule.html

基本上,PyCObject将不透明指针转换为PyObject,您可以在python中传递它,当您使用一个指针返回到C时,您可以将其展开并使用它。

Pycamples非常相似,只是它们增加了一些特性,主要是 允许您在胶囊中存储多个指针,因此它基本上是一个dict

在您的特定情况下,在添加指针时,您只需执行此操作(删除错误检查和销毁代码):

PyObject *pystate = PyCObject_FromVoidPtr(State, NULL);
PyObject *dict = PyModule_GetDict(module);
PyDict_SetItemString(dict, "CStateObject", pystate);

# To retrieve it from self (assuming that it is an object)
PyObject *pystate = PyObject_GetAttrString(self, "CStateObject");
State *state = (State *)PyCObject_AsVoidPtr(pystate);

相关问题 更多 >

    热门问题