[英]C++ class not recognized by Python 3 as a module via Boost.Python Embedding
Boost.Python v1.56中的以下示例顯示了如何將Python 3.4.2解釋器嵌入到您自己的應用程序中。 不幸的是,在Windows 8.1下使用MSVC2013進行配置時,該示例無法正常使用。 我還沒有找到一個關於嵌入的完整示例,至少沒有一個比10年左右更年輕。
運行它時收到以下錯誤: ImportError:'embedded_hello'不是內置模塊
代碼在這里: http : //pastebin.com/shTtdxT8
任何暗示我可以做什么讓這個運行? 一般來說如何在Python中公開c ++類,反之亦然?
代碼正在使用Python 2頭配置進行編譯。 使用Python 3頭配置進行編譯時, boost/python/module_init.hpp
會將embedded_hello
模塊的初始化函數聲明為PyInit_embedded_hello
而不是initembedded_hello
。 我強烈建議驗證正確的頭配置,並執行Boost.Python的干凈構建,因為Boost.Python和使用庫構建的模塊需要使用相同的頭配置。
此外,在將模塊添加到內置表時, PyImport_AppendInittab()
調用需要在Py_Initialize()
之前Py_Initialize()
。 PyImport_AppendInittab()
文檔明確指出:
將單個模塊添加到現有內置模塊表中。 ...這應該在
Py_Initialize()
之前Py_Initialize()
。
Boost.Python使用BOOST_PYTHON_MODULE
宏來定義Python模塊。 在模塊的主體內,當前范圍是模塊本身。 因此,當通過類型包裝器公開C ++類型時,例如當通過boost::python::class_
將C ++類暴露給Python時,生成的Python類將位於BOOST_PYTHON_MODULE
定義的模塊中。
另一方面,在Python中聲明的用戶定義類型是第一類對象。 從C ++的角度來看,它們可以被視為工廠函數。 因此,要在C ++中使用Python定義的類,需要獲取類對象的句柄,然后通過調用類對象來實例化類的實例。
這是一個完整的最小示例,演示了如何嵌入Python 3解釋器:
example
),並將基本C ++類( spam_wrap
)公開給具有默認的虛函數/調度的Python( example.Spam
)。 example.Spam
)。 example.Spam
)中公開的Python類( example.Spam
) example.PySpam
並使用生成的類。 #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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.