[英]How to call a python function from C++ with pybind11?
请考虑以下 C++ pybind11 程序:
#include <pybind11/embed.h>
namespace py = pybind11;
int main() {
py::scoped_interpreter guard{};
py::dict locals;
py::exec(R"(
import sys
def f():
print(sys.version)
)", py::globals(), locals);
locals["f"](); // <-- ERROR
}
py::exec
调用和封闭的import sys
调用都成功,但是调用locals["f"]()
会抛出异常:
NameError: name 'sys' is not defined
在 function f
的第一行。
预期的行为是程序打印 python 系统版本。
有任何想法吗?
更新:
我按照@DavidW 的建议修改了程序:
#include <pybind11/embed.h>
namespace py = pybind11;
int main() {
py::scoped_interpreter guard{};
py::dict globals = py::globals();
py::exec(R"(
import sys
def f():
print(sys.version)
)", globals, globals);
globals["f"](); // <-- WORKS NOW
}
现在它可以工作了。
我不是 100% 确定我理解发生了什么,所以我会很感激解释。
(特别是通用globals
/ locals
字典的修改是否会影响任何其他脚本。是否有一些全局字典是exec
脚本正在修改的 python 解释器的一部分?或者py::globals()
是否复制了它state 所以执行的脚本与其他脚本隔离?)
更新 2 :
所以看起来有全局变量和局部变量是同一个字典是默认的 state:
$ python
>>> globals() == locals()
True
>>> from __main__ import __dict__ as x
>>> x == globals()
True
>>> x == locals()
True
...并且两者的默认值是__main__.__dict__
,无论是什么( __main__.__dict__
是py::globals()
返回的字典)
我仍然不清楚__main__.__dict__
到底是什么。
所以最初的问题(在评论中解决)是具有不同的全局变量和局部变量会导致它被评估为好像它在 class 中(参见Python 文档的exec
- PyBind11 ZC1C425268E68384D1AB450 的行为基本相同)
请记住,在模块级别,全局变量和局部变量是同一个字典。 如果 exec 获得两个单独的对象作为全局对象和局部对象,则代码将被执行,就好像它嵌入在 class 定义中一样。
A function scope 不查找在其封闭的 class 中定义的变量 - 这不起作用
class C:
import sys
def f():
print(sys.version)
# but C.sys.version would work
因此您的代码不起作用。
pybind11::globals
返回一个在多个地方共享的字典:
返回表示当前执行帧中的全局变量的字典,如果没有帧(通常在嵌入解释器时),则返回
__main__.__dict__
。
因此对这本字典的任何修改都将是持久的并保持不变(这可能不是你想要的。)。 在您的情况下,它可能是__main__.__dict__
但通常“当前执行框架”可能会从调用到调用发生变化,具体取决于您跨越 C++-Python 边界的程度。 For example, if a Python function calls a C++ function that modifies globals()
then exactly what you modify depends on the caller.
我的建议是创建一个新的空dict
并将其传递给exec
。 这可确保您在全新的非共享命名空间中运行。
__main__
只是一个代表“顶级代码环境”的特殊模块。 像任何模块一样有一个__dict__
。 在 REPL 中运行时,它是全局 scope。 从pybind11
的角度来看,它只是一个带有 dict 的模块,您可能不应该随便写入它(除非您真的决定要故意放一些东西以在全球范围内共享它)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.