使用Python/C API传递C指针 [英] Passing a C pointer around with the Python/C API

查看:446
本文介绍了使用Python/C API传递C指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Python/C API的新手...我正在尝试向我的C程序添加新功能,其中我可以将python嵌入其中,同时扩展功能,以便嵌入式解释器可以执行一个脚本,该脚本可以将与作为C程序一部分编写的扩展python模块进行交互.我的C程序没有全局变量.我想这样保留事情;同时为了将C功能暴露给python,似乎扩展的C函数至少需要访问全局变量才能访问程序状态.我该如何解决?

I'm new to the Python/C API ... I'm trying to add new functionality to my C program, wherein I can embed python into it and simultaneously extend functionality so that the embedded interpreter can execute a script that will interact with an extending python module written as part of my C program. My C program doesn't have global variables. I would like to keep things this way; At the same time in order to expose C functionality to python, it appears the extending C function at least needs access to global variables to access state of the program. How do I get around this?

例如这是我计划嵌入从主调用PYINTERFACE_Initialize的地方的方式

e.g. Here is how I plan on embedding where PYINTERFACE_Initialize is called from main

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

这是通过国家* ptr的最干净的方法吗?我当然不认为需要将内部状态公开给python.我已经考虑过要使用胶囊,但这并不是胶囊支持这种行为的意图.

Is this the cleanest way to pass the State *ptr around? I certainly don't see the need to expose the internal state to python. I've thought about using capsules, but it doesn't seem to be the intention of capsules to support this sort of behaviour.

提前谢谢! V

推荐答案

胶囊基本上是python不透明的void指针,您可以传递这些指针或将其与模块关联.它们是解决您的问题的方式".

Capsules are basically python-opaque void pointers that you can pass around or associate with modules. They are "the way" to solve your problem.

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

Here's an example that uses an instance x that doesn't have to be static. First attach the pointer to your module something like this (error checking removed)...

// 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指针返回,您可以执行以下操作(在您在上面的代码中开始引用它之前,实际上必须这样做):

Then in the function you want to expose to python in order to get that X pointer back you do something like this (this actually has to go before you start referring to it in the code above):

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"只是用于进行一些附加类型检查的名称-在此处为您的应用添加一些有意义的名称.土耳其是我当时制作的一个演示模块名称.

Here "turkey._X_C_API" is just a name for some added type checking - put some meaningful name in here for your app. Turkey is a demo module name that I made up just then.

现在假设,并根据方式,在调用Py_InitModule()时已导出turkey_do_something fn,您可以从python脚本中这样调用:

Now assuming that, and depending on how, you've exported the turkey_do_something fn when calling Py_InitModule() you can call this like this from a python script:

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

Check this: http://docs.python.org/2/c-api/arg.html for how to format the tuples and this.. http://docs.python.org/3.1/c-api/capsule.html for the doco on capsules

这篇关于使用Python/C API传递C指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆