『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 ...
随机推荐
- TypeScript笔记
#安装typescript [1] npm install -g typescript #编译typescript tsc test.ts //会生成test.js文件 #泛型,即使用“类型变量”,函 ...
- scala-协变和逆变
class GaoJi class ZhongJi extends GaoJi //协变=========================== class Card[+T] val cgaoji = ...
- python练习题-day9
2.写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者. def dan_index(itter): li=[] for i in range(len(itte ...
- etree导入问题
原因:主要是lxml没有这个包的问题,需要安装下: 1.需要在https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml 下选择你和你对应的pycharm对应的版 ...
- (转)Docker容器的重启策略及docker run的--restart选项详解
1. Docker容器的重启策略 Docker容器的重启策略是面向生产环境的一个启动策略,在开发过程中可以忽略该策略. Docker容器的重启都是由Docker守护进程完成的,因此与守护进程息息相关. ...
- C#设计模式(6)——原型模式(Prototype Pattern)(转)
一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...
- deeplabv3+ demo测试图像分割
#!--*-- coding:utf-8 --*-- # Deeplab Demo import os import tarfile from matplotlib import gridspec i ...
- Eclipse集成scala插件
1.Eclipse中右击help,选择Eclipse Marketplace,搜索scala,一路点击安装,重启Eclipse. 2.新建工程,new->other->出现scala wi ...
- Treap仿set 模板
Treap仿set 模板 蓝书232 &代码: #include <cstdio> #include <bitset> #include <iostream> ...
- js高级---本地对象、内置对象、宿主对象
名词参考: 原生对象:也叫内部对象.本地对象.native object 内置对象:Build-in object 宿主对象:host object ECMA-262 定义: 原生对象:独立于宿主环境 ...