博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
『Python CoolBook』C扩展库_其六_从C语言中调用Python代码
阅读量:5757 次
发布时间:2019-06-18

本文共 3721 字,大约阅读时间需要 12 分钟。

一、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 >>>

 

转载地址:http://cbvkx.baihongyu.com/

你可能感兴趣的文章
iOS 高性能异构滚动视图构建方案 —— LazyScrollView
查看>>
Java 重载、重写、构造函数详解
查看>>
【Best Practice】基于阿里云数加·StreamCompute快速构建网站日志实时分析大屏
查看>>
【云栖大会】探索商业升级之路
查看>>
HybridDB实例新购指南
查看>>
C语言及程序设计提高例程-35 使用指针操作二维数组
查看>>
华大基因BGI Online的云计算实践
查看>>
排序高级之交换排序_冒泡排序
查看>>
Cocos2d-x3.2 Ease加速度
查看>>
[EntLib]关于SR.Strings的使用办法[加了下载地址]
查看>>
中小型网站架构分析及优化
查看>>
写shell的事情
查看>>
负载均衡之Haproxy配置详解(及httpd配置)
查看>>
标准与扩展ACL 、 命名ACL 、 总结和答疑
查看>>
查找恶意的TOR中继节点
查看>>
MAVEN 属性定义与使用
查看>>
shell高级视频答学生while循环问题
查看>>
使用@media实现IE hack的方法
查看>>
《11招玩转网络安全》之第一招:Docker For Docker
查看>>
hive_0.11中文用户手册
查看>>