点击进入项目

一、C语言运行pyfun的PyObject对象

思路是在C语言中提供实参,传给python函数:

  • 获取py函数对象(PyObject),函数参数(C类型)
  • 获取GIL(PyGILState_Ensure)
  • 确保fun对象可调用
  • 参数转换为python对应类型(Py_BuildValue)
  • 调用python函数(PyObject_Call)
  • 确定调用无异常
  • 检查返回值
  • 释放GIL(PyGILState_Release)
  • 异常处理
#include "Python.h"

/* Execute func(x,y) in the Python interpreter.  The
arguments and return result of the function must
be Python floats */ double call_func(PyObject *func, double x, double y) {
PyObject *args;
PyObject *kwargs;
PyObject *result = 0;
double retval; /* Make sure we own the GIL */
PyGILState_STATE state = PyGILState_Ensure(); /* Verify that func is a proper callable */
/* 你必须先有一个表示你将要调用的Python可调用对象。 这可以是一个函数、
类、方法、内置方法或其他任意实现了 __call__() 操作的东西。 为了确
保是可调用的,可以像下面的代码这样利用 PyCallable_Check() 做检查 */
if (!PyCallable_Check(func)) {
fprintf(stderr,"call_func: expected a callable\n");
goto fail;
}
/* Build arguments */
/* 使用 Py_BuildValue()构建参数元组或字典 */
args = Py_BuildValue("(dd)", x, y);
kwargs = NULL; /* Call the function */
/* 使用 PyObject_Call(),传一个可调用对象给它、一个参数元组
和一个可选的关键字字典。
如果没有关键字参数,传递NULL */
result = PyObject_Call(func, args, kwargs);
/* 需要确保使用了 Py_DECREF() 或者 Py_XDECREF() 清理参数。
第二个函数相对安全点,因为它允许传递NULL指针(直接忽略它),
这也是为什么我们使用它来清理可选的关键字参数。 */
Py_DECREF(args);
Py_XDECREF(kwargs); /* Check for Python exceptions (if any) */
/* 调用万Python函数之后,用PyErr_Occurred() 函数检查是否
有异常发生 */
if (PyErr_Occurred()) {
PyErr_Print();
goto fail;
} /* Verify the result is a float object */
if (!PyFloat_Check(result)) {
fprintf(stderr,"call_func: callable didn't return a float\n");
goto fail;
} /* Create the return value */
retval = PyFloat_AsDouble(result);
Py_DECREF(result); /* Restore previous GIL state and return */
PyGILState_Release(state);
return retval; fail:
Py_XDECREF(result);
PyGILState_Release(state);
abort(); // Change to something more appropriate
}

要注意的是每一个 PyGILState_Ensure() 调用必须跟着一个匹配的 PyGILState_Release() 调用——即便有错误发生。 在这里,我们使用一个 goto 语句看上去是个可怕的设计, 但是实际上我们使用它来讲控制权转移给一个普通的exit块来执行相应的操作。 在 fail: 标签后面的代码和Python的 fianl: 块的用途是一样的。

二、使用模块名和方法名获取pyfun的PyObject对象

  • 获取模块名字符串,方法名字符串
  • 模块名转化为python的字符串类型(PyUnicode_FromString)
  • 模拟python的import行为(PyImport_Import),这是因为我们想经由python的逻辑获取函数
  • 由python的module获取方法(PyObject_GetAttrString),这个API获取方法使用的是C字符串
  • 返回方法,时python的对象类型
/* Load a symbol from a module */
PyObject *import_name(const char *modname, const char *symbol) {
PyObject *u_name, *module;
u_name = PyUnicode_FromString(modname);
module = PyImport_Import(u_name);
Py_DECREF(u_name);
return PyObject_GetAttrString(module, symbol);
}

三、C模拟Python运行

  • 初始化python环境(Py_Initialize)
  • 导入模块获取方法(见本文第二部分)为PyObject
  • 调用方法PyObject(见本文第一部分)
  • 结束python环境(Py_Finalize)
/* Simple embedding example */
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));
}
/* Done */
Py_DECREF(pow_func);
Py_Finalize();
return 0;
}

编译运行,

gcc -g embed.c -I/home/hellcat/anaconda3/include/python3.6m           -L/home/hellcat/anaconda3/lib/python3.6/config-3.6m-x86_64-linux-gnu -lpython3.6m

四、将可调用PyObject用C重新封装调用

这是个意义不大功能,只是展示C API中PyObject本质运行逻辑——PyObject可以代指任何Python中的对象,这里是它接收函数的例子:

/* Extension function for testing the C-Python callback */
static 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);
}

把它写到前一节中的pysample.c中,有如下效果

>>> import sample
>>> def add(x,y):
... return x+y
...
>>> sample.call_func(add,3,4)
7.0
>>>

『Python CoolBook』C扩展库_其六_从C语言中调用Python代码的更多相关文章

  1. 『Python CoolBook』C扩展库_其一_用法讲解

    不依靠其他工具,直接使用Python的扩展API来编写一些简单的C扩展模块. 本篇参考PythonCookbook第15节和Python核心编程完成,值得注意的是,Python2.X和Python3. ...

  2. 『Python CoolBook』C扩展库_其六_线程

    GIL操作 想让C扩展代码和Python解释器中的其他进程一起正确的执行, 那么你就需要去释放并重新获取全局解释器锁(GIL). 在Python接口封装中去释放并重新获取全局解释器锁(GIL),此时本 ...

  3. 『Python CoolBook』C扩展库_其四_结构体操作与Capsule

    点击进入项目 一.Python生成C语言结构体 C语言中的结构体传给Python时会被封装为胶囊(Capsule), 我们想要一个如下结构体进行运算,则需要Python传入x.y两个浮点数, type ...

  4. 『Python CoolBook』C扩展库_其三_简单数组操作

    点击进入项目 这里的数组要点在于: 数组结构,array.array或者numpy.array 本篇的数组仅限一维,不过基础的C数组也是一维 一.分块讲解 源函数 /* Average values ...

  5. 『Python CoolBook』C扩展库_其五_C语言层面Python库之间调用API

    点击进入项目 一.C层面模块添加API 我们仍然操作如下结构体, #include <math.h> typedef struct Point { double x,y; } Point; ...

  6. 『Python CoolBook』C扩展库_其二_demo演示

    点击进入项目 C函数源文件 /* sample.c */ #include "sample.h" /* Compute the greatest common divisor */ ...

  7. 『Python CoolBook』Cython

    github地址 使用Cython导入库的话,需要一下几个文件: .c:C函数源码 .h:C函数头 .pxd:Cython函数头 .pyx:包装函数 setup.py:python 本节示例.c和.h ...

  8. 在Java中调用Python

    写在前面 在微服务架构大行其道的今天,对于将程序进行嵌套调用的做法其实并不可取,甚至显得有些愚蠢.当然,之所以要面对这个问题,或许是因为一些历史原因,或者仅仅是为了简单.恰好我在项目中就遇到了这个问题 ...

  9. C#中调用python方法

    最近因为项目设计,有部分使用Python脚本,因此代码中需要调用python方法. 1.首先,在c#中调用python必须安装IronPython,在 http://ironpython.codepl ...

随机推荐

  1. nginx基本用法和HTTPS配置

    nginx作用讲解:1.反向代理:需要多个程序共享80端口的时候就需要用到反向代理,nginx是反向代理的一种实现方式.2.静态资源管理:一般使用nginx做反向代理的同时,应该把静态资源交由ngin ...

  2. Centos7+python3.6+face-recognition

    Step1 安装Python3.6.xhttps://www.digitalocean.com/community/tutorials/how-to-install-python-3-and-set- ...

  3. CSS样式中文字的换行

    在我们做输出时可能会遇到这样一个问题,就是汉字和英文字母相遇,然后自动换行的问题.例如,当我在输出产品标题时,由于产品名称比较长,包括汉字和英文字母,FF下浏览是正常的,而IE下面 英文会出现换行.当 ...

  4. node 七牛云图片上传

    后端代码 //https://portal.qiniu.com/user/key var accessKey = '-xxx-QvPiZzXYWY9AuytTjgix'; var secretKey ...

  5. C#设计模式(11)——外观模式(Facade Pattern)(转)

    一.引言 在软件开发过程中,客户端程序经常会与复杂系统的内部子系统进行耦合,从而导致客户端程序随着子系统的变化而变化,然而为了将复杂系统的内部子系统与客户端之间的依赖解耦,从而就有了外观模式,也称作 ...

  6. fiddler学习总结--通过Fiddler模拟弱网进行测试

    弱网测试的目的: 弱网测试可以发现一些因为网络问题导致的交互问题,从而更好的完善应用的性能. 关注点:1.卡死,崩溃,无响应,闪退.2.业务交互数据传输正确性. 通过Fiddler可以模拟弱网进行测试 ...

  7. JAVA 多线程之volatile的介绍

    volatile的介绍 volatile的主要作用是:提示编译器该对象的值有可能在编译器未监测的情况下被改变. volatile类似于大家所熟知的const也是一个类型修饰符.volatile是给编译 ...

  8. Python- 解决PIP下载安装速度慢

    让PIP源使用国内镜像,提升下载速度和安装成功率. 国外的源下载速度太慢,而且经常出现下载后安装出错问题.把PIP安装源替换成国内镜像,可以大幅提升下载速度,还可以提高安装成功率. 国内源: 新版ub ...

  9. Hdu2602 Bone Collector (01背包)

    Problem Description Many years ago , in Teddy’s hometown there was a man who was called “Bone Collec ...

  10. 数据库oracle 目录结构

    Oracle_Home主目录位于D:\dev\oracle\product\10.2.0(oracle安装路径)下,它包含Oracle软件运行有关的子目录和网络文件以及选定的组件等:若在主机上第一次且 ...