2014-11-06 53 views
2

Boost.Python v1.56中的以下示例顯示瞭如何將Python 3.4.2解釋器嵌入到您自己的應用程序中。不幸的是,這個例子在Windows 8.1下使用MSVC2013進行配置時無法使用。而且我還沒有找到1個關於嵌入的完整示例,至少沒有一個比10年少。C++類未被Python 3識別爲模塊,通過Boost.Python嵌入

我收到運行了以下錯誤:導入錯誤:「embedded_hello」不是一個內置模塊

的代碼是在這裏:http://pastebin.com/shTtdxT8

任何提示我能做些什麼,讓這個運行?一般來說,如何在Python中公開C++類,反之亦然?

回答

3

代碼使用Python 2頭配置進行編譯。使用Python 3頭配置進行編譯時,boost/python/module_init.hpp將宣佈embedded_hello模塊的初始化函數爲PyInit_embedded_hello,而不是initembedded_hello。我強烈建議驗證正確的標頭配置,並執行Boost.Python的全新構建,因爲Boost.Python和使用庫構建的模塊需要使用相同的標頭配置。

此外,將模塊添加到內置表時,PyImport_AppendInittab()調用需要發生在Py_Initialize()之前。該PyImport_AppendInittab()文件明確規定:

Add a single module to the existing table of built-in modules. ... This should be called before Py_Initialize() .

Boost.Python使用了BOOST_PYTHON_MODULE宏來定義一個Python模塊。在模塊的主體內,當前scope是模塊本身。因此,當通過類型包裝器暴露C++類型時,例如當通過boost::python::class_將C++類暴露給Python時,生成的Python類將位於由BOOST_PYTHON_MODULE定義的模塊內。

另一方面,在Python中聲明的用戶定義類型是第一類對象。從C++的角度來看,它們可以被看作是工廠函數。因此,要在C++中使用Python定義的類,需要獲取類對象的句柄,然後通過調用類對象來實例化類的實例。


在這裏是一個完整的最小示例演示嵌入一個Python 3解釋的是:已被直接構建在二進制和公開了一個基本的C

  • 導入一個模塊(example)++類(spam_wrap)到Python(example.Spam),它具有虛擬函數/使用默認分派。
  • 演示使用暴露的Python類(example.Spam)。
  • 派生自Python(example.PySpam)中暴露的Python類(example.Spam)並使用生成的類。
#include <iostream> 
#include <boost/python.hpp> 

/// @brief Mockup Spam model. 
struct spam 
    : boost::noncopyable 
{ 
    virtual ~spam() {}; 
    virtual std::string hello() { return "Hello from C++"; } 
}; 

//@ brief Mockup Spam wrapper. 
struct spam_wrap 
    : spam, 
    boost::python::wrapper<spam> 
{ 
    virtual std::string hello() 
    { 
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) 
    return boost::python::call<std::string>(
     this->get_override("hello").ptr()); 
#else 
    return this->get_override("hello")(); 
#endif 
    } 

    std::string default_hello() { return this->spam::hello(); } 
}; 

/// @brief Python example module. 
BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 

    // Expose C++ spam_wrap as Python Spam class. 
    python::class_<spam_wrap, boost::noncopyable>("Spam") 
    .def("hello", &spam::hello, &spam_wrap::default_hello) 
    ; 
} 

int main() 
{ 
    // Add example to built-in. 
    PyImport_AppendInittab("example", &PyInit_example); 

    // Start the interpreter. 
    Py_Initialize(); 

    namespace python = boost::python; 
    try 
    { 
    python::object main = python::import("__main__"); 
    python::object global = main.attr("__dict__"); 

    // Execute Python code, using the example module. 
    exec(
     "from example import Spam   \n" 
     "spam = Spam()      \n" 
     "         \n" 
     "class PySpam(Spam):    \n" 
     " def hello(self):    \n" 
     "  return 'Hello from Python'\n",  
     global, global); 

    /// Check the instance of the Python object using the C++ class. 
    // >>> spam_object = spam 
    python::object spam_object = global["spam"]; 
    assert(python::extract<spam>(spam_object).check()); 
    // >>> result = spam_object.hello() 
    python::object result = spam_object.attr("hello")(); 
    // >>> print(result) 
    std::cout << python::extract<std::string>(result)() << std::endl; 
    // >>> assert("Hello from C++" == result) 
    assert("Hello from C++" == python::extract<std::string>(result)()); 

    /// Create an instance using PySpam class. It too is a Python object. 
    // >>> py_spam_type = PySpam 
    python::object py_spam_type = global["PySpam"]; 
    // >>> py_spam_object = py_spam_type() 
    python::object py_spam_object = py_spam_type(); 
    // >>> result = py_spam_object() 
    result = py_spam_object.attr("hello")(); 
    // >>> print(result) 
    std::cout << python::extract<std::string>(result)() << std::endl; 
    // >>> assert("Hello from Python" == result) 
    assert("Hello from Python" == python::extract<std::string>(result)()); 
    } 
    catch (const python::error_already_set&) 
    { 
    PyErr_Print(); 
    } 
} 

程序應該運行到完成沒有錯誤,導致下面的輸出:

Hello from C++ 
Hello from Python 
+0

非常感謝您的例子。是的,我忘記在PasteBin上的代碼中更改Python3的PyInit_,並對其進行了更正。您的示例迄今爲止只適用於簡單的類。我必須找出它是否也適用於派生於具有虛函數和所有這些東西的抽象類。 但是現在我怎樣才能將Python中定義的類重新導入到C++中呢?那部分仍然不起作用。 :( – patlecat 2014-11-07 09:47:21

+0

@patlecat讓模塊加載通常是比較困難的部分,剩下的就是使用Boost.Python在C++中編寫Python,我已經更新了這個例子,使其更加複雜一些,演示瞭如何使用類在C++中用Python定義,用>>>註釋的C++註釋顯示等效的Python調用。 – 2014-11-07 14:12:30