簡體   English   中英

使用C / API和C ++類編寫Python模塊

[英]Writing a Python module using C/API and C++ classes

我是編寫自定義Python模塊的新手,我對Capsules的工作方式有點困惑。 我在系統OSX安裝中使用Python 2.7.6並嘗試使用Capsules(如Python推薦的那樣> 2.7)來傳遞指針(在他們使用PyCObject之前)。 我的代碼目前不起作用,我想得到一些見解,原則上應該如何處理事情。 代碼應該定義一個類LuscherClm,我希望能夠執行以下操作:

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

第一個問題:目前我必須做以下事情:

>>> c40=Luscher.init(4,0)
>>>
>>> c40.eval(0.12)
Segfault 

因此,我的第一個問題是:如何修改方法表以使用更多的操作符樣式轉換而不是成員函數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;
}

構造函數:它返回指向膠囊的指針。 我不知道這是否正確。 因為在這種情況下,當我調用clm = LuscherClm.init(l,m)時,clm對象是一個PyCapsule並且沒有屬性eval,因此我無法在其上調用clm.eval(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;
}

那么膠囊是如何傳遞給評估函數的呢? 下面的代碼是不正確的,因為我從CObjects轉移到膠囊后沒有更新它。 膠囊應該是一個全局變量(我不喜歡)或者我如何將它傳遞給評估函數? 或者我可以自稱,但現在的自我是什么?

//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或盡可能提升,因為這個模塊應該很容易移植,我想避免每次我想在其他地方使用它時都要安裝額外的軟件包。 進一步:C / API在調用函數時產生的開銷是多少? 我需要稱它為O(10 ^ 6)次的命令,我仍然希望它快。

好的,我現在正在使用boost.python,但是當我運行object.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是一個numpy擴展,boost不能理解。 所以我的問題是:1)如何將復數作為python數據類型返回(復雜的標准python類型?)2)為什么我會得到段錯誤。 我的測試用例中的結果是真實的,所以它應該默認為else語句。 我猜這個指針超出了范圍,就是這樣。 但即使在if-case(我關注ref-increment)中,它也會出現段錯誤。 有人可以幫我解決類型轉換問題嗎?

謝謝托爾斯滕

好,我知道了。 以下轉換器完成工作:

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

使用這個轉換器和Wouter的帖子,我想我的問題得到了回答。 謝謝

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM