『Python CoolBook』C扩展库_其四_结构体操做与Capsule

点击进入项目git

1、Python生成C语言结构体

C语言中的结构体传给Python时会被封装为胶囊(Capsule),程序员

咱们想要一个以下结构体进行运算,则须要Python传入x、y两个浮点数,github

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():从结构体建立胶囊ui

PyCapsule_GetPointer():提取胶囊中的指针,使用 PyCapsule_GetPointer() 函数并指定名称。 若是提供的名称和胶囊不匹配或其余错误出现,那么就会抛出异常并返回NULL。实际上就是从胶囊转换回结构体spa

效果以下,设计

>>> 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底下的包装的更改。 例如,若是你决定使用另一个胶囊了,那么只须要更改这两个函数便可。3d

对于胶囊对象一个难点在于垃圾回收和内存管理。 PyPoint_FromPoint() 函数接受一个 must_free 参数, 用来指定当胶囊被销毁时底层Point * 结构体是否应该被回收。 在某些C代码中,归属问题一般很难被处理(好比一个Point结构体被嵌入到一个被单独管理的大结构体中)。 程序员能够使用 extra 参数来控制,而不是单方面的决定垃圾回收。 要注意的是和现有胶囊有关的析构器能使用 PyCapsule_SetDestructor() 函数来更改。指针

2、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
相关文章
相关标签/搜索