Как вы расширяете python с помощью C ++?

Я успешно расширил python с помощью C, благодаря этому удобному скелетному модулю . Но я не могу найти его для C ++, и у меня проблема с круговой зависимостью при попытке исправить ошибки, которые дает C ++ при компиляции этого скелетного модуля.

Как вы расширяете Python с помощью C ++?

Я бы предпочел не полагаться на Boost (или SWIP или другие библиотеки), если мне это не нужно. Зависимости – это боль в прикладе. Лучший сценарий, я нахожу файл скелета, который уже компилируется с C ++.

Вот отредактированный скелет, который я сделал для 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); } 

Это компилируется для меня, но когда я проверяю это:

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

3 Solutions collect form web for “Как вы расширяете python с помощью C ++?”

Прежде всего, хотя вы не хотите вводить дополнительную зависимость, я предлагаю вам взглянуть на PyCXX . Цитируя его веб-страницу:

CXX / Objects – это набор возможностей на C ++, упрощающий запись расширений Python. Главный способ, с помощью которого PyCXX упрощает запись расширений Python, заключается в том, что он значительно увеличивает вероятность того, что ваша программа не сделает ошибку подсчета ссылок и не будет необходимости постоянно проверять возврат ошибок из API Python C. CXX / Objects объединяет Python с C ++ следующими способами:

  • Обработка исключений на языке C ++ используется для обнаружения ошибок и очистки. В сложной функции это часто представляет собой огромную проблему при записи в C. С помощью PyCXX мы позволяем компилятору отслеживать, какие объекты нужно разыменовать при возникновении ошибки.
  • Библиотека стандартных шаблонов (STL) и ее многочисленные алгоритмы подключаются и воспроизводятся с контейнерами Python, такими как списки и кортежи.
  • Дополнительный объект CXX / Extensions позволяет вам заменять неуклюжие таблицы C на вызовы объектов и методов, которые определяют ваши модули и объекты расширения.

Я думаю, что PyCXX лицензируется под лицензией BSD, а это значит, что вы также можете включить весь исходный код PyCXX в распределенный архив вашего расширения, если ваше расширение будет выпущено по аналогичной лицензии.

Если вы действительно и абсолютно не хотите зависеть от PyCXX или любой другой сторонней библиотеки, я думаю, вам нужно только обернуть функции, которые будут вызывать интерпретатор Python в extern "C" { и } чтобы избежать изменения имени.

Вот исправленный код:

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

используйте extern C, чтобы обернуть все имена функций, которые вызываются из python. Поскольку компиляторы C ++ используют что-то под названием «mangling» (необходимое для работы с перегрузкой), python не может читать библиотеки c ++. Но extern C решит ваши проблемы. Делай это так:

 // большая часть вашего кода может идти
 void cpp_function () {}
 extern "C" {
    // все функции, которые непосредственно должны отвечать на вызовы python
    void python_function () {}
 }

Убедитесь, что вы поставили каждую функцию python внутри блока extern. Вы все еще можете использовать функции c ++ внутри функций, это просто, что имена будут экспортироваться без «mangling».

Как насчет Boost :: Python ?

EDIT: извините, я наблюдал за тем, что вы не хотите зависеть от повышения, но я думаю, что это может быть один из лучших вариантов.

  • Как создать приложение, которое внедряет и запускает код Python без локальной установки Python?
  • boost :: python Экспорт пользовательских исключений
  • Можно ли встроить виджет C ++ в приложение PyQt?
  • Как исходный код Python «free_list = (PyIntObject *) Py_TYPE (v);» переместить указатель free_list на следующий объект?
  • Как определить массив пользовательских типов в WSDL?
  • Почему существует «int + string» в статически типизированном C #, но не в динамически типизированном Python?
  • запись надежного (определение цвета и размера) обнаружения круга с помощью opencv (на основе преобразования Hough или других функций)
  • Как вы используете стандартную библиотеку в IronPython?
  • Преобразование цветового пространства PIL YCbCr -> RGB
  • СинтаксисError с scipy.weave.inline
  • Что такое версия C # для GIL?
  • Python - лучший язык программирования в мире.