2011-05-24 87 views
14

我有一個C++類,帶有一個成員函數,可以從一個小到大量的參數。讓我們將這些參數命名爲a-f。所有參數都有默認值。作爲我正在開發的python項目的一部分,我想將這個類暴露給python。目前,成員函數看起來是這樣的:Boost :: Python-可能自動從字典轉換 - > std :: map?

class myClass { 
    public: 
    // Constructors - set a-f to default values. 

    void SetParameters(std::map<std::string, double> &); 
    private: 
    double a, b, c, d, e, f; 
} 

void myClass::SetParameters(std::map<std::string, double> const& params) { 
    // Code to iterate over the map, and set any found key/value pairs to their 
    // corresponding variable. i.e.- "a" --> 2.0, would set myClass::a to 2.0 
} 

理想的情況下,在Python,我想做到這一點使用的字典:

>>> A = myModule.myClass(); 
>>> A.SetParameters({'a': 2.2, 'd': 4.3, b: '9.3'}) 

通過這種方式,用戶可以在輸入值任何訂單,並輸入其中的任何數量將被覆蓋。任何關於如何在boost :: python中完成的想法?在我看來,我可以通過將地圖輸入更改爲boost :: python對象並使用提取函數來完成此操作。但是,這將需要我改變我的庫的接口(我寧願保留std :: map接口,並且有一些Python版本的中介/自動轉換技術)。思考?

回答

21

我認爲有幾個是更容易實現比寫自己的轉換方式。你可以使用boost :: python的map_indexing_suite爲你做轉換,或者你可以在python中使用關鍵字參數。我個人更喜歡關鍵字參數,因爲這是更「Python」的方式來做到這一點。

因此,這是你的類(我增加了對地圖的類型定義):

typedef std::map<std::string, double> MyMap; 

class myClass { 
public: 
    // Constructors - set a-f to default values. 

    void SetParameters(MyMap &); 
private: 
    double a, b, c, d, e, f; 
}; 

示例使用map_indexing_suite:

#include <boost/python/suite/indexing/map_indexing_suite.hpp> 

using boost::python; 

BOOST_PYTHON_MODULE(mymodule) 
{ 
    class_<std::map<std::string, double> >("MyMap") 
     .def(map_indexing_suite<std::map<std::wstring, double> >()); 

    class_<myClass>("myClass") 
     .def("SetParameters", &myClass::SetParameters); 
} 

例使用關鍵字參數。這需要使用raw_function包裝:

using namespace boost::python; 

object SetParameters(tuple args, dict kwargs) 
{ 
    myClass& self = extract<myClass&>(args[0]); 

    list keys = kwargs.keys(); 

    MyMap outMap; 
    for(int i = 0; i < len(keys); ++i) { 
     object curArg = kwargs[keys[i]]; 
     if(curArg) { 
      outMap[extract<std::string>(keys[i])] = extract<double>(kwargs[keys[i]]); 
     }    
    } 
    self.SetParameters(outMap); 

    return object(); 
} 

BOOST_PYTHON_MODULE(mymodule) 
{ 
    class_<myClass>("myClass") 
     .def("SetParameters", raw_function(&SetParameters, 1)); 
} 

這允許你寫這樣的東西在Python:

A.SetParameters(a = 2.2, d = 4.3, b = 9.3) 
+0

@ aleksey-關鍵字參數方法看起來最適合什麼我想這樣做,但是,我在發佈的代碼中遇到了一些問題,看起來像raw_function只是喜歡指定的函數將輸入作爲元組和字典。是否有類成員函數的單獨類似結構? – MarkD 2011-05-25 02:18:51

+0

哦,我明白了,我想通過使用一個繼承自我試圖包裝的類的包裝類來解決這個問題 – 2011-05-25 02:23:09

+0

另外,args元組中的第一個參數應該是對你的類的引用。你可以省略自變量並從args [0]中提取myClass&。看看是否有效。 – 2011-05-25 02:28:25

0

我只是讓我的腳趾溼與boost :: python所以不能完全回答你的問題。但我看到的第一個障礙是保證py字典的鍵都是字符串。 Python字典也可以在元組上鍵控(我假設有更多的類型)。

+0

凡是是可哈希可以一鍵,和一個字典可以有許多不同類型的鍵。 – 2012-06-13 11:20:54

6

This blog post對如何編寫這些轉換器有非常清晰的描述。其基本模式是定義的形式爲一類:

struct SomeType_from_PyObject 
{ 
    SomeType_from_PyObject(); 
    static void* convertible(PyObject* obj_ptr); 
    static void construct(PyObject* obj_ptr, 
          converter::rvalue_from_python_stage1_data* data); 
}; 

當構造器負責將這個轉換器的Boost.Python的註冊表:

SomeType_from_PyObject::SomeType_from_PyObject() 
{ 
    converter::registry::push_back(&convertible, 
            &construct, 
            type_id<SomeType>()); 
} 

功能convertible告訴升壓與否該轉換器可以轉換指定的Python對象:

void* SomeType_from_PyObject::convertible(PyObject* obj_ptr) 
{ 
    if (PyMapping_Check(obj_ptr)) { 
     return obj_ptr; 
    } else { 
     return NULL; 
    } 
} 

construct功能實際創建的對象轉換類型:

void SomeType_from_PyObject::construct(PyObject* obj_ptr, 
             converter::rvalue_from_python_stage1_data* data) 
{ 
    typedef converter::rvalue_from_python_storage<SomeType> storage_t; 
    storage_t* the_storage = reinterpret_cast<storage_t*>(data); 
    void* memory_chunk = the_storage->storage.bytes; 
    object obj(handle<>(borrowed(obj_ptr))); 
    SomeType* output = new (memory_chunk) SomeType(); 
    // Use the contents of obj to populate output, e.g. using extract<> 
    data->convertible = memory_chunk; 
} 
您BOOST_PYTHON_MODULE內

,然後在你的,包括行

SomeType_from_PyObject(); 
+0

非常感謝你爲這個偉大的職位雷。我開始沿着這條路線走下去(並且很可能會完成我正在努力學習更多關於Python/C API的知識。我認爲aleksay的關鍵字參數方法將會是我如何才能實現它的工作方式,但這是非常有價值的東西+1 – MarkD 2011-05-25 02:20:43

+0

我同意,雖然轉換器不是我會解決Mark的問題的方式,但是我很欣賞boost :: python轉換器的一個很好的帖子。 – 2011-12-08 01:58:05

相關問題