代码使用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