2010-05-17 7 views
18

Python'u C ile başarıyla genişletdim, this handy skeleton module sayesinde. Ama C++ için bir tane bulamıyorum ve bu iskelet modülünü derlediğimde C++'nın verdiği hataları düzeltmeye çalışırken döngüsel bağımlılık sorunum var.Python'u C++ ile nasıl genişletirsiniz?

Python'u C++ ile nasıl genişletirsiniz? Gerekmiyorsa Boost'a (veya SWIP veya diğer kütüphanelere) güvenmemeyi tercih ederim. Bağımlılıklar popoda bir acıdır. En iyi senaryo, zaten C++ ile derleyen bir iskelet dosyası buluyorum. İşte

C++ için yaptık düzenlenmiş iskelet:

#include <Python.h> 

#include "Flp.h" 

static PyObject * ErrorObject; 

typedef struct { 
    PyObject_HEAD 
    PyObject * x_attr; // attributes dictionary 
} FlpObject; 

static void Flp_dealloc(FlpObject * self); 
static PyObject * Flp_getattr(FlpObject * self, char * name); 
static int Flp_setattr(FlpObject * self, char * name, PyObject * v); 
DL_EXPORT(void) initflp(); 

static PyTypeObject Flp_Type = { 
    /* The ob_type field must be initialized in the module init function 
    * to be portable to Windows without using C++. */ 
    PyObject_HEAD_INIT(NULL) 
    0,   /*ob_size*/ 
    "Flp",   /*tp_name*/ 
    sizeof(FlpObject), /*tp_basicsize*/ 
    0,   /*tp_itemsize*/ 
    /* methods */ 
    (destructor)Flp_dealloc, /*tp_dealloc*/ 
    0,   /*tp_print*/ 
    (getattrfunc)Flp_getattr, /*tp_getattr*/ 
    (setattrfunc)Flp_setattr, /*tp_setattr*/ 
    0,   /*tp_compare*/ 
    0,   /*tp_repr*/ 
    0,   /*tp_as_number*/ 
    0,   /*tp_as_sequence*/ 
    0,   /*tp_as_mapping*/ 
    0,   /*tp_hash*/ 
}; 

#define FlpObject_Check(v) ((v)->ob_type == &Flp_Type) 

static FlpObject * newFlpObject(PyObject * arg) 
{ 
    FlpObject * self; 
    self = PyObject_NEW(FlpObject, &Flp_Type); 
    if (self == NULL) 
     return NULL; 
    self->x_attr = NULL; 
    return self; 
} 

// Flp methods 

static void Flp_dealloc(FlpObject * self) 
{ 
    Py_XDECREF(self->x_attr); 
    PyMem_DEL(self); 
} 

static PyObject * Flp_demo(FlpObject * self, PyObject * args) 
{ 
    if (! PyArg_ParseTuple(args, "")) 
     return NULL; 
    Py_INCREF(Py_None); 
    return Py_None; 
} 

static PyMethodDef Flp_methods[] = { 
    {"demo", (PyCFunction)Flp_demo, 1}, 
    {NULL,  NULL} // sentinel 
}; 

static PyObject * Flp_getattr(FlpObject * self, char * name) 
{ 
    if (self->x_attr != NULL) { 
     PyObject * v = PyDict_GetItemString(self->x_attr, name); 
     if (v != NULL) { 
      Py_INCREF(v); 
      return v; 
     } 
    } 
    return Py_FindMethod(Flp_methods, (PyObject *)self, name); 
} 

static int Flp_setattr(FlpObject * self, char * name, PyObject * v) 
{ 
    if (self->x_attr == NULL) { 
     self->x_attr = PyDict_New(); 
     if (self->x_attr == NULL) 
      return -1; 
    } 
    if (v == NULL) { 
     int rv = PyDict_DelItemString(self->x_attr, name); 
     if (rv < 0) 
      PyErr_SetString(PyExc_AttributeError, 
        "delete non-existing Flp attribute"); 
     return rv; 
    } 
    else 
     return PyDict_SetItemString(self->x_attr, name, v); 
} 
/* --------------------------------------------------------------------- */ 

/* Function of two integers returning integer */ 

static PyObject * flp_foo(PyObject * self, PyObject * args) 
{ 
    long i, j; 
    long res; 
    if (!PyArg_ParseTuple(args, "ll", &i, &j)) 
     return NULL; 
    res = i+j; /* flpX Do something here */ 
    return PyInt_FromLong(res); 
} 


/* Function of no arguments returning new Flp object */ 

static PyObject * flp_new(PyObject * self, PyObject * args) 
{ 
    FlpObject *rv; 

    if (!PyArg_ParseTuple(args, "")) 
     return NULL; 
    rv = newFlpObject(args); 
    if (rv == NULL) 
     return NULL; 
    return (PyObject *)rv; 
} 

/* Example with subtle bug from extensions manual ("Thin Ice"). */ 

static PyObject * flp_bug(PyObject * self, PyObject * args) 
{ 
    PyObject *list, *item; 

    if (!PyArg_ParseTuple(args, "O", &list)) 
     return NULL; 

    item = PyList_GetItem(list, 0); 
    /* Py_INCREF(item); */ 
    PyList_SetItem(list, 1, PyInt_FromLong(0L)); 
    PyObject_Print(item, stdout, 0); 
    printf("\n"); 
    /* Py_DECREF(item); */ 

    Py_INCREF(Py_None); 
    return Py_None; 
} 

/* Test bad format character */ 

static PyObject * flp_roj(PyObject * self, PyObject * args) 
{ 
    PyObject *a; 
    long b; 
    if (!PyArg_ParseTuple(args, "O#", &a, &b)) 
     return NULL; 
    Py_INCREF(Py_None); 
    return Py_None; 
} 


/* List of functions defined in the module */ 

static PyMethodDef flp_methods[] = { 
    {"roj",  flp_roj,  1}, 
    {"foo",  flp_foo,  1}, 
    {"new",  flp_new,  1}, 
    {"bug",  flp_bug,  1}, 
    {NULL,  NULL}  /* sentinel */ 
}; 


/* Initialization function for the module (*must* be called initflp) */ 

DL_EXPORT(void) initflp() 
{ 
    PyObject *m, *d; 

    /* Initialize the type of the new type object here; doing it here 
    * is required for portability to Windows without requiring C++. */ 
    Flp_Type.ob_type = &PyType_Type; 

    /* Create the module and add the functions */ 
    m = Py_InitModule("flp", flp_methods); 

    /* Add some symbolic constants to the module */ 
    d = PyModule_GetDict(m); 
    ErrorObject = PyErr_NewException("flp.error", NULL, NULL); 
    PyDict_SetItemString(d, "error", ErrorObject); 
} 

Bu, benim için iyi derler ama ben test ettiğinde:

$ python 
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import flp 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ImportError: dynamic module does not define init function (initflp) 
>>> 
+2

Belki de C++ ile hangi hataları aldığınızı söyleyebiliriz - çözüm, bazı mantıklı yerleştirilmiş "extern" C "gibi basit olabilir. –

+0

Bu iyi bir fikir. – andrewrk

+0

SWIG, bunun için tasarlanmamış mı? – rossipedia

cevap

13

Her şeyden önce, ek bir bağımlılık getirmek istemiyor olsanız bile, PyCXX'a bir göz atmanızı öneriyorum. Web sayfasını alıntılayarak:

CXX/Object, Python uzantılarını yazmayı kolaylaştırmak için bir C++ kümesidir. PyCXX'in Python eklentilerini yazmayı kolaylaştırdığı en önemli yol, programınızın referans sayım hatası yapma olasılığını büyük ölçüde artırması ve Python C API'sinden hata iadelerini sürekli olarak kontrol etmek zorunda kalmamalarıdır. Cxx/Nesneler bu yolla C++ ile Python entegre:

  • C++ istisna işleme hatalarını tespit etmek ve temizlemek için dayanıyordu edilir. Karmaşık bir işlevde, bu, C dilinde yazılırken genellikle çok büyük bir sorundur. PyCXX ile, derleyicinin, bir hata oluştuğunda hangi nesnelere müdahale edilmesi gerektiğini izlemesine izin veririz.
  • Standart Şablon Kütüphanesi (STL) ve birçok algoritması, listeler ve takma adlar gibi Python kapsayıcılar ile takılıp oynatılır.
  • İsteğe bağlı CXX/Extensions özelliği, becerikli C tablolarını, modüllerinizi ve uzantı nesnelerini tanımlayan nesne ve yöntem çağrıları ile değiştirmenize izin verir.

Ben PyCXX Uzantınızın benzer bir lisansı altında çıkacak eğer sadece de Uzantınızın dağıtılan tarball PyCXX tüm kaynak kodunu dahil anlamına gelir BSD lisansı altında lisanslanmıştır düşünüyorum .

gerçekten ve kesinlikle PyCXX veya başka bir üçüncü taraf kitaplığından bağlıdır istemiyorsanız

, ben sadece adı bozma önlemek için extern "C" { ve } Python yorumlayıcısı tarafından çağrılır wrap işlevlerine var. piton gelen denilen olsun tüm işlev isimlerini sarmak için

#include <Python.h> 

#include "Flp.h" 

static PyObject * ErrorObject; 

typedef struct { 
    PyObject_HEAD 
    PyObject * x_attr; // attributes dictionary 
} FlpObject; 

extern "C" { 
    static void Flp_dealloc(FlpObject * self); 
    static PyObject * Flp_getattr(FlpObject * self, char * name); 
    static int Flp_setattr(FlpObject * self, char * name, PyObject * v); 
    DL_EXPORT(void) initflp(); 
} 

static PyTypeObject Flp_Type = { 
    /* The ob_type field must be initialized in the module init function 
    * to be portable to Windows without using C++. */ 
    PyObject_HEAD_INIT(NULL) 
    0,   /*ob_size*/ 
    "Flp",   /*tp_name*/ 
    sizeof(FlpObject), /*tp_basicsize*/ 
    0,   /*tp_itemsize*/ 
    /* methods */ 
    (destructor)Flp_dealloc, /*tp_dealloc*/ 
    0,   /*tp_print*/ 
    (getattrfunc)Flp_getattr, /*tp_getattr*/ 
    (setattrfunc)Flp_setattr, /*tp_setattr*/ 
    0,   /*tp_compare*/ 
    0,   /*tp_repr*/ 
    0,   /*tp_as_number*/ 
    0,   /*tp_as_sequence*/ 
    0,   /*tp_as_mapping*/ 
    0,   /*tp_hash*/ 
}; 

#define FlpObject_Check(v) ((v)->ob_type == &Flp_Type) 

static FlpObject * newFlpObject(PyObject * arg) 
{ 
    FlpObject * self; 
    self = PyObject_NEW(FlpObject, &Flp_Type); 
    if (self == NULL) 
     return NULL; 
    self->x_attr = NULL; 
    return self; 
} 

// Flp methods 

static void Flp_dealloc(FlpObject * self) 
{ 
    Py_XDECREF(self->x_attr); 
    PyMem_DEL(self); 
} 

static PyObject * Flp_demo(FlpObject * self, PyObject * args) 
{ 
    if (! PyArg_ParseTuple(args, "")) 
     return NULL; 
    Py_INCREF(Py_None); 
    return Py_None; 
} 

static PyMethodDef Flp_methods[] = { 
    {"demo", (PyCFunction)Flp_demo, 1}, 
    {NULL,  NULL} // sentinel 
}; 

static PyObject * Flp_getattr(FlpObject * self, char * name) 
{ 
    if (self->x_attr != NULL) { 
     PyObject * v = PyDict_GetItemString(self->x_attr, name); 
     if (v != NULL) { 
      Py_INCREF(v); 
      return v; 
     } 
    } 
    return Py_FindMethod(Flp_methods, (PyObject *)self, name); 
} 

static int Flp_setattr(FlpObject * self, char * name, PyObject * v) 
{ 
    if (self->x_attr == NULL) { 
     self->x_attr = PyDict_New(); 
     if (self->x_attr == NULL) 
      return -1; 
    } 
    if (v == NULL) { 
     int rv = PyDict_DelItemString(self->x_attr, name); 
     if (rv < 0) 
      PyErr_SetString(PyExc_AttributeError, 
        "delete non-existing Flp attribute"); 
     return rv; 
    } 
    else 
     return PyDict_SetItemString(self->x_attr, name, v); 
} 
/* --------------------------------------------------------------------- */ 

/* Function of two integers returning integer */ 

static PyObject * flp_foo(PyObject * self, PyObject * args) 
{ 
    long i, j; 
    long res; 
    if (!PyArg_ParseTuple(args, "ll", &i, &j)) 
     return NULL; 
    res = i+j; /* flpX Do something here */ 
    return PyInt_FromLong(res); 
} 


/* Function of no arguments returning new Flp object */ 

static PyObject * flp_new(PyObject * self, PyObject * args) 
{ 
    FlpObject *rv; 

    if (!PyArg_ParseTuple(args, "")) 
     return NULL; 
    rv = newFlpObject(args); 
    if (rv == NULL) 
     return NULL; 
    return (PyObject *)rv; 
} 

/* Example with subtle bug from extensions manual ("Thin Ice"). */ 

static PyObject * flp_bug(PyObject * self, PyObject * args) 
{ 
    PyObject *list, *item; 

    if (!PyArg_ParseTuple(args, "O", &list)) 
     return NULL; 

    item = PyList_GetItem(list, 0); 
    /* Py_INCREF(item); */ 
    PyList_SetItem(list, 1, PyInt_FromLong(0L)); 
    PyObject_Print(item, stdout, 0); 
    printf("\n"); 
    /* Py_DECREF(item); */ 

    Py_INCREF(Py_None); 
    return Py_None; 
} 

/* Test bad format character */ 

static PyObject * flp_roj(PyObject * self, PyObject * args) 
{ 
    PyObject *a; 
    long b; 
    if (!PyArg_ParseTuple(args, "O#", &a, &b)) 
     return NULL; 
    Py_INCREF(Py_None); 
    return Py_None; 
} 


/* List of functions defined in the module */ 

static PyMethodDef flp_methods[] = { 
    {"roj",  flp_roj,  1}, 
    {"foo",  flp_foo,  1}, 
    {"new",  flp_new,  1}, 
    {"bug",  flp_bug,  1}, 
    {NULL,  NULL}  /* sentinel */ 
}; 


/* Initialization function for the module (*must* be called initflp) */ 

DL_EXPORT(void) initflp() 
{ 
    PyObject *m, *d; 

    /* Initialize the type of the new type object here; doing it here 
    * is required for portability to Windows without requiring C++. */ 
    Flp_Type.ob_type = &PyType_Type; 

    /* Create the module and add the functions */ 
    m = Py_InitModule("flp", flp_methods); 

    /* Add some symbolic constants to the module */ 
    d = PyModule_GetDict(m); 
    ErrorObject = PyErr_NewException("flp.error", NULL, NULL); 
    PyDict_SetItemString(d, "error", ErrorObject); 
} 
+0

Ayrıca, Pyllem_DEL (self), '' pyObject_FREE (self); Muhtemelen bununla mı ilgili? https://bugs.launchpad.net/ubuntu/feisty/+source/python-fam/+bug/115655 – andrewrk

1

Ne Boost::Python hakkında?

DÜZENLEME: üzgünüm, desteklemeye güvenmek istemediğinizi denetledim ama yine de en iyi seçeneklerden biri olabileceğini düşünüyorum.

5

kullanım extern C:

İşte düzeltilmiş kod. Çünkü C++ derleyicileri 'name mangling' adı verilen bir şey kullanırlar (aşırı yükleme ile ilgili olarak gereklidir), python C++ kütüphanelerini okuyamaz.Fakat extern C problemlerinizi çözecektir. Bunu yapın:

 
// most of your code can go whereever 
void cpp_function() {} 
extern "C" { 
    // all functions that python calls directly must go in here 
    void python_function() {} 
} 

Her işlev python gereksinimlerini extern bloğunun içine koyduğunuzdan emin olun. Fonksiyonlar içinde hala C++ özelliklerini kullanabilirsiniz, sadece isimler 'isim yönetimi' olmaksızın dışa aktarılacaktır.

İlgili konular