Seite 1 von 1

Wrap C++-Klasse (Wie bringt man Py. deren Methoden bei?)

Verfasst: Mittwoch 1. Juni 2011, 15:42
von zippy84
Hallo,

bin gerade dabei mich in die C-API von Python einzuarbeiten. Ich möchte einen eigenen Typ erstellen, der aus einer vorhandenen C++-Klasse enstehen soll. Ich hab mir den Part mit den dem struct in der Dokumentation von Python 2.7 durchgelesen, weiß aber nicht so recht wie ich das auf eine Klasse anwenden soll. Besonders bei den nicht statischen Methoden der Klasse komme ich nicht weiter. Wie gibt man diese bei tp_methods im PyTypeObject an?

Könnte mir das bitte jemand von euch am nachstehenden Beispiel zeigen?

Code: Alles auswählen

#include <vector>

struct Pt { double x, y; };

class Test {
public:
  std::vector<Pt> pts;
  
  unsigned int addPt(double x, double y) {
    Pt pt;
    pt.x = x;
    pt.y = y;
    
    pts.push_back(pt);
  }
  
};

/*
 * im python hätte ichs gern so:
 * import Test
 * a = Test.Test()
 * a.add_pt(3.7, 2.9)
 * */

Re: Wrap C++-Klasse (Wie bringt man Py. deren Methoden bei?)

Verfasst: Mittwoch 1. Juni 2011, 15:47
von deets
@zippy84

Ich wuerde dir empfehlen, statt von Hand zu wrappen einen der verfuegbaren Generatoren zu verwenden. Ich persoenlich bevorzuge SIP bzw. in letzter Zeit habe ich auch mit Cython gute Erfahrungen gemacht. Das vereinfacht dir die Sache *sehr*.

Re: Wrap C++-Klasse (Wie bringt man Py. deren Methoden bei?)

Verfasst: Mittwoch 1. Juni 2011, 22:37
von zippy84
Ich habe mich nun mal an einem konkreteren Beispiel beschäftigt. Das hier ist dabei herausgekommen:

Code: Alles auswählen

#include <Python.h>
#include <vector>

struct Pt { double x, y; };

class PNL {
public:
  typedef std::vector<Pt> PolyType;
  std::vector<PolyType> polys;
  
  void addPoly(PolyType poly);
 
};

void PNL::addPoly(PolyType poly) {
  polys.push_back(poly);
}

static PyObject* add_poly(PNL *self, PyObject *args) {
  PyObject *ptsList;
  
  if(PyArg_ParseTuple(args, "O", &ptsList) < 0)
    return NULL;
  
  int ptNbr = PySequence_Length(ptsList);
  
  PNL::PolyType poly;
  
  for(unsigned int i = 0; i < ptNbr; i++) {
    PyObject *pt = PySequence_GetItem(ptsList, i);
    
    PyObject *x = PyTuple_GetItem(pt, 0);
    PyObject *y = PyTuple_GetItem(pt, 1);
    
    Pt point;
    point.x = PyFloat_AsDouble(x);
    point.y = PyFloat_AsDouble(y);
    
    poly.push_back(point);
    
  }
  
  self->addPoly(poly);
  
  Py_INCREF(Py_None);
  return Py_None;
}

static PyMethodDef PNLPyType_methods[] = {
  {"add_poly", (PyCFunction) add_poly, METH_VARARGS, "Adds a polygon."},
  {NULL}
};

static PyTypeObject PNLPyType = {
  PyObject_HEAD_INIT(NULL)
  0,
  "pnl.PNL",
  sizeof(PNL)
};

static PyMethodDef pnl_module_methods[] = {
  {NULL}
};

PyMODINIT_FUNC initpnl() {
  PNLPyType.tp_new = PyType_GenericNew;
  PNLPyType.tp_methods = PNLPyType_methods;
  PNLPyType.tp_doc = "The PNL type.";
  PNLPyType.tp_flags = Py_TPFLAGS_DEFAULT; 
  
  if(PyType_Ready(&PNLPyType) < 0)
    return;
  
  PyObject* pnl = Py_InitModule("pnl", pnl_module_methods);
  
  Py_INCREF(&PNLPyType);
  PyModule_AddObject(pnl, "PNL", (PyObject*) &PNLPyType);
}


int main(int argc, char *argv[]) {
  Py_SetProgramName(argv[0]);
  Py_Initialize();
  initpnl();
}
Ich kann es in Python importieren, jedoch erhalte ich ein Segmentation fault, wenn ich folgende ausführe:

Code: Alles auswählen

>>> a = pnl.PNL()
>>> a.add_poly(((7, 1), (2, 3)))
Irgendwas scheine ich vergessen zu haben, nur was?