[转载] 扩展Python之在Python中调用C编写的函数模块
参考链接: 如何在Python中调用C函数
目录
编写Python扩展1. 创建应用代码2. 根据样板编写封装代码2.1 包含Python头文件2.2 为每一个模块函数添加形如PyObject* *Module_func()* 的封装函数2.3 为每一个模块函数添加一个PyMethodDef *ModuleMethods[]* 数组/表2.4 添加模块初始化函数
3 编译并测试3.1 创建 setup.py3.2 运行 setup.py 来编译并链接代码3.3 在Python中导入模块3.4 测试函数
4. 文档扩展4.1 在2.2中出现的 `int PyArg_ParseTuple(PyObject *arg, const char *format, ...);` 函数Python和C/C++之间的“转换编码”取自文档的例子:文档1.7部分
4.2 在3.1中创建的`setup.py` 。
编写Python扩展
1. 创建应用代码
编写一个比较简单的函数,求阶乘。并且写上main函数进行测试。 编译测试
$ gcc Extest1.c -o Extest
$ ./Extest
4! = 24
2. 根据样板编写封装代码
先给个文档地址:Extending Python with C or C++
2.1 包含Python头文件
在大多数类UNIX系统上,Python包含文件一般位于/usr/local/include/python2.x 或者 /usr/include/python2.x 中。我的系统是ubuntu 18.04 LTS。没有python2,系统自动安装的只有python3。我的位于 /usr/include/python3.6 中 将Python.h 这个头文件包含在源码中
#include "Python.h"
这边之后编译这个文件时可能会出现错误 fatal error: Python.h: No such file or directory compilation terminated. 。 stack overflow上的解决方案
sudo apt-get install python3-dev
2.2 为每一个模块函数添加形如PyObject* Module_func() 的封装函数
对于每个需要在Python环境中访问的函数,需要创建一个以static PyObjuec* 标识,以模块名开头,紧接着是下划线和函数名本身的函数。例如,若要让 fac() 函数可以在Python中导入,并将Extest 作为最终的模块名称,需要创建一个名为Extest_fac 的封装函数。在用到这个函数的Python脚本中,可以使用import Extest 和 Extest.fac() 的形式在任意地方调用fac() 函数。封装函数的任务是将Python中的值转成C形式,接着调用相应的函数。当C函数执行完毕时,需要返回Python的环境中。封装函数需要将返回值转换成Python形式,并进行真正的返回,传回所有需要的值。
2.3 为每一个模块函数添加一个PyMethodDef ModuleMethods[] 数组/表
这边书里《Python核心编程》和文档稍微有点出入,书里是3个参数,文档是4个参数,但是文档没有写第4个参数是什么,所以这边先按书里写的。
2.4 添加模块初始化函数
书里是这么写的,我怀疑是python2和3的区别,所以这里书里的不太对,我这边在后面的运行中会出现问题,所以这里稍微改一下。用文档的内容。 文档里的初始化格式:
3 编译并测试
3.1 创建 setup.py
3.2 运行 setup.py 来编译并链接代码
运行该命令构建扩展
python3 setup.py build
Error 1: 找不到python.h。解决方案见上Error 2: 用书里的函数会显示没有initModule这个函数。解决方案见上Error 3: 显示找不到distutils 模块No module named 'distutils.core'。解决方案
sudo apt-get install python3-distutils
3.3 在Python中导入模块
扩展模块会创建在build/lib.*目录下,即运行setup.py脚本的位置。要么切换到这么目录中,要么用下面的方式将气安装到Python中。
$ python3 setup.py install
Error 这里有了问题,注意最后一行Permission denied ,所以这里用 sudo python3 setup.py install 就可以了。
3.4 测试函数
4. 文档扩展
4.1 在2.2中出现的 int PyArg_ParseTuple(PyObject *arg, const char *format, ...); 函数
函数文档 1.7在fac()的示例中,当客户程序调用Extest.fac()时,会调用封装函数。这里会接受一个Python整数,将其转换成C整数,接着调用C函数fac(),获取返回结果,同样是一个整数。将这个返回值转换成Python整数,返回给调用者(记住,编写的封装函数就是def fac(n)声明的代理函数。当这个封装函数返回时,就相当于Python fac()函数执行完毕了)。如何完成转换?Python -> C : PyArg_Parse*(). C->Python : Py_BuildValue()PyArg_Parse*() : 类似于C中的sscanf 函数。接受一个字节流,然后根据一些格式字符串进行解析,将结果放入到相应指针所指的变量中。若解析成功就返回1;否则返回0.Py_BuildValue() :类似于 sprintf 函数,接受一个格式字符串,并将所有参数按照格式字符串指定的格式转换成一个Python 对象。
Python和C/C++之间的“转换编码”
格式编码Python数据类型C/C++数据类型s, s#str/unicode, len()char*, intiintintbintcharcstrchardfloatdoublehintshortlintlong
取自文档的例子:文档1.7部分
#include "Python.h"
int ok;
int i, j;
long k, l;
const char *s;
Py_ssize_t size;
ok = PyArg_ParseTuple(args, ""); /* No arguments */
/* Python call: f() */
ok = PyArg_ParseTuple(args, "s", &s); /* A string */
/* Possible Python call: f('whoops!') */
ok = PyArg_ParseTuple(args, "lls", &k, &l, &s); /* Two longs and a string */
/* Possible Python call: f(1, 2, 'three') */
ok = PyArg_ParseTuple(args, "(ii)s#", &i, &j, &s, &size);
/* A pair of ints and a string, whose size is also returned */
/* Possible Python call: f((1, 2), 'three') */
{
const char *file;
const char *mode = "r";
int bufsize = 0;
ok = PyArg_ParseTuple(args, "s|si", &file, &mode, &bufsize);
/* A string, and optionally another string and an integer */
/* Possible Python calls:
f('spam')
f('spam', 'w')
f('spam', 'wb', 100000) */
}
{
int left, top, right, bottom, h, v;
ok = PyArg_ParseTuple(args, "((ii)(ii))(ii)",
&left, &top, &right, &bottom, &h, &v);
/* A rectangle and a point */
/* Possible Python call:
f(((0, 0), (400, 300)), (10, 10)) */
}
4.2 在3.1中创建的setup.py 。
官方文档在这里Writing the Setup Script
参考书籍: 《Python核心编程》Unit8 百度网盘链接:https://pan.baidu.com/s/1XYSY65_BuQkEHm-LFzzi3g 提取码:awqc 《Python3文档》https://docs.python.org/3/ 这篇文章主要需要用到的文档内容上面已经给了
[转载] 扩展Python之在Python中调用C编写的函数模块相关推荐
- python 在一个py文件中调用另一个py文件中的变量以及一个有趣的问题
python 在一个py文件中调用另一个py文件中的变量以及一个有趣的问题 1.在一个py文件中调用另一个py文件中的变量 新建一个py文件,记为t1.py # t1.py m = 2 n = 1 a ...
- Python如何在main中调用函数内的函数
Python如何在main中调用函数内的函数 一般在Python中在函数中定义的函数是不能直接调用的,但是如果要用的话怎么办呢? 一般情况下: def a():#第一层函数def b():#第二层函数 ...
- java怎么调用存储函数_java中调用存储过程或存储函数的方法
java中调用存储过程或存储函数的方法 1.调用存储过程:CallableStatement clstmt = null;try {clstmt = conn.prepareCall("{c ...
- java 执行oracle 存储过程_oracle--在java中调用存储过程和存储函数
在java中调用存储过程和存储函数 存储过程: 查询某个员工的姓名 月薪 职位: create or replace procedure queryempinfo(eno in number, pen ...
- python configure函数 循环_使用python统计git仓库中频繁修改的热点函数
本篇博客以开源代码RT-Thread为例,描述了如何使用python扫描统计代码中频繁修改的函数,帮助我们发现系统中需求变化和BUG制造的重灾区. 需求背景 最近在学习设计模式时,印象深刻的一句话就是 ...
- 在全局中调用类的静态成员函数
在全局中直接调用类的静态成函数会产生重复声明错误. 例如: FooClass::FooStaticFunction(); 如果在全局中间接调用类的静态成员函数则不会产生错误,但是会产生多余的全局变量. ...
- vs2013 c# 中调用 c 编写的dll出错的可能错误
先说出错原因: 堆栈调用顺序 解决办法: 使用 __stdcall 或 使用C#属性 CallingConvention 起因是我想在c#中调用c函数结果出错了 如下 C 头文件 ...
- 在一个PHP中调用另一个php函数,php调用函数 php如何调用函数?
php如何调用函数? 1.递推 2.回归递推: 递推为正向的推导,即从前向后的分析问题,寻找递推的条件. 1-3求和为例 sum(1) = 1 0 sum(2) = 2 1 sum(3) = 3 2 ...
- 如何在matlab sfunction 函数中调用自己写的函数?
自己编写了一个s函数,有几个参数引用了自己写的几个函数,在脚本中可以正确运行,但在写成s函数,进行 simulink 仿真的时候,已知提示"too many input auguments& ...
最新文章
- 一个简单的PHP模板引擎
- Python matplotlib中文显示异常,导入simhei字体有误
- 【渝粤教育】广东开放大学 土木工程材料 形成性考核 (22)
- VS.NET提示试图运行项目时出错:无法启动调试。绑定句柄无效解决办法
- 多表关联查询_【函数007】 EXCEL多表关联查询实战
- MySQL事务处理特性的实现原理
- 十进制数怎样转成十六进制数
- codevs 1683 车厢重组
- 【转】解密微软的架构师之路
- tiledmap 图块属性_TiledMap 组件参考
- mac 重装 mysql
- 手把手学习Vue3.0:CSS样式基础和HTML5基础收藏
- 工作中的Linux防火墙心得
- 特斯拉 开源_开源与癌症作斗争,特斯拉采用Coreboot,Uber和Lyft发行开源机器学习...
- axis调用webservice不同参数的方法
- 漫谈OCL概念、特征和实践(作者:大雁北飞)
- IE和Firefox浏览器CSS网页布局不同点
- Excel怎么设置密码保护工作表
- android 手机文件及文件夹目录详解
- 第9章第9节:完成过渡页幻灯片版式的制作 [PowerPoint精美幻灯片实战教程]
热门文章
- NYOJ1 - A+B Problem
- html实现在线新闻浏览器,使用JQuery Mobile实现手机新闻浏览器
- JavaScript的String对象使用
- Go语言基础进阶—程序结构—包和文件
- CTF之Web安全训练前篇1
- 圆方树(bzoj 2125: 最短路)
- 牛客网暑期ACM多校训练营(第三场): A. Ternary String(欧拉降幂+递推)
- 牛客网暑期ACM多校训练营(第三场): E. Sort String(KMP)
- Mysql用户权限管理:Grank和Revoke
- 运算符重载的非成员函数形式