Boost.Python v1.56中的以下示例显示了如何将Python 3.4.2解释器嵌入到您自己的应用程序中。不幸的是,在Windows 8.1下使用MSVC2013进行配置时,该示例无法正常使用。我还没有找到一个关于嵌入的完整示例,至少没有一个比10年左右更年轻。
运行它时收到以下错误: ImportError:' embedded_hello'不是内置模块
代码在这里:http://pastebin.com/shTtdxT8
任何暗示我可以做些什么来让它运行?一般来说如何在Python中公开c ++类,反之亦然?
答案 0 :(得分:6)
代码正在使用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()
文档明确指出:
将单个模块添加到现有内置模块表中。 ......这应该在
Py_Initialize()
之前调用。
Boost.Python使用BOOST_PYTHON_MODULE
宏来定义Python模块。在模块的主体内,当前scope是模块本身。因此,当C ++类型通过类型包装器公开时,例如当C ++类通过boost::python::class_
向Python公开时,生成的Python类将位于BOOST_PYTHON_MODULE
定义的模块中。
另一方面,在Python中声明的用户定义类型是第一类对象。从C ++的角度来看,它们可以被视为工厂函数。因此,要在C ++中使用Python定义的类,需要获取类对象的句柄,然后通过调用类对象来实例化类的实例。
这是一个完整的最小示例,演示如何嵌入Python 3解释器:
example
),并将基本C ++类(spam_wrap
)公开给具有虚函数/调度的Python(example.Spam
)默认。example.Spam
)。example.Spam
)中公开的Python类(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