📜  从 C 调用Python |设置 2

📅  最后修改于: 2022-05-13 01:55:01.225000             🧑  作者: Mango

从 C 调用Python |设置 2

先决条件:从 C 调用Python |设置 1

需要传入对现有Python可调用对象的引用才能使用此函数。要做到这一点,有很多方法,比如简单地编写 C 代码以从现有模块中提取符号或将可调用对象传递给扩展模块。

代码 #1:简单的嵌入示例

int main()
{
    PyObject * pow_func;
    double x;
    Py_Initialize();
      
    // Get a reference to the math.pow function
    pow_func = import_name("math", "pow");
      
    // Call it using our call_func() code 
    for (x = 0.0; x < 10.0; x += 0.1)
    {
        printf("% 0.2f % 0.2f\n", x, call_func(pow_func, x, 2.0));
    }
          
    Py_DECREF(pow_func);
    Py_Finalize();
    return 0;
}


要构建最后一个示例,需要编译 C 并链接到Python解释器。下面的片段显示了如何做到这一点(这可能需要在您的机器上进行一些摆弄):

代码#2:

all::
cc -g embed.c -I/usr/local/include/python3.3m \
-L /usr/local/lib/python3.3/config-3.3m -lpython3.3m

编译并运行生成的可执行文件会给出如下输出:

0.00 0.00
0.10 0.01
0.20 0.04
0.30 0.09
0.40 0.16
...


下面的代码给出了另一个示例,该示例显示了一个扩展函数,该函数接收可调用的参数和一些参数,并将它们传递给call_func()以进行测试。

代码#3:

/* Extension function for testing the C-Python callback */
  
PyObject * py_call_func(PyObject * self, PyObject * args)
{
    PyObject * func;
  
    double x, y, result;
    if (! PyArg_ParseTuple(args, "Odd", &func, &x, &y))
    {
        return NULL;
    }
    result = call_func(func, x, y);
    return Py_BuildValue("d", result);
}


代码#4:测试扩展函数

import work
  
def add(x, y):
    return x + y
  
work.call_func(add, 3, 4)

输出 :

7.0


至关重要的是,首先我们需要一个Python对象来表示要调用的可调用对象。这可以是函数、类、方法、内置方法或任何实现__call__()操作的东西。要验证它是否是可调用函数,请使用PyCallable_Check()

代码 #5:检查PyCallable_Check()函数

double call_func(PyObject *func, double x, double y)
{
    ...
    // Verify that func is a proper callable
    if (!PyCallable_Check(func))
    {
        fprintf(stderr, "call_func: expected a callable\n");
        goto fail;
    }
    ...


只需使用PyObject_Call()调用一个函数,为它提供可调用对象、一个参数元组和一个可选的关键字参数字典。

Py_BuildValue()可用于构建参数元组或字典。

代码#6:

double call_func(PyObject *func, double x, double y)
    {
        PyObject *args;
        PyObject *kwargs;
          
        /* Build arguments */
        args = Py_BuildValue("(dd)", x, y);
        kwargs = NULL;
        /* Call the function */
        result = PyObject_Call(func, args, kwargs);
        Py_DECREF(args);
        Py_XDECREF(kwargs);
         
          
        /* Check for Python exceptions (if any) */
        if (PyErr_Occurred())
        {
            PyErr_Print();
            goto fail;
        }
          
    fail:
        PyGILState_Release(state);
        abort();
          
    }