我试图从使用boost.python导出的C ++类的构造函数中访问python本地,但PyEval_GetLocals()似乎返回全局而不是本地dict。一个例子:在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()'创造了一个新的范围。我希望在fun()退出后,'xyz'名称再次超出范围,因此在我到达print语句时会留下未定义的'xyz'。
我做错了什么?有没有办法从C ++对象或函数中访问本地名称?
答案 0 :(得分:1)
我认为测试用例可能会导致误报。您是否可能在致电del
之前忘记了xyz
fun()
变量?
定义函数会创建一个本地范围的变量,该变量引用函数对象。例如:
def fun():
x = X()
创建当前范围内function
变量引用的fun
对象。如果调用该函数,则(默认情况下)创建一个新的本地作用域,其中X()
返回的对象将在函数的本地范围内由x
引用,而不是在调用者的范围内。 frame的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
标记后,我也必须在locals()
内调用fun()
来观察x
是否已插入全局符号表。