Globals ()、 local ()和 vars ()之间的区别是什么?

globals()locals()vars()之间的区别是什么?他们返回什么?更新结果是否有用?

71685 次浏览

每一种都会返回一本字典:

  • globals() 一直都是返回 模组命名空间的字典
  • locals() 一直都是返回 目前命名空间的 字典
  • vars()返回当前名称空间的 或者字典(如果没有参数调用)或参数的 字典。

localsvars可能需要更多的解释。如果在函数内部调用了 locals(),它会使用当前局部变量名称空间(加上任何闭包变量)的值更新一个 dict,并返回它。对同一堆栈帧中的 locals()的多个调用每次都返回相同的 dict- 它作为其 f_locals属性附加到堆栈帧对象。在每个 locals()调用和每个 f_locals属性访问上,dict 的内容都会更新,但在这样的调用或属性访问上,则更新为 只有。当变量被赋值时,它不会自动更新,而且在 dict 中赋值的条目也不会赋值相应的局部变量:

import inspect


def f():
x = 1
l = locals()
print(l)
locals()
print(l)
x = 2
print(x, l['x'])
l['x'] = 3
print(x, l['x'])
inspect.currentframe().f_locals
print(x, l['x'])


f()

给我们:

{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2

第一个 print(l)只显示一个 'x'条目,因为对 l的赋值发生在 locals()调用之后。第二个 print(l)在再次调用 locals()之后显示一个 l条目,尽管我们没有保存返回值。第三个和第四个 print显示赋值变量不更新 l,反之亦然,但是在我们访问 f_locals之后,局部变量又被复制到 locals()中。

两个注意事项:

  1. 此行为是 CPython 特有的——其他 Python 可能允许更新自动返回到本地名称空间。
  2. 在 CPython 2.x 中,可以通过在函数中放入一行 exec "pass"来实现这一点。这将函数切换到一个较老的、较慢的执行模式,该模式使用 locals() dict 作为局部变量的规范表示。

如果 locals()被称为 在外面函数,它将返回当前名称空间的实际字典。对字典中反映的名称空间 的进一步更改,以及对名称空间中反映的字典 的更改:

class Test(object):
a = 'one'
b = 'two'
huh = locals()
c = 'three'
huh['d'] = 'four'
print huh

给我们:

{
'a': 'one',
'b': 'two',
'c': 'three',
'd': 'four',
'huh': {...},
'__module__': '__main__',
}

到目前为止,我所说的关于 locals()的一切对于 vars()也是正确的... ... 这里有一个区别: vars()接受一个对象作为它的参数,如果你给它一个对象,它返回该对象的 __dict__。对于一个典型的对象,它的 __dict__是它的大部分属性数据存储的地方。这包括类变量和模块全局变量:

class Test(object):
a = 'one'
b = 'two'
def frobber(self):
print self.c
t = Test()
huh = vars(t)
huh['c'] = 'three'
t.frobber()

这就给了我们:

three

注意,函数的 __dict__是它的属性名称空间,而不是局部变量。函数的 __dict__存储本地变量是没有意义的,因为递归和多线程意味着可以同时对一个函数进行多次调用,每次调用都有自己的本地变量:

def f(outer):
if outer:
f(False)
print('Outer call locals:', locals())
print('f.__dict__:', f.__dict__)
else:
print('Inner call locals:', locals())
print('f.__dict__:', f.__dict__)


f.x = 3


f(True)

这就给了我们:

Inner call locals: {'outer': False}
f.__dict__: {'x': 3}
Outer call locals: {'outer': True}
f.__dict__: {'x': 3}

在这里,f递归地调用自己,因此内部调用和外部调用重叠。每个函数在调用 locals()时都会看到自己的本地变量,但是两个调用看到的是相同的 f.__dict__,而且 f.__dict__中没有任何本地变量。