【问题标题】:Passing a C pointer around with the Python/C API使用 Python/C API 传递 C 指针
【发布时间】:2012-01-16 05:15:56
【问题描述】:

我是 Python/C API 的新手...我正在尝试向我的 C 程序添加新功能,其中我可以将 python 嵌入其中并同时扩展功能,以便嵌入式解释器可以执行一个脚本将与作为我的 C 程序的一部分编写的扩展 python 模块进行交互。我的 C 程序没有全局变量。我想保持这种方式;同时为了将 C 功能暴露给 python,扩展的 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);
}

这是传递 State *ptr 的最干净的方法吗?我当然不认为需要将内部状态暴露给 python。我曾考虑过使用胶囊,但胶囊似乎并不打算支持这种行为。

提前致谢! V

【问题讨论】:

    标签: python python-c-api


    【解决方案1】:

    Capsules 基本上是 python 不透明的 void 指针,您可以传递或与模块关联。它们是解决您问题的“方法”。

    这是一个使用实例 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._X_C_API”只是一些添加类型检查的名称 - 在这里为您的应用添加一些有意义的名称。土耳其是我当时编的一个演示模块名称。

    现在假设,根据方式,您在调用 Py_InitModule() 时导出了 turkey_do_something fn,您可以从 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

    【讨论】:

      【解决方案2】:

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

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

      基本上,PyCObject 的东西将你的不透明指针转换成一个 PyObject,你可以在 python 中传递它,当你用一个返回 C 时,你可以打开它并使用它。

      PyCapsules 非常相似,只是它们添加了一些功能,主要是它们 允许您在 Capsule 中存储多个指针,因此它基本上是一个字典。

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

      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);
      

      【讨论】:

        猜你喜欢
        • 2020-01-19
        • 1970-01-01
        • 1970-01-01
        • 2012-02-05
        • 2015-02-11
        • 1970-01-01
        • 1970-01-01
        • 2013-04-03
        • 2011-06-25
        相关资源
        最近更新 更多