Boost.python 将对象拉取到本地范围内以进行读取访问
Boost.python pull object into local scope for read access
我正在使用Boost.Python将C++函数导出到Python。在这个函数中,我想访问本地堆栈帧上的 Python 对象,而不需要在 Python 端访问这个对象。
示例:我有一个C++对象X
和一个C++函数cppfun
导出到 Python,然后按照代码,
x = X()
def fun():
cppfun()
# no explicit access to x
在cppfun
内部,我可以使用 PyEval_GetLocals
访问本地堆栈帧,但由于Python 端不包含任何对 x
的引用,这个对象不会在该本地堆栈帧中(类似地,如果你print(locals())
fun
内部,x
将不存在,除非你添加对它的引用,例如 print(x)
)。
有什么方法可以在cppfun
内部访问x
,也就是说,我可以以某种方式强制 Python 将其拉入locals
而不在 Python 端的fun
内访问它吗?我尝试简单地运行boost::python::eval("x")
但这也在错误的范围内运行。
添加:所以我不想让外框架的x
在fun
或类似的东西中可写(我知道这是不可能的); 这个问题纯粹是关于如何从外部框架获得对变量的读取访问权限,而无需在 Python 端访问它。
可以通过使用 PyEval_GetGlobals()
来访问外部作用域,它返回当前执行帧中全局变量的字典。 它与 Python 内置的 globals()
函数非常相似,后者返回定义函数的模块的全局符号表。 但是,标准模块和扩展模块之间的帧堆栈处理方式略有不同。 对于扩展模块,当前执行帧是调用方,因此PyEval_GetGlobals()
将返回调用方模块的全局符号,而不是扩展模块的全局符号。
或者,可以通过PyEval_GetFrame()
获取当前帧的句柄,然后遍历堆栈,检查每个帧的本地(f_local
)和全局(f_global
)字典。
这是一个完整的最小示例,演示了这两种技术以及它们之间的细微差异。 在示例中,get_global()
将使用PyEval_GetGlobals()
,search_stack_locals()
将检查堆栈中每个帧的本地字典。
#include <boost/python.hpp>
namespace detail {
/// @brief Return a handle to a global variable. If one is not found, then
/// None is returned.
boost::python::object get_global(std::string name)
{
// Borrow a reference from the locals dictionary to create a handle.
// If PyEval_GetGlobals() returns NULL, then Boost.Python will throw.
namespace python = boost::python;
python::dict globals(python::borrowed(PyEval_GetGlobals()));
return globals.get(name);
}
/// @brief Search through the call stack for a variable. If found, the
/// object is returned. Otherwise, None.
boost::python::object search_stack_locals(std::string name)
{
// Get a handle to the current frame.
namespace python = boost::python;
python::object frame(python::borrowed(
reinterpret_cast<PyObject*>(PyEval_GetFrame())));
// Iterate through the stack's frames until the variable has been found
// or the stack has been exhausted.
while (frame)
{
// If the current frame has the desired variable, then return it.
python::dict locals(frame.attr("f_locals"));
if (locals.has_key(name))
{
return locals.get(name);
}
// Move up the stack.
frame = frame.attr("f_back");
}
// Return None
return python::object();
}
} // namespace detail
/// @brief Mockup function to demonstrate finding non-local variables.
boost::python::object cppfun(std::string name)
{
return boost::python::make_tuple(
detail::get_global(name), detail::search_stack_locals(name));
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::def("cppfun", &cppfun);
}
在spam.py
:
import example
x = 'spam.global.x'
y = 'spam.global.y'
def inner():
for name in ('x', 'y', 'z'):
print name, example.cppfun(name)
def outer():
x = 'spam.outer.x'
inner()
交互式用法:
>>> x = 'main.global.x'
>>> y = 'main.global.y'
>>> z = 'main.global.z'
>>> import spam
>>> spam.outer()
x ('spam.global.x', 'spam.outer.x')
y ('spam.global.y', 'main.global.y')
z (None, 'main.global.z')
请注意,当使用 PyEval_GetGlobals()
时,example
扩展模块使用调用方模块的全局符号表 (spam
)。 解释器主命名空间中声明的全局变量仅在迭代堆栈时找到。
- 为什么在全局范围内使用"extern int a"似乎不行?
- 错误:未在此范围内声明'reverse'
- 并行用于C++17中数组索引范围内的循环
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 不计算一个范围内的完美数
- 错误:"imread"未在此范围内声明
- 我在范围内未声明的错误类有问题
- 如何在cpp中使用地图显示给定日期范围内(在下面的问题中)的费率?
- 我有一个数组,我想输入一个范围,然后找到范围内所有偶数的总和?
- 未在此范围内声明错误 'xy'
- 在C++中使用变量而不是"#define"来指定数组大小是不是一种糟糕的做法?(C错误:在文件范围内
- 通过使用全局变量的函数访问在给定范围内被覆盖的变量
- 如何全局创建对象并使用该对象访问全局范围内的公共成员函数
- 如何在BST中从最高到最低打印特定范围内的数字,访问的节点最少
- 在文件范围内使用具有副作用的C++函数,访问singleton
- 如何访问本地范围内的全局变量
- Boost.python 将对象拉取到本地范围内以进行读取访问
- 为什么我无法在全局范围内访问我的数组下标
- Qt在其他范围内访问TextEdit的文本
- 当C++试图访问向量的元素(在范围内)时,Qt Quick Windows应用程序崩溃