gpt4 book ai didi

python - PyEval_GetLocals 返回全局变量?

转载 作者:太空宇宙 更新时间:2023-11-04 11:38:37 24 4
gpt4 key购买 nike

我试图从使用 boost.python 导出的 C++ 类的构造函数访问 python 局部变量,但 PyEval_GetLocals() 似乎返回全局而不是局部字典。一个例子:在 C++ 中我做

class X {
public:
X() {
boost::python::object locals(boost::python::borrowed(PyEval_GetLocals()));
locals["xyz"]=42
}
};

BOOST_PYTHON_MODULE(test) {
class_<X>("X", init<>());
}

如果我现在用 Python 做

x = X()
print(xyz)

我得到“42”作为输出(如预期的那样)。然而,同样的事情发生在

def fun():
x = X()

print(xyz)

它也打印“42”,尽管“fun()”已经创建了一个新的作用域。我原以为 'xyz' 名称在 fun() 退出后再次超出范围,因此在我到达打印语句时留下未定义的 'xyz'。

我做错了什么?有什么方法可以从 C++ 对象或函数中访问本地名称?

最佳答案

我认为测试用例可能会导致误报。您是否可能在调用 fun() 之前忘记了 del xyz 变量?

定义一个函数会创建一个局部于当前作用域的变量,该变量引用该函数对象。例如:

def fun():
x = X()

创建一个 function 对象,该对象由当前范围内的 fun 变量引用。如果调用该函数,则(默认情况下)创建一个新的局部作用域,其中从 X() 返回的对象将在局部作用域内被 x 引用函数的一部分,而不是在调用者框架的 locals() 内。


下面是一个基于原始代码的例子:

#include <boost/python.hpp>

/// @brief Mockup types.
struct X
{
X()
{
// Borrow a reference from the locals dictionary to create a handle.
// If PyEval_GetLocals() returns NULL, then Boost.Python will throw.
namespace python = boost::python;
python::object locals(python::borrowed(PyEval_GetLocals()));

// Inject a reference to the int(42) object as 'xyz' into the
// frame's local variables.
locals["xyz"] = 42;
}
};

BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<X>("X", python::init<>());
}

断言可见性的交互式用法:

>>> import example
>>> def fun():
... assert('xyz' not in locals())
... x = example.X()
... assert('xyz' in locals())
... assert('xyz' not in globals())
...
>>> assert('xyz' not in globals())
>>> fun()
>>> assert('xyz' not in globals())
>>> x = example.X()
>>> assert('xyz' in globals())
>>> del xyz
>>> fun()
>>> assert('xyz' not in globals())

为了完整起见,一个FuncionType可以用 CodeType 构建谁的co_flags没有设置 newlocals 标志,导致用于函数调用的框架的 locals() 返回与 globals() 相同的结果.这是一个交互式使用示例,演示了这一点:

>>> def fun():
... x = 42
... print "local id in fun:", id(locals())
...
>>> import types
>>> def no_locals(fn):
... func_code = fn.func_code
... return types.FunctionType(
... types.CodeType(
... func_code.co_argcount,
... func_code.co_nlocals,
... func_code.co_stacksize,
... func_code.co_flags & ~2, # disable newlocals
... func_code.co_code,
... func_code.co_consts,
... func_code.co_names,
... func_code.co_varnames,
... func_code.co_filename,
... func_code.co_name,
... func_code.co_firstlineno,
... func_code.co_lnotab),
... globals())
...
>>> id(globals())
3075430164L
>>> assert('x' not in locals())
>>> fun()
local id in fun: 3074819588
>>> assert('x' not in locals())
>>> fun = no_locals(fun) # disable newlocals flag for fun
>>> assert('x' not in locals())
>>> fun()
local id in fun: 3075430164
>>> assert('x' in locals())
>>> x
42

即使禁用了 newlocals 标志,我也不得不在 fun() 中调用 locals() 来观察 x 被插入到全局符号表中。

关于python - PyEval_GetLocals 返回全局变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22285320/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com