gpt4 book ai didi

c++ - 如何用 C++ 扩展 python?

转载 作者:IT老高 更新时间:2023-10-28 21:03:05 25 4
gpt4 key购买 nike

感谢this handy skeleton module,我成功地用C 扩展了python .但是我找不到 C++ 的,并且在尝试修复 C++ 在编译此骨架模块时给出的错误时遇到循环依赖问题。

如何用 C++ 扩展 Python?

如果没有必要,我宁愿不依赖 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)
>>>

最佳答案

首先,即使你不想引入额外的依赖,我建议你看看PyCXX .引用其网页:

CXX/Objects is a set of C++ facilities to make it easier to write Python extensions. The chief way in which PyCXX makes it easier to write Python extensions is that it greatly increases the probability that your program will not make a reference-counting error and will not have to continually check error returns from the Python C API. CXX/Objects integrates Python with C++ in these ways:

  • C++ exception handling is relied on to detect errors and clean up. In a complicated function this is often a tremendous problem when writing in C. With PyCXX, we let the compiler keep track of what objects need to be dereferenced when an error occurs.
  • The Standard Template Library (STL) and its many algorithms plug and play with Python containers such as lists and tuples.
  • The optional CXX/Extensions facility allows you to replace the clumsy C tables with objects and method calls that define your modules and extension objects.

我认为 PyCXX 是在 BSD 许可证下获得许可的,这意味着如果您的扩展程序将在类似的许可证下发布,您也可以将 PyCXX 的整个源代码包含在您的扩展程序的分布式压缩包中。

如果你真的绝对不想依赖 PyCXX 或任何其他第三方库,我认为你只需要 wrap 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);
}

关于c++ - 如何用 C++ 扩展 python?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2847617/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com