Boost.Python教程:嵌入,从c/c++中调用python代码

26 篇文章 0 订阅

使用解释器

到现在为止,您应该知道如何使用Boost.Python从Python调用C ++代码。 但是,有时您可能需要反过来:从C ++端调用Python代码。 这需要您 Python解释器嵌入到C ++程序中。

目前,Boost.Python并不直接支持嵌入时您需要的所有内容。 因此,您需要使用Python / C API填补空白。 但是,Boost.Python已经使嵌入变得更加容易,并且在未来的版本中,根本不需要触摸Python / C API。 敬请期待... 

构建嵌入式程序

为了能够将python嵌入到程序中,您必须链接到Boost.Python以及Python自己的运行时库。

Boost.Python的库有两种变体。 两者都位于Boost的/libs/python/build/bin-stage子目录中。 在Windows上,变体称为boost_python.lib (用于发布版本)和boost_python_debug.lib (用于调试)。 如果找不到库,可能还没有构建Boost.Python。 

Python的库可以在Python目录的/libs子目录中找到。 在Windows上,它被称为pythonXY.lib,其中XY是您的主要Python版本号。

此外,必须将Python的/include子目录添加到包含路径中。

在Jamfile中,以上所有内容归结为:

projectroot c:\projects\embedded_program ; # location of the program

# bring in the rules for python
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
include python.jam ;

exe embedded_program # name of the executable
  : #sources
     embedded_program.cpp
  : # requirements
     <find-library>boost_python <library-path>c:\boost\libs\python
  $(PYTHON_PROPERTIES)
    <library-path>$(PYTHON_LIB_PATH)
    <find-library>$(PYTHON_EMBEDDED_LIBRARY) ;

入门

能够构建很好,但还没有什么可以构建。 将Python解释器嵌入到您的一个C ++程序中需要以下4个步骤:

  1. #include <boost/python.hpp>
  2. 调用Py_Initialize ()来启动解释器并创建__main__模块。
  3. 调用其他Python C API例程来使用解释器。
[注意]注意

请注意,此时您不能调用Py_Finalize ()来停止解释器。 这可以在boost.python的未来版本中修复。

(当然,在所有这些步骤之间可以有其他C ++代码。)

现在我们可以将解释器嵌入到我们的程序中,让我们看看如何使用它...

使用解释器

您可能已经知道,Python中的对象是引用计数的。 当然,Python C API的PyObject也是引用计数的。 但是有一点不同。 虽然引用计数在Python中是完全自动的,但Python C API要求您手动完成 。 这很麻烦,特别是在C ++异常存在的情况下很难做到。 幸运的是,Boost.Python提供了句柄对象类模板来自动化该过程。

运行Python代码

Boost.python提供了三个相关的函数来从C ++运行Python代码。

object eval(str expression, object globals = object(), object locals = object())
object exec(str code, object globals = object(), object locals = object())
object exec_file(str filename, object globals = object(), object locals = object())

eval计算给定的表达式并返回结果值。 exec执行返回结果的给定代码(通常是一组语句),exec_file执行给定文件中包含的代码。

globalslocals参数是Python字典,包含运行代码的上下文的全局变量和局部变量。 对于大多数意图和目的,您可以使用__main__模块的命名空间字典作为两个参数。

Boost.python提供了导入模块的功能:

object import(str name)

import导入python模块(可能首先将其加载到正在运行的进程中),然后返回它。

让我们导入__main__模块并在其命名空间中运行一些Python代码:

object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");

object ignored = exec("hello = file('hello.txt', 'w')\n"
                      "hello.write('Hello world!')\n"
                      "hello.close()",
                      main_namespace);

这应该在当前目录中创建一个名为“hello.txt”的文件,其中包含编程圈中众所周知的短语。

操纵Python对象

通常我们想要一个类来操作Python对象。 但是我们已经在上面看过这样一个类,在上一节中 :恰当命名的object类及其派生类。 我们已经看到它们可以用handle构造。 以下示例应进一步说明这一事实:

object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
object ignored = exec("result = 5 ** 2", main_namespace);
int five_squared = extract<int>(main_namespace["result"]);

这里我们为__main__模块的命名空间创建一个字典对象。 然后我们将5平方分配给结果变量并从字典中读取该变量。 另一种实现相同结果的方法是使用eval代替,它直接返回结果:

object result = eval("5 ** 2");
int five_squared = extract<int>(result);

异常处理

如果在评估python表达式时发生异常,则抛出error_already_set :

try
{
    object result = eval("5/0");
    // execution will never get here:
    int five_divided_by_zero = extract<int>(result);
}
catch(error_already_set const &)
{
    // handle the exception in some way
}

error_already_set异常类本身不携带任何信息。 要了解有关发生的Python异常的更多信息,您需要在catch语句中使用Python C API的异常处理函数 。 这可以像调用PyErr_Print()将异常的回溯打印到控制台,或者将异常的类型与标准异常的类型进行比较一样简单:

catch(error_already_set const &)
{
    if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError))
    {
        // handle ZeroDivisionError specially
    }
    else
    {
        // print all other errors to stderr
        PyErr_Print();
    }
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

道格拉斯范朋克

播种花生牛奶自留田

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值