Boost python,使用命名空间调用函数对象

Posted

技术标签:

【中文标题】Boost python,使用命名空间调用函数对象【英文标题】:Boost python, calling function objects with a namespace 【发布时间】:2013-05-10 16:05:07 【问题描述】:

我正在使用 boost python 在我的 C++ 应用程序中嵌入 python。

我希望能够调用 boost python 函数对象,并将全局名称空间与该函数调用相关联。具体简化后的相关代码为:

bp::object main = bp::import("__main__");
bp::object main_namespace = main.attr("__dict__");


//Put the function name runPyProg in the main_namespace

bp::object PyProg = exec(
        "import cStringIO\n"
        "import sys\n"
        "sys.stderr = cStringIO.StringIO()\n"
        "def runPyProg(exp):\n"
        "    print exp\n"
        "    exec(exp)\n"
        "    return\n"
        "\n",main_namespace);

//Now call the python function runPyProg with an argument

bp::object py_fn = main.attr("runPyProg");
py_fn(expStr)

我知道当我使用 boost python exec() 函数时,我可以在全局命名空间中发送,如上所示。我的问题是当我调用 py_fn 时如何将 main_namespace 与 python 函数相关联?我的最终目标是将来自 runPyProg 的局部变量放在 main_namespace 中。

谢谢。

【问题讨论】:

【参考方案1】:

如果我正确理解了这个问题,那么它应该像指定exec 将在其中执行的上下文一样简单。函数或方法可以通过globals() 访问定义它的命名空间。因此,从runPyProg() 中调用globals() 将返回与main_namespace 等效的Python。此外,exec 接受两个可选参数:

第一个参数指定将用于globals() 的字典。如果省略第二个参数,则它也用于locals()。 第二个参数指定将用于locals() 的字典。 exec 中发生的变量更改将应用​​于 locals()

因此,改变:

exec exp

exec exp in globals()

它应该提供所需的行为,其中exp 可以与main_namespace 中的全局变量交互。


这是一个基本的例子:

#include <boost/python.hpp>

int main()

  Py_Initialize();

  namespace python = boost::python;
  python::object main = python::import("__main__");
  python::object main_namespace = main.attr("__dict__");

  //Put the function name runPyProg in the main_namespace
  python::exec(
    "def runPyProg(exp):\n"
    "    print exp\n"
    "    exec exp in globals()\n"
    "    return\n"
    "\n", main_namespace);

  // Now call the python function runPyProg with an argument
  python::object runPyProg = main.attr("runPyProg");

  // Set x in python and access from C++.
  runPyProg("x = 42");
  std::cout << python::extract<int>(main.attr("x")) << std::endl;

  // Set y from C++ and access within python.
  main.attr("y") = 100;
  runPyProg("print y");

  // Access and modify x in python, then access from C++.
  runPyProg("x += y");
  std::cout << python::extract<int>(main.attr("x")) << std::endl;

注释输出:

x = 42          // set from python
42              // print from C++
                // y set to 100 from C++
print y         // print y from python
100             //
x += y          // access and modify from python
142             // print x from C++

【讨论】:

所以我意识到,如果我有一个 C++ 类 PyExpression,并且该类的每个实例调用 boost python exec() 来执行自己的表达式,那么所有实例实际上都使用相同的全局命名空间.有没有办法将命名空间的范围保留到 PyExpression 的每个 C++ 实例?当我尝试传入未初始化为 main.attr("dict") 的 boost::python::object 时,exec() 会引发错误。 @user773494:命名空间只是 Python 中的字典。要么更新 runPyProg 以接受它将在其中执行表达式的命名空间(可能是 PyExpression 实例上的 __dict__ 对象),或者使用 inspect 模块从堆栈中提取所需的命名空间。 您能指出一个发送 PyExpression 字典的工作示例吗?很难在网上找到任何东西。我基本上已经使用BOOST_PYTHON_MODULE(PyExpression) 公开了 PyExpression 类我正在导入模块并获取命名空间,例如 bp::object thisExpModule = bp::object( (bp::handle&lt;&gt;(PyImport_ImportModule("PyExpression"))) );bp::object instance_namespace = thisExpModule.attr("__dict__"); 当我发送 instance_namespace 时,它​​可以作为字典命名空间工作,但 PyExpression 的所有实例再次修改同一个对象。 Tnx! @user773494:由于import behavior,Python 模块本质上是单例的。如果您在PyExpression 模块中有一个Foo 类,那么PyExpression.__dict__ 就是模块命名空间。另一方面,a, b = PyExpression.Foo(), PyExpression.Foo()a.__dict__b.__dict__ 是特定于每个实例的命名空间。如果您需要更多帮助来获得工作示例,请考虑使用相关代码创建一个新问题。 谢谢 Tanner,我在这里开了一个新帖子 link

以上是关于Boost python,使用命名空间调用函数对象的主要内容,如果未能解决你的问题,请参考以下文章

Boost.Python:匹配 C++ 模板类型的嵌套命名空间

boost python,使用除 main global 之外的命名空间

11.11函数对象,名称空间,作用域,命名关键字参数

Boost.Python 从 C++ 创建对现有 Python 对象的新引用

python3命名空间与作用域,闭包函数,装饰器

Python面向对象之反射