获取当前作用域内所有变量及其值的字典

51 投票
6 回答
25614 浏览
提问于 2025-04-15 12:29

考虑一下这个代码片段:

globalVar = 25

def myfunc(paramVar):
    localVar = 30
    print "Vars: {globalVar}, {paramVar}, {localVar}!".format(**VARS_IN_SCOPE)

myfunc(123)

这里的 VARS_IN_SCOPE 是我想要的字典,它会包含 globalVarparamVarlocalVar 等变量。

我想要在字符串中引用所有当前可用的变量。所以我期望的输出是:

Vars: 25, 123, 30

我可以通过将 **dict(globals().items() + locals().items()) 传递给 format() 来实现这一点。这种做法总是正确的吗?还是说在某些特殊情况下,这个表达式会处理得不对?

重新写了以澄清问题。

6 个回答

2

你可以自己做一个:

allvars = dict()
allvars.update(globals())
allvars.update(locals())

或者把前两行合起来:

allvars = dict(globals())
allvars.update(locals())
8

这段代码是你想要的效果吗?

d = dict(globals())
d.update(locals())

如果我理解文档没错,你是先复制了一份 globals() 字典,然后把重复的变量覆盖掉,同时从 locals() 字典里插入新的条目(因为在你的作用域内,locals() 的优先级应该更高)。


我一直没能成功让一个函数返回调用函数作用域内的所有变量字典。下面是代码(我只是用 pprint 来让输出看起来更好看):

from pprint import *

def allvars_bad():
    fake_temp_var = 1
    d = dict(globals())
    d.update(locals())
    return d

def foo_bad():
    x = 5
    return allvars_bad()

def foo_good():
    x = 5
    fake_temp_var = "good"
    d = dict(globals())
    d.update(locals())
    return d

pprint (foo_bad(), width=50)
pprint (foo_good(), width=50)

这是输出结果:

 {'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d316ec>,
 '__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': None,
 '__file__': 'temp.py',
 '__name__': '__main__',
 '__package__': None,
 'allvars_bad': <function allvars_bad at 0xb7d32b1c>,
 'd': <Recursion on dict with id=3084093748>,
 'fake_temp_var': 1,
 'foo_bad': <function foo_bad at 0xb7d329cc>,
 'foo_good': <function foo_good at 0xb7d32f0c>,
 'isreadable': <function isreadable at 0xb7d32c34>,
 'isrecursive': <function isrecursive at 0xb7d32c6c>,
 'pformat': <function pformat at 0xb7d32bc4>,
 'pprint': <function pprint at 0xb7d32b8c>,
 'saferepr': <function saferepr at 0xb7d32bfc>}
{'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d316ec>,
 '__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': None,
 '__file__': 'temp.py',
 '__name__': '__main__',
 '__package__': None,
 'allvars_bad': <function allvars_bad at 0xb7d32b1c>,
 'd': <Recursion on dict with id=3084093884>,
 'fake_temp_var': 'good',
 'foo_bad': <function foo_bad at 0xb7d329cc>,
 'foo_good': <function foo_good at 0xb7d32f0c>,
 'isreadable': <function isreadable at 0xb7d32c34>,
 'isrecursive': <function isrecursive at 0xb7d32c6c>,
 'pformat': <function pformat at 0xb7d32bc4>,
 'pprint': <function pprint at 0xb7d32b8c>,
 'saferepr': <function saferepr at 0xb7d32bfc>,
 'x': 5}

注意,在第二个输出中,我们覆盖了 fake_temp_var,而且 x 也在里面;第一个输出只包含了 allvars_bad 作用域内的局部变量。

所以如果你想访问完整的变量作用域,就不能把 locals() 放在另一个函数里。


我曾经怀疑有某种框架对象,只是不知道去哪里找。

我相信这个代码符合你的要求:

def allvars_good(offset=0):
    frame = sys._getframe(1+offset)
    d = frame.f_globals
    d.update(frame.f_locals)
    return d


def foo_good2():
    a = 1
    b = 2
    return allvars_good()

-->

{'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d6474c>,
 '__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': None,
 '__file__': 'temp.py',
 '__name__': '__main__',
 '__package__': None,
 'a': 1,
 'allvars_bad': <function allvars_bad at 0xb7d65b54>,
 'allvars_good': <function allvars_good at 0xb7d65a04>,
 'b': 2,
 'foo_bad': <function foo_bad at 0xb7d65f44>,
 'foo_good': <function foo_good at 0xb7d65f7c>,
 'foo_good2': <function foo_good2 at 0xb7d65fb4>,
 'isreadable': <function isreadable at 0xb7d65c6c>,
 'isrecursive': <function isrecursive at 0xb7d65ca4>,
 'pformat': <function pformat at 0xb7d65bfc>,
 'pprint': <function pprint at 0xb7d65bc4>,
 'saferepr': <function saferepr at 0xb7d65c34>,
 'sys': <module 'sys' (built-in)>}
46

合并两个字典的最佳方法是使用 dict(globals(), **locals()),这样局部变量会覆盖全局变量。

不过,合并全局变量和局部变量的方法有两个地方需要注意:第一,内置变量(builtins)没有被考虑进去。我想这可能是故意的,因为你可能不把内置变量当作“变量”来看待……但如果你愿意,它们也可以算作变量!第二,如果你在一个嵌套函数中,任何在外层函数中定义的局部变量(没有很好的方法可以获取这些变量的字典),而且只有在嵌套函数中明确使用的变量,也就是“自由变量”,才会在闭包中保留下来。

我想这些问题对于你打算使用的场景来说并不算大问题,但你提到了“边缘情况”;-)。如果你需要处理这些情况,有办法获取内置变量(这很简单),以及(不那么简单的)所有的闭包变量(来自外层函数的变量,前提是你在嵌套函数中明确提到它们——可以用 thefunction.func_code.co_freevars 获取变量名,thefunction.func_closure 获取闭包,使用 cell_contents 获取每个闭包的值)。不过,记住,这些变量只会是那些在你的嵌套函数代码中被明确访问的外层函数的变量!

撰写回答