用C/API和C++类编写Python模块

2024-09-30 12:16:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我对编写定制Python模块是新手,我有点搞不清胶囊是如何工作的。我使用systemosx安装中的python2.7.6,并尝试使用胶囊(Python>;2.7的推荐)来传递指针(在他们使用PyCObject之前)。我的代码目前不工作,我想了解一下原则上应该如何处理。代码应该定义一个类LuscherClm,我希望能够执行以下操作:

>>> c40=Luscher(4,0)
>>>
>>> c40(0.12)
>>> <print the result of the evaluation>

第一个问题:目前我需要做的事情是:

^{pr2}$

因此,我的第一个问题是:如何修改method表以获得更多的运算符样式转换,而不是成员函数init和eval。在

<>但是,我的代码还有其他问题,这里是相关的部分(基础C++类工作顺利,我在生产中经常用到):

毁灭者:

//destructor
static void clm_destruct(PyObject* capsule){
    void* ptr=PyCapsule_GetPointer(capsule,"zetfunc");
    Zetafunc* zetptr=static_cast<Zetafunc*>(ptr);
    delete zetptr;
    return;
}

构造函数:返回指向胶囊的指针。我不知道这是否正确。因为在这种情况下,我打电话的时候,克莱姆=LuscherClm.init(l,m),clm对象是一个PyCapsule,没有属性eval,因此我无法调用clm.评估(x) 在那上面。该如何处理?在

//constructor
static PyObject* clm_init(PyObject* self, PyObject *args){
    //return value
    PyObject* result=NULL;

    //parse variables
    unsigned int lval=0;
    int mval=0;
    if(!PyArg_ParseTuple(args,"li",&lval,&mval)){
        ::std::cout << "Please specify l and m!" << ::std::endl;
        return result;
    }

    //class instance:
    Zetafunc* zetfunc=new Zetafunc(lval,mval);
    instanceCapsule=PyCapsule_New(static_cast<void*>   (zetfunc),"zetfunc",&clm_destruct);
    return instanceCapsule;
}

那么胶囊是如何传递给evaluate函数的呢?下面的代码是不正确的,因为我在从CObjects移到Capsules之后没有更新它。胶囊是一个全局变量(我不喜欢这样),还是我如何将它传递给求值函数?或者我应该称之为自我,但此刻的自我是什么呢?在

//evaluate the function
static PyObject* clm_evaluate(PyObject* self, PyObject* args){
    //get the PyCObject from the capsule:
    void* tmpzetfunc=PyCapsule_GetPointer(instanceCapsule,"zetfunc");
    if (PyErr_Occurred()){
        std::cerr << "Some Error occured!" << std::endl;
        return NULL;
    }
    Zetafunc* zetfunc=static_cast< Zetafunc* >(tmpzetfunc);
    //parse value:
    double x;
    if(!PyArg_ParseTuple(args,"d",&x)){
        std::cerr << "Specify a number at which you want to evaluate the function" << std::endl;
        return NULL;
    }
    double result=(*zetfunc)(x).re();

    //return the result as a packed function:
    return Py_BuildValue("d",result);
}

//methods
static PyMethodDef LuscherClmMethods[] = {
    {"init",  clm_init, METH_VARARGS, "Initialize clm class!"},
    {"eval", clm_evaluate, METH_VARARGS, "Evaluate the Zeta-Function!"},
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

Python<;3初始化函数:

PyMODINIT_FUNC
initLuscherClm(void)
{
    PyObject *m = Py_InitModule("LuscherClm", LuscherClmMethods);
    return;
}

你能解释为什么我错了?如果可能的话,我希望远离SWIG或boost,因为这个模块应该很容易移植,并且我希望避免每次在其他地方使用它时都必须安装额外的软件包。 进一步:C/API在调用函数时会产生什么开销?我需要把它称为O(10^6)次的顺序,我还是希望它快点。在

好的,我在用boost.python但我跑的时候有个小毛病对象.eval(). 这就是我现在的程序:

BOOST_PYTHON_MODULE(threevecd)
{
    class_< threevec<double> >("threevecd",init<double,double,double>());
}

BOOST_PYTHON_MODULE(LuscherClm)
{
    class_<Zetafunc>("LuscherClm",init<int,int, optional<double,threevec<double>,double,int> >())
    .def("eval",&Zetafunc::operator(),return_value_policy<return_by_value>());
    boost::python::to_python_converter<dcomplex,dcomplex_to_python_object>();
}

dcomplex是我自己的复数实现。所以我不得不写一个转换器:

struct dcomplex_to_python_object
{
    static PyObject* convert(dcomplex const& comp)
    {
        if(fabs(comp.im())<std::numeric_limits<double>::epsilon()){
            boost::python::object result=boost::python::object(complex<double>(comp.re(),comp.im()));
            return boost::python::incref(result.ptr());
        }
        else{
            return Py_BuildValue("d",comp.re());
        }
    }
};

Complex128是boost无法理解的numpy扩展。所以我的问题是: 1) 如何将复数作为python数据类型返回(complex是标准python类型吗?) 2) 为什么我会得到一个segfault。我在testcase中的结果是真实的,所以它应该默认为else语句。我猜指针超出了范围,就这样。但即使在if的情况下(我关心ref增量),它也会产生错误。有人能帮我解决类型转换问题吗?在

谢谢 托尔斯滕


Tags: thereturninitstaticresultnullpyobjectstd
1条回答
网友
1楼 · 发布于 2024-09-30 12:16:26

好的,我知道了。以下转换器执行此工作:

struct dcomplex_to_python_object
{
    static PyObject* convert(dcomplex const& comp)
    {
        PyObject* result;
        if(std::abs(comp.im())<=std::numeric_limits<double>::epsilon()){
            result=PyFloat_FromDouble(comp.re());
        }
        else{
            result=PyComplex_FromDoubles(comp.re(),comp.im());
        }
        Py_INCREF(result);
        return result;
    }
};

利用这个转换器和沃特的帖子,我想我的问题得到了回答。谢谢

相关问题 更多 >

    热门问题