代碼使用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
非常感謝您的例子。是的,我忘記在PasteBin上的代碼中更改Python3的PyInit_,並對其進行了更正。您的示例迄今爲止只適用於簡單的類。我必須找出它是否也適用於派生於具有虛函數和所有這些東西的抽象類。 但是現在我怎樣才能將Python中定義的類重新導入到C++中呢?那部分仍然不起作用。 :( – patlecat 2014-11-07 09:47:21
@patlecat讓模塊加載通常是比較困難的部分,剩下的就是使用Boost.Python在C++中編寫Python,我已經更新了這個例子,使其更加複雜一些,演示瞭如何使用類在C++中用Python定義,用>>>註釋的C++註釋顯示等效的Python調用。 – 2014-11-07 14:12:30