『Python CoolBook』C扩展库_其四_结构体操作与Capsule
一、Python生成C语言结构体
C语言中的结构体传给Python时会被封装为胶囊(Capsule),
我们想要一个如下结构体进行运算,则需要Python传入x、y两个浮点数,
typedef struct Point {
double x,y;
} Point;
然后对这两个浮点数解析后生成C中Point的结构体,如下,
/* Create a new Point object */
static PyObject *py_Point(PyObject *self, PyObject *args) { Point *p;
double x,y;
if (!PyArg_ParseTuple(args,"dd",&x,&y)) {
return NULL;
}
p = (Point *) malloc(sizeof(Point));
p->x = x;
p->y = y;
return PyPoint_FromPoint(p, 1);
}
上面最后一句将使用C中的结构体构建Python胶囊对象并返回给Python,
/* Destructor function for points */
static void del_Point(PyObject *obj) {
free(PyCapsule_GetPointer(obj,"Point"));
} static PyObject *PyPoint_FromPoint(Point *p, int must_free) {
/* 胶囊和C指针类似。在内部,它们获取一个通用指针和一个名称,可以使用
PyCapsule_New() 函数很容易的被创建。 另外,一个可选的析构函数能被
绑定到胶囊上,用来在胶囊对象被垃圾回收时释放底层的内存*/
return PyCapsule_New(p, "Point", must_free ? del_Point : NULL);
}
PyCapsule_New():从结构体创建胶囊
PyCapsule_GetPointer():提取胶囊中的指针,使用 PyCapsule_GetPointer() 函数并指定名称。 如果提供的名称和胶囊不匹配或其他错误出现,那么就会抛出异常并返回NULL。实际上就是从胶囊转换回结构体
效果如下,
>>> import sample
>>> p1 = sample.Point(2,3)
>>> p2 = sample.Point(4,5)
>>> p1
<capsule object "Point" at 0x1004ea330>
>>> p2
<capsule object "Point" at 0x1005d1db0>
总结
本节中,一对工具函数—— PyPoint_FromPoint() 和 PyPoint_AsPoint() 被用来创建和从胶囊对象中提取Point实例。 在任何扩展函数中,我们会使用这些函数而不是直接使用胶囊对象。 这种设计使得我们可以很容易的应对将来对Point底下的包装的更改。 例如,如果你决定使用另外一个胶囊了,那么只需要更改这两个函数即可。
对于胶囊对象一个难点在于垃圾回收和内存管理。 PyPoint_FromPoint() 函数接受一个 must_free 参数, 用来指定当胶囊被销毁时底层Point * 结构体是否应该被回收。 在某些C代码中,归属问题通常很难被处理(比如一个Point结构体被嵌入到一个被单独管理的大结构体中)。 程序员可以使用 extra 参数来控制,而不是单方面的决定垃圾回收。 要注意的是和现有胶囊有关的析构器能使用 PyCapsule_SetDestructor() 函数来更改。
二、Python中的C结构体传入C语言进行运算
/* Utility functions */
static Point *PyPoint_AsPoint(PyObject *obj) {
return (Point *) PyCapsule_GetPointer(obj, "Point");
} static PyObject *py_distance(PyObject *self, PyObject *args) {
Point *p1, *p2;
PyObject *py_p1, *py_p2;
double result; if (!PyArg_ParseTuple(args,"OO",&py_p1, &py_p2)) {
return NULL;
}
if (!(p1 = PyPoint_AsPoint(py_p1))) {
return NULL;
}
if (!(p2 = PyPoint_AsPoint(py_p2))) {
return NULL;
}
result = distance(p1,p2);
return Py_BuildValue("d", result);
}
将两个结构体转为C指针存储后,分别使用PyCapsule_GetPointer()提取指针信息转换为结构体,计算后返回。
>>> sample.distance(p1,p2)
2.8284271247461903
『Python CoolBook』C扩展库_其四_结构体操作与Capsule的更多相关文章
- 『Python CoolBook』C扩展库_其五_C语言层面Python库之间调用API
点击进入项目 一.C层面模块添加API 我们仍然操作如下结构体, #include <math.h> typedef struct Point { double x,y; } Point; ...
- 『Python CoolBook』C扩展库_其一_用法讲解
不依靠其他工具,直接使用Python的扩展API来编写一些简单的C扩展模块. 本篇参考PythonCookbook第15节和Python核心编程完成,值得注意的是,Python2.X和Python3. ...
- 『Python CoolBook』C扩展库_其三_简单数组操作
点击进入项目 这里的数组要点在于: 数组结构,array.array或者numpy.array 本篇的数组仅限一维,不过基础的C数组也是一维 一.分块讲解 源函数 /* Average values ...
- 『Python CoolBook』C扩展库_其六_线程
GIL操作 想让C扩展代码和Python解释器中的其他进程一起正确的执行, 那么你就需要去释放并重新获取全局解释器锁(GIL). 在Python接口封装中去释放并重新获取全局解释器锁(GIL),此时本 ...
- 『Python CoolBook』C扩展库_其二_demo演示
点击进入项目 C函数源文件 /* sample.c */ #include "sample.h" /* Compute the greatest common divisor */ ...
- 『Python CoolBook』C扩展库_其六_从C语言中调用Python代码
点击进入项目 一.C语言运行pyfun的PyObject对象 思路是在C语言中提供实参,传给python函数: 获取py函数对象(PyObject),函数参数(C类型) 获取GIL(PyGILStat ...
- 『Python CoolBook』使用ctypes访问C代码_下_demo进阶
点击进入项目 这一次我们尝试一下略微复杂的c程序. 一.C程序 头文件: #ifndef __SAMPLE_H__ #define __SAMPLE_H__ #include <math.h&g ...
- 『Python CoolBook』使用ctypes访问C代码_上_用法讲解
一.动态库文件生成 源文件hello.c #include "hello.h" #include <stdio.h> void hello(const char *na ...
- 『Python CoolBook』Cython
github地址 使用Cython导入库的话,需要一下几个文件: .c:C函数源码 .h:C函数头 .pxd:Cython函数头 .pyx:包装函数 setup.py:python 本节示例.c和.h ...
随机推荐
- Redis入门到高可用(十四)—— bitmap
一.初步认识 二.API 1.setbit 2.getbit 3.bitcount 4.bitop 5.bitpos 三.位图使用 四. 使用经验
- webstorm 配置 开发微信小程序
默认情况下,webstorm是不支持wxml和wxss的文件类型,不会有语法高亮 设置高亮 除了高亮,还需要代码提示, 所幸已经有前辈整理了小程序的代码片段,只需要导入其安装包即可使用,包文件路径如下 ...
- MySQL行转列与列转行
行转列 例如:把图1转换成图2结果展示 图1 图2 CREATE TABLE `TEST_TB_GRADE` ( `ID` ) NOT NULL AUTO_INCREMENT, `) DEFAULT ...
- python进阶之 线程编程
1.进程回顾 之前已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在于:程序是指令的集合,它是进程 ...
- Mysql导入表信息[Err] 1067 - Invalid default value for '字段名'
修改mysql配置文件 vi /etc/my.cnf //添加以下配置 sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISI ...
- 【JVM】-NO.116.JVM.1 -【JDK11 HashMap详解-5-红黑树】
Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...
- SpringBoot框架的使用
什么是SpringBoot Spring Boot是Spring社区发布的一个开源项目,旨在帮助开发者快速并且更简单的构建项目.大多数SpringBoot项目只需要很少的配置文件. SpringBoo ...
- HDU 2874 Connections between cities(LCA Tarjan)
Connections between cities [题目链接]Connections between cities [题目类型]LCA Tarjan &题意: 输入一个森林,总节点不超过N ...
- Java基础(变量数&常量&据类型&类型转换)
什么是变量: 变量就是一个不固定的数值,它随时会改变,就像银行卡里存的钱一样会变动. 变量的格式:1 数据类型 变量名=变量值: 2 数据类型 变量名: 变量名=变量值: 变量的三大要素:1变量 ...
- 爬虫出现Forbidden by robots.txt(转载 https://blog.csdn.net/zzk1995/article/details/51628205)
先说结论,关闭scrapy自带的ROBOTSTXT_OBEY功能,在setting找到这个变量,设置为False即可解决. 使用scrapy爬取淘宝页面的时候,在提交http请求时出现debug信息F ...