将Python嵌入C ++并使用Boost.Python从C ++代码调用方法

将Python嵌入C ++并使用Boost.Python从C ++代码调用方法,第1张

将Python嵌入C ++并使用Boost.Python从C ++代码调用方法

简而言之,与嵌入式Python静态链接的Python扩展需要在初始化解释器之前将其模块初始化函数显式添加到初始化表中。

Pyimport_AppendInittab("hello", &inithello);Py_Initialize();

Boost.Python使用该

BOOST_PYTHON_MODULE
宏定义Python模块初始化程序。结果函数不是模块导入器。这种区别类似于创建
example.py
模块和调用的区别
importexample

导入模块时,Python将首先检查该模块是否为内置模块。如果模块不存在,则Python将搜索模块搜索路径,以尝试根据模块名称查找python文件或库。如果找到了库,则Python期望该库提供一个将初始化模块的函数。找到后,导入将在modules表中创建一个空模块,然后对其进行初始化。对于静态链接的模块(例如

hello
原始代码中的模块),模块搜索路径将无济于事,因为没有可查找的库。

对于嵌入,模块表和初始化函数文档指出,对于静态模块,除非初始化表中有条目,否则不会自动调用模块初始化器函数。对于Python 2和Python
3,可以通过调用

Pyimport_AppendInittab()
before来实现
Py_Initialize()

BOOST_PYTHON_MODULE(hello){  // ...}Pyimport_AppendInittab("hello", &inithello);Py_Initialize();// ...boost::python::object hello = boost::python::import("hello");

还要注意,Python的C API用于在Python
2和3之间嵌入更改的模块初始化函数的命名约定,因此,对于

BOOST_PYTHON_MODULE(hello)
,可能需要同时使用
&inithello
Python
2和
&PyInit_hello
Python 3。


这是一个完整的示例,演示了将嵌入式Python导入

demo
用户模块,然后再导入静态链接的
hello
模块。它还在用户模块中调用一个函数,
demo.multiply
然后该函数将调用通过静态链接的模块公开的方法。

#include <cstdlib>  // setenv, atoi#include <iostream> // cerr, cout, endl#include <boost/python.hpp>struct World{  void set(std::string msg) { this->msg = msg; }  std::string greet()       { return msg;      }  std::string msg;};/// Staticly linking a Python extension for embedded Python.BOOST_PYTHON_MODULE(hello){  namespace python = boost::python;  python::class_<World>("World")    .def("greet", &World::greet)    .def("set", &World::set)    ;}int main(int argc, char *argv[]){  if (argc < 3)  {    std::cerr << "Usage: call pythonfile funcname [args]" << std::endl;    return 1;  }  char* module_name   = argv[1];  char* function_name = argv[2];  // Explicitly add initializers for staticly linked modules.  Pyimport_AppendInittab("hello", &inithello);  // Initialize Python.  setenv("PYTHONPATH", ".", 1);  Py_Initialize();  namespace python = boost::python;  try  {    // Convert remaining args into a Python list of integers.    python::list args;    for (int i=3; i < argc; ++i)    {      args.append(std::atoi(argv[i]));    }    // import the user requested module.    // >>> import module    python::object module = python::import(module_name);    // Invoke the user requested function with the provided arguments.    // >>> result = module.fn(*args)    python::object result = module.attr(function_name)(*python::tuple(args));    // Print the result.    std::cout << python::extract<int>(result)() << std::endl;  }  catch (const python::error_already_set&)  {    PyErr_Print();    return 1;  }  // Do not call Py_Finalize() with Boost.Python.}

内容

demo.py

import helloplanet = hello.World()planet.set('foo')def multiply(a,b):    print planet.greet()    print "Will compute", a, "times", b    c = 0    for i in range(0, a):        c = c + b    return c

用法:

$ ./a.out demo multiply 21 2fooWill compute 21 times 242

在上面的代码中,我选择使用Boost.Python而不是Python / C API,并用等效的Python代码注释C
++注释。我发现它更加简洁,出错的可能性也大大降低。如果发生Python错误,Boost.Python将引发异常,并且所有引用计数都将得到适当处理。

另外,在使用Boost.Python时,请勿调用

Py_Finalize()
。根据“嵌入-
入门”部分:

请注意,此时您不得呼叫

Py_Finalize()
停止解释器。这可能会在boost.python的未来版本中修复。



欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5620272.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存