[英]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.