2016-12-22 4 views
0

면책 조항 : 다음 예제는 Python Cookbook (O'Reilly)에서 가져 왔습니다.Cython 확장 기능 작성 : Python에서 내부 구조체에 C 구조체를 액세스하는 방법?

의 내가 있다고 가정 해 봅시다 간단한 struct 다음 두 Point들 사이의 유클리드 거리를 계산하는 기능

typedef struct { 
    double x,y; 
} Point; 

:

extern double distance(Point* p1, Point* p2); 

을이 모든 공유 라이브러리의 일부 points라고 :

  • points.h - 헤더 파일
  • points.c - 소스 파일
  • libpoints.so - 라이브러리 파일 (IT에 대한 사이 썬 확장 링크)
  • 내가 ( pypoints.py라고합니다) 내 포장 파이썬 스크립트를 생성 한

:

#include "Python.h" 
#include "points.h" 


// Destructor for a Point instance 
static void del_Point(PyObject* obj) { 
    // ... 
} 

// Constructor for a Point instance 
static void py_Point(PyObject* obj) { 
    // ... 
} 

// Wrapper for the distance function 
static PyObject* py_distance(PyObject* self, PyObject* arg) { 
    // ... 
} 

// Method table 
static PyMethodDef PointsMethods[] = { 
    {"Point", py_Point, METH_VARARGS, "Constructor for a Point"}, 
    {"distance", py_distance, METH_VARARGS, "Calculate Euclidean distance between two Points"} 
} 

// Module description 
static struct PyModuleDef pointsmodule = { 
    PyModuleDef_HEAD_INIT, 
    "points", // Name of the module; use "import points" to use 
    "A module for working with points", // Doc string for the module 
    -1, 
    PointsMethods // Methods provided by the module 
} 

이것은 단지 예일뿐입니다. 위의 struct 및 기능에 대해서는 ctypes 또는 cffi을 쉽게 사용할 수 있지만 Cython 확장을 작성하는 방법을 배우고 싶습니다. setup.py은 여기에 필요하지 않으므로 게시 할 필요가 없습니다.

이제 당신이 볼 수있는 위의 생성자는 우리가

import points 

p1 = points.Point(1, 2) # Calls py_Point(...) 
p2 = points.Point(-3, 7) # Calls py_Point(...) 

dist = points.distance(p1, p2) 

그것은 잘 작동 할 수 있습니다. 그러나 실제로 구조의 Point 내부에 액세스하려면 어떻게해야합니까? 예를 들어 우리가 쉽게

을 할 수있는 C 코드 있도록 (우리는 C++ 용어를 사용하는 경우 우리는 모든 struct 회원 public이다 말할 수 있음) struct 내부에 직접 액세스 할 수 있습니다 알다시피 나는

print("p1(x: " + str(p1.x) + ", y: " + str(p1.y)) 

을 얼마나

Point p1 = {.x = 1., .y = 2.}; 
printf("p1(x: %f, y: %f)", p1.x, p1.y) 

getter 및 setter없이 Python 클래스 멤버 (self.x, self.y)에 액세스 할 수도 있습니다.

double x(Point* p); 
double y(Point* p); 

그러나 나는 방법의 표 안에 자신의 전화를 설명하기 위해 이러한 방법을 포장하는 방법을 확실하지 오전 :

나는 중간 단계의 역할 기능을 쓸 수 있습니다.

어떻게하면됩니까? 내가 Point 구조의 x을 얻기위한 간단한 p1.x을 갖고 싶습니다.

+0

'double x (Point * p);'는'Point'에 대한 포인터를 인수로 취하고'double'을 반환하는'x'라는 함수의 함수 선언입니다 - 그래서 당신은 랩 (및 쓰기). y 함수와 마찬가지로. – martineau

+0

'p1.x'와'p1.y' 표기법 Python을 사용하기 위해서,'Point'와 같은 클래스가 주어지면'x'라는 이름의 속성과'x'라는 속성을위한 속성을 만들 수 있습니다. y '. Cython에 속성을 구현할 수 있는지 확실하지 않습니다. – martineau

답변

1

처음에는이 질문에 대해 다소 혼란 스러웠습니다. Cython 콘텐츠가 없기 때문에 (혼란으로 인한 편집상의 혼란이있었습니다.)

Python cookbook uses Cython in a very odd way 나는 따르지 않는 것이 좋습니다. 어떤 이유로 Cython에서 전에 사용하지 않은 PyCapsules를 사용하려고합니다.

# tell Cython about what's in "points.h" 
# (this does match the cookbook version) 

cdef extern from "points.h" 
    ctypedef struct Point: 
     double x 
     double y 

    double distance(Point *, Point *) 

# Then we describe a class that has a Point member "pt" 
cdef class Py_Point: 
    cdef Point pt 

    def __init__(self,x,y): 
     self.pt.x = x 
     self.pt.y = y 

    # define properties in the normal Python way 
    @property 
    def x(self): 
     return self.pt.x 

    @x.setter 
    def x(self,val): 
     self.pt.x = val 

    @property 
    def y(self): 
     return self.pt.y 

    @y.setter 
    def y(self,val): 
     self.pt.y = val 

def py_distance(Py_Point a, Py_Point b): 
    return distance(&a.pt,&b.pt) # get addresses of the Point members 

그런 다음 컴파일 및 파이썬 요리 책에 공정성에

from whatever_your_module_is_called import * 

# create a couple of points 
pt1 = Py_Point(1.3,4.5) 
pt2 = Py_Point(1.5,0) 

print(pt1.x, pt1.y) # access the members 

print(py_distance(pt1,pt2)) # distance between the two 

그 다음 내가 무슨 짓을했는지 매우 유사 무언가를 두 번째 예제를 제공 파이썬에서 사용할 (수 있지만, Cython이 파이썬과 같은 접근 방식을 지원하지 않았던 때의 약간 더 오래된 특성 구문을 사용하여). 그래서 조금 더 읽으 셨다면이 질문이 필요 없을 것입니다. 그러나 Cython과 pycapsules을 섞어서 사용하지 마십시오. 이는 합리적인 해결책이 아니므로 왜 권장하는지 알 수 없습니다.