python基础-C扩展

写python的c扩展简介
使用C/C++编写Python模块扩展
Python - 用C扩展编程
使用 C 或 C++ 扩展 Python

原因

  • 添加额外的非python功能。
  • 性能瓶颈的效率提升
  • 专有源代码保密

写扩展库的代码

Extest.c文件包含包含要扩展的C模块,包含fac()和reverse()函数。
并调试完bug。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int fac(int n)
{if (n<2) return 1;return n * fac(n-1);
}char * reverse(char *s)
{register char t, *p = s, *q = s+(strlen(s)-1);while(p<q){t = *p;*p++ = *q;*q-- = t;}return s;
}int test()
{char s[255];printf("4! == %d\n", fac(4));printf("8! == %d\n", fac(8));printf("12! == %d\n", fac(12));strcpy(s, "abcdef");printf("reversing 'abcdef', we get '%s'\n",reverse(s));strcpy(s, "madam");printf("reversing 'madam', we get '%s'\n",reverse(s));return 0;
}

包装代码

  • 包含python头文件
  • 为每个模块的每个函数增加一个Pyobject * Module_func()的包装函数
  • 为每个模块增加一个PyMethodDef ModuleMethods[]的数组
  • 增加木块初始化函数void initModule()

为想被Python环境访问的函数增加一个静态变量,函数的返回值类型为PyObject*,函数名前要加上模块名和一个下划线。比如Extest模块的fac函数,创建包装函数Extest_fac()。这样可以在python中import Extest,然后调用Extest.fac()。

包装函数就是把Python的值传递给C,然后调用C函数处理。当处理完成返回给python的时候,把函数的计算结果转换成python对象,返回给python。

从python到C的转换用PyArg_Parse*系列函数。从C转到python的时候,就用Py_BuildValue()函数。

PyArg_Parse系列函数用法跟C的sscanf 函数很像,接受一个字符串流,根据一个指定格式字符串进行解析,把结果放入到相应的指针所指的变量中。返回值为1表示解析成功,返回值为0表示失败。
Py_BuildValue的用法跟sprintf函数很像,把所有的参数按格式字符串所指定的格式转换成一个python对象。

函数描述
int PyArg_ParseTuple()把python传过来的参数转为C
int PyArg_ParseTupleAndKeywords()把python传过来的参数转为C,但是同时解析关键字参数
PyObject *Py_BuildValue()把C的数据转为python的一个对象或一组对象,然后返回

python和C数据转换的格式符号

format codepython typec type
sstrchar *
zstr/Nonechar * /NULL
iintint
llonglong
cstrchar
dfloatdouble
DcomplexPy_Complex *
O(any)PyObject *
SstrPyStringObject
// 包装函数
static PyObject * Extest_fac(PyObject * self, PyObject * args)
{int res;int num;PyObject * retval;res = PyArg_ParseTuple(args, "i", &num);if (!res){return NULL;}res = fac(num);retval = Py_BuildValue("i", res);return retval;
}static PyObject * Extest_doppel(PyObject *self, PyObject * args)
{char * orig_str;char * dupe_str;PyObject * retval;if(!PyArg_ParseTuple(args, "s", $orig_str)) return NULL;retval = Py_BuildValue("ss", orig_str, dupe_str=reverse(strdup(orig_str)));free(dupe_str);return retval;
}static PyObject * Extest_test(PyObject * self, PyObject *args)
{test();return Py_BuildValue("");
}

‘ss’格式让Py_BuildValue()函数生成了一个包含两个字符串的tuple。

C代码中注意内存泄露。复制字符串后在函数退出前要释放。
为每个模块增加PyMethodDef ModuleMethods[]数组
完成包装函数后,需要把函数列在某个地方,编译python解释器能够导入并调用。
这是个二维数组,里面每个数组包含一个函数,最后放一个NULL数组表示列表的结束。

// 模块的方法数组PyMethodDef ModuleMethods[]
//METH_VARARGS常量表示参数以tuple形式传入.如果使用PyArg_ParseTupleAndKeywords()函数解析命名
//参数需要使用METH_VARARGS与METH_KEYWORDS常量进行逻辑与运算。
static PyMethodDef ExtestMethods[]{{"fac", Extest_fac, METH_VARARGS},{"doppel", Extest_doppel, METH_VARARGS},{'test', Extest_test, METH_VARARGS}{NULL, NULL},
}

增加模块初始换函数void initModule()
调用Py_InitModule()函数,并把模块名和ModuleMethods[]数组的名字穿进去。

//增加模块初始化函数void initModule()
void initExtest()
{Py_InitModule("Extest", ExtestMethods);
}

编译

  • 创建setup.py
  • 通过运行setup.py来编译和连接代码
  • 从python中导入扩展模块

创建setup.py,编译主要由setup()函数完成。这个函数调用之前的所有代码。每个扩展模块需要一个Extension实例。
Extension(MOD,sources=['Extest.c'])
名字为模块名,sources参数是所有源代码的文件列表。
setup()函数第一个参数表示要编译哪些东西,一个列表列出要编译的对象。

from distutils.core import setup, ExtensionMOD = 'Extest'
setup(name=MOD, ext_modules=[Extension(MOD,sources=['Extest.c'])])

编译和连接代码
运行setup.py build命令可以开始编译我们的扩展了。

$python setup.py build 

导入和测试
扩展会被创建在运行setup.py脚本所在的目录下的build/lib.*目录下。可以切换到哪个目录中测试新木块,也可以使用命令安装到python中

$python setup.py install

然后就可以在python中导入和使用模块中的函数了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开源自己用python封装的一个Windows GUI(UI Automation)自动化工具,支持MFC,Windows Forms,WPF,Metro,Qt...

首先&#xff0c;大家可以看下这个链接 Windows GUI自动化测试技术的比较和展望 。 这篇文章介绍了Windows中GUI自动化的三种技术&#xff1a;Windows API, MSAA - Microsoft Active Accessibility, UIAutomation 用脚本语言AutoIT实现自动化就是第一种技术Windows API, 查找窗…

Exynos4412 Uboot 移植(六)—— 相关知识补充

Uboot版本&#xff1a;u-boot-2013.01 一、gd结构体的定义与使用 gd_t 和 bd_t 是u-boot中两个重要的数据结构&#xff0c;在初始化操作很多都要靠这两个数据结构来保存或传递。 gd_t 定义在/u-boot-2013.01/arch/arm/include/asm/global_data.h bd_t 定义在 ./include/asm-ar…

eclipse4.3.1标准版安装freemarker插件

一直用的是Myeclipse&#xff0c;它的好处就是所有的插件都是给你准备好了&#xff0c;不用费心去整太多&#xff0c;我有点喜欢倒腾&#xff0c;就是想用用eclipse. 今天去eclipse官网下载了一个eclipse&#xff0c;我现在下载的版本是4.3.1的&#xff0c;软件更新总是很快 这…

Exynos4412 Uboot 移植(五)—— Uboot 移植过程

Uboot 版本&#xff1a;u-boot-2013.01 开发板&#xff1a;FS_4412 平台&#xff08;Exynos4412,可以根据自己的板子修改&#xff0c;只要是4412的过程都是一样的&#xff09; 一、建立自己的平台 1、下载源码 我们可以在下面这个网站上下载最新的和以前任一版本的uboot ftp://…

编程练习

尽可能使字符串相等 给你两个长度相同的字符串&#xff0c;s 和 t。 将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销&#xff08;开销可能为 0&#xff09;&#xff0c;也就是两个字符的 ASCII 码值的差的绝对值。 用于变更字符串的最大预算是 maxCo…

apply()和call()的区别

之前做过这样的一道题就是问apply&#xff08;&#xff09;与call&#xff08;&#xff09;的区别。当时没能答出来&#xff0c;现在整理一下&#xff0c;希望以后有帮助。其实每个函数都包含两个非继承而来的方法&#xff1a;apply&#xff08;&#xff09;和call&#xff08;…

Nagios 安装及常见错误

一、实验环境监控服务器&#xff08;nagios服务器--192.168.1.100&#xff09;CentOS5.4 nagios-3.2.1 nagios-plugins-1.4.14 nrpe-2.12被监控客户端&#xff08;linux客户端--192.168.1.200&#xff09;CentOS5.4 nagios-plugins-1.4.14 nrpe-2.12二、nrpe插件1、nrpe插…

Exynos4412 Uboot 移植(四)—— Uboot引导内核过程分析

bootloader 要想启动内核&#xff0c;可以直接跳到内核的第一个指令处&#xff0c;即内核的起始地址&#xff0c;这样便可以完成内核的启动工作了。但是要想启动内核还需要满足一些条件&#xff0c;如下所示&#xff1a; 1、cpu 寄存器设置 * R0 0 * R1 机器类型 id …

Python QT5

Python QT5 简洁入门 Python3 搭建Qt5 环境 Python 使用QT5开发界面的一个demo开发过程的总结 Python GUI教程 PyQt5 Reference Guide

忘记 mysql 密码的取回方法

如果 MySQL 正在运行&#xff0c;首先杀之&#xff1a; killall -TERM mysqld(如果是windows,直接调出进程管理器,结束之) 以安全模式启动 MySQL &#xff1a;/usr/bin/safe_mysqld --skip-grant-tables & (windows 下 mysql安装所以盘/mysql/bin/safe_mysqld --skip-grant…

Exynos4412 Uboot 移植(三)—— Uboot添加自定义命令

Uboot添加自定义命令&#xff1a;uboot中的命令使用U_BOOT_CMD这个宏声明来注册进系统&#xff0c;链接脚本会把所有的cmd_tbl_t结构体放在相邻的地方。 UBoot版本&#xff1a;u-boot-2013.01 一、U-Boot命令的格式 即使是内核的启动&#xff0c;也是通过U-Boot命令来实现的。…

python调试

python常用的程序调试方法_Python调试的几种方式 python常用的程序调试方法_Python调试的几种方式 Python代码调试的几种方法总结 常用的 Python 调试工具 Python 程序如何高效地调试&#xff1f;

如何抓准问题?

博主推荐延展咨询高级顾问姬忠岩文章“横看成岭侧成峰&#xff0c;远近高低各不同”&#xff0c;同一个问题&#xff0c;角度不同结论就不同&#xff0c;一句古诗把这道理讲得淋漓尽致。无论是日常生活&#xff0c;还是企业管理&#xff0c;我们都会碰到各种各样的问题&#xf…

Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析

uboot启动流程分析如下&#xff1a; 第一阶段&#xff1a; a -- 设置cpu工作模式为SVC模式 b -- 关闭中断&#xff0c;mmu,cache v -- 关看门狗 d -- 初始化内存&#xff0c;串口 e -- 设置栈 f -- 代码自搬移 g -- 清bss h -- 跳c 第二阶段 a -- 初始化外设&#xff0c;进入超…

Linux内核学习四库全书

http://blog.csdn.net/21aspnet/article/details/6585602 关于内核学习我建议不要上来就读内核而是先了解内核的构成和特性&#xff0c;然后通过思考发现疑问这时再去读内核源码。即先了解概貌在读局部细节。而且内核分成好多部分&#xff0c;不要只是按照顺序去读&#xff0c;…

c多线程

C语言多线程&#xff0c;C11多线程完全攻略

Exynos4412 Uboot 移植(一)—— Uboot 编译流程分析

Uboot 所用版本 u-boot-2013.01 u-boot-2013.01 中有上千文件&#xff0c;要想了解对于某款开发板&#xff0c;使用哪些文件、哪些文件首先执行、可执行文件占用内存的情况&#xff0c;最好的方法就是阅读它的Makefile。 根据顶层Readme文件的说明&#xff1a; 可以知道如果使…

sqlserver2005仅当使用了列的列表,并且 IDENTITY_INSERT 为 ON 时,才能在表 'SendMealAddress'中为标识列指定显式值。...

ps con.prepareStatement("insert into SendMealAddress values(null,?,?,?,?)"); 表有一列是自增长的标识列&#xff0c;比如第一列是&#xff0c;需要使用这样的格式&#xff1a;ps con.prepareStatement("insert into SendMealAddress(UserId,Concrete…

ipython

使用IPython有哪些好处&#xff1f; IPython介绍 史上最详细、最完全的ipython使用教程&#xff0c;Python使用者必备&#xff01;——ipython系列之二 https://ipython.readthedocs.io/en/stable/ ipython的用法详解 IPython使用学习笔记 IPython Documentation 为什么要使用I…

Exynos4412 所用内存 —— DDR2

一、SDRAM 二、DDR 三、DDR2 四、DDR2的配置