for create code c++ python

create - ¿Cómo extiendes python con C++?



cython (3)

¿Qué pasa con Boost::Python ?

EDIT: lo siento, supervisé que no desea depender del impulso, pero creo que todavía podría ser una de las mejores opciones.

He ampliado con éxito Python con C, gracias a este práctico módulo de esqueleto . Pero no puedo encontrar uno para C ++, y tengo un problema de dependencia circular cuando intento corregir los errores que C ++ produce cuando compilo este módulo de esqueleto.

¿Cómo extender Python con C ++?

Prefiero no depender de Boost (o SWIP u otras bibliotecas) si no tengo que hacerlo. Las dependencias son un dolor en el trasero. En el mejor de los casos, encuentro un archivo esqueleto que ya compila con C ++.

Aquí está el esqueleto editado que he hecho para C ++:

#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); }

Esto compila bien para mí, pero cuando lo pruebo:

$ 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) >>>


En primer lugar, aunque no quiera introducir una dependencia adicional, le sugiero que eche un vistazo a PyCXX . Citando su página web:

CXX / Objects es un conjunto de funciones de C ++ para facilitar la escritura de extensiones de Python. La forma principal en que PyCXX facilita la escritura de las extensiones de Python es que aumenta enormemente la probabilidad de que su programa no cometa un error de conteo de referencias y no tenga que verificar continuamente las devoluciones de errores de la API de Python C. CXX / Objects integra Python con C ++ de estas maneras:

  • Se confía en el manejo de excepciones de C ++ para detectar errores y limpiar. En una función complicada, esto suele ser un gran problema cuando se escribe en C. Con PyCXX, permitimos que el compilador realice un seguimiento de qué objetos deben ser referenciados cuando se produce un error.
  • La biblioteca de plantillas estándar (STL) y sus numerosos algoritmos se conectan y reproducen con contenedores Python, como listas y tuplas.
  • La función opcional CXX / Extensions le permite reemplazar las tablas C con objetos y llamadas de método que definen sus módulos y objetos de extensión.

Creo que PyCXX está licenciado bajo la licencia BSD, lo que significa que también puede incluir todo el código fuente de PyCXX en el tarball distribuido de su extensión si su extensión se lanzará bajo una licencia similar.

Si realmente y no desea depender de PyCXX o de cualquier otra biblioteca de terceros, creo que solo tiene que wrap funciones que el intérprete de Python llamará en la extern "C" { y } extern "C" { para evitar la manipulación de nombres.

Aquí está el código corregido:

#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); }


use extern C para envolver todos los nombres de funciones que se llaman desde python. Debido a que los compiladores de C ++ usan algo llamado ''denominación de nombres'' (necesario para lidiar con la sobrecarga), python no puede leer las bibliotecas de c ++. Pero extern C resolverá tus problemas. Hazlo asi:

// 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() {} }

Asegúrese de poner todas las funciones que Python necesita dentro del bloque externo. Aún puedes usar las funciones de c ++ dentro de las funciones, es solo que los nombres se exportarán sin ''denominación de nombres''.