Класс C ++, не распознаваемый Python 3 как модуль через Boost.Python Embedding

В следующем примере Boost.Python v1.56 показано, как встроить интерпретатор Python 3.4.2 в собственное приложение. К сожалению, этот пример не работает из коробки на моей конфигурации с MSVC2013 под Windows 8.1. И я не нашел 1 рабочего полного примера о встраивании, по крайней мере, ни одного, который моложе 10 лет или около того.

Я получаю следующую ошибку при запуске: ImportError: ’embedded_hello’ не является встроенным модулем

Код здесь: http://pastebin.com/shTtdxT8

Любые намеки, что я могу сделать, чтобы позволить этому бежать? И вообще как выставить класс с ++ в Python и наоборот?

4

Решение

Код компилируется с конфигурацией заголовка 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. Внутри тела модуля текущий объем это сам модуль. Таким образом, когда типы C ++ предоставляются через оболочки типов, например, когда классы C ++ предоставляются через Python через boost::python::class_, результирующий класс Python будет внутри модуля, определенного BOOST_PYTHON_MODULE,

С другой стороны, пользовательские типы, объявленные в Python, являются объектами первого класса. С точки зрения C ++ их можно рассматривать как фабричную функцию. Следовательно, чтобы использовать определенный в Python класс в C ++, нужно получить дескриптор объекта класса, а затем создать экземпляр класса, вызвав объект класса.


Вот полный минимальный пример, демонстрирующий встраивание интерпретатора Python 3, который:

  • Импортирует модуль (example), который был встроен непосредственно в двоичный файл и предоставляет базовый класс C ++ (spam_wrap) в Python (example.Spam), которая имеет виртуальную функцию / диспетчеризацию по умолчанию.
  • Демонстрирует использование открытого класса Python (example.Spam).
  • Получается из открытого класса Python (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
6

Другие решения


По вопросам рекламы [email protected]