本文介绍了你如何用C ++扩展python?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于,我已成功地使用C扩展了Python。但是我找不到一个C ++,我有循环依赖的麻烦,当试图修复C ++给我的错误,当我编译这个骨架模块。



使用C ++扩展Python?



我不想依赖Boost(或者SWIP或者其他库)。依赖性是屁股的痛苦。最好的情况是,我找到一个已经用C ++编译的骨架文件。



这是我为C ++编辑的骨架:

  #include< Python.h> 

#includeFlp.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 = {
/ * ob_type字段必须在模块init函数
*中初始化,以便在不使用C ++的情况下移植到Windows。 * /
PyObject_HEAD_INIT(NULL)
0,/ * ob_size * /
Flp,/ * tp_name * /
sizeof(FlpObject),/ * tp_basicsize * /
0,/ * tp_itemsize * /
/ *方法* /
(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方法

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,))
返回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,
删除不存在的Flp属性);
return rv;
}
else
return PyDict_SetItemString(self-> x_attr,name,v);
}
/ * --------------------------------------- ------------------------------ * /

/ *返回整数的两个整数的函数* /

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这里做一些事情* /
return PyInt_FromLong(res);
}


/ *无返回新Flp对象的参数的函数* /

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

/ *扩展手册中的细微错误(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(\\\
);
/ * Py_DECREF(item); * /

Py_INCREF(Py_None);
return Py_None;
}

/ *测试错误的格式字符* /

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


/ *模块中定义的函数列表* /

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


/ *模块的初始化函数(*必须被称为initflp)* /

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

/ *在这里初始化新类型对象的类型;做这里
*是需要可移植到Windows,而不需要C ++。 * /
Flp_Type.ob_type =& PyType_Type;

/ *创建模块并添加函数* /
m = Py_InitModule(flp,flp_methods);

/ *为模块添加一些符号常量* /
d = PyModule_GetDict(m);
ErrorObject = PyErr_NewException(flp.error,NULL,NULL);
PyDict_SetItemString(d,error,ErrorObject);
}

这对我来说很好,但是当我测试它:

  $ python 
Python 2.6.5(r265:79063,2010年4月16日,13:57:41)
[ GCC 4.4.3] on linux2
键入help,copyright,credits或license获取更多信息。
>>>> import flp
回溯(最近最后一次调用):
在< module>中的文件< stdin>
ImportError:动态模块没有定义init函数(initflp)
>>>


解决方案

首先,即使你不想引入额外的依赖关系,我建议您查看。引用其网页:

我认为PyCXX是根据BSD许可证意思是你可以在扩展的分布式压缩包中包含PyCXX的整个源代码,如果你的扩展将在类似的许可证下发布。



如果你真的绝对不想依赖PyCXX或任何其他第三方库,我想你只需要函数,将由 externC{}中的Python解释器调用

  

> #include< Python.h>

#includeFlp.h

static PyObject * ErrorObject;

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

externC{
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 = {
/ * ob_type字段必须在模块init函数
*中初始化,以便在不使用C ++的情况下移植到Windows。 * /
PyObject_HEAD_INIT(NULL)
0,/ * ob_size * /
Flp,/ * tp_name * /
sizeof(FlpObject),/ * tp_basicsize * /
0,/ * tp_itemsize * /
/ *方法* /
(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方法

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,))
返回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,
删除不存在的Flp属性);
return rv;
}
else
return PyDict_SetItemString(self-> x_attr,name,v);
}
/ * --------------------------------------- ------------------------------ * /

/ *返回整数的两个整数的函数* /

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这里做一些事情* /
return PyInt_FromLong(res);
}


/ *无返回新Flp对象的参数的函数* /

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

/ *扩展手册中的细微错误(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(\\\
);
/ * Py_DECREF(item); * /

Py_INCREF(Py_None);
return Py_None;
}

/ *测试错误的格式字符* /

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


/ *模块中定义的函数列表* /

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


/ *模块的初始化函数(*必须被称为initflp)* /

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

/ *在这里初始化新类型对象的类型;做这里
*是需要可移植到Windows,而不需要C ++。 * /
Flp_Type.ob_type =& PyType_Type;

/ *创建模块并添加函数* /
m = Py_InitModule(flp,flp_methods);

/ *为模块添加一些符号常量* /
d = PyModule_GetDict(m);
ErrorObject = PyErr_NewException(flp.error,NULL,NULL);
PyDict_SetItemString(d,error,ErrorObject);
}


I've successfully extended python with C, thanks to this handy skeleton module. But I can't find one for C++, and I have circular dependency trouble when trying to fix the errors that C++ gives when I compile this skeleton module.

How do you extend Python with C++?

I'd rather not depend on Boost (or SWIP or other libraries) if I don't have to. Dependencies are a pain in the butt. Best case scenario, I find a skeleton file that already compiles with C++.

Here's the edited skeleton I've made for 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);
}

This compiles fine for me, but when I test it:

$ 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)
>>>
解决方案

First of all, even though you don't want to introduce an additional dependency, I suggest you to have a look at PyCXX. Quoting its webpage:

I think PyCXX is licensed under the BSD license, which means that you can just as well include the whole source code of PyCXX in the distributed tarball of your extension if your extension will be released under a similar license.

If you really and absolutely don't want to depend on PyCXX or any other third-party library, I think you only have to wrap functions that will be called by the Python interpreter in extern "C" { and } to avoid name mangling.

Here's the corrected code:

#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 ++扩展python?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 05:49