【问题标题】:What's the difference between globals(), locals(), and vars()?globals()、locals() 和 vars() 有什么区别?
【发布时间】:2011-12-19 16:12:28
【问题描述】:

globals()locals()vars() 有什么区别?他们返回什么?更新结果有用吗?

【问题讨论】:

  • 可以在 python 3 中更新任何这些并让脚本真正工作吗?

标签: python


【解决方案1】:

每个都返回一个字典:

  • globals() always 返回 module 命名空间的字典
  • locals() always 返回 当前 命名空间的 a 字典
  • vars() 返回一个当前命名空间的字典(如果不带参数调用)或参数的字典。

localsvars 可以使用更多解释。如果在函数内部调用locals(),它会使用当前局部变量命名空间(加上任何闭包变量)的值更新字典并返回它。在同一个堆栈帧中多次调用locals() 每次都会返回相同的字典——它作为f_locals 属性附加到堆栈帧对象。 dict 的内容会在每个locals() 调用和每个f_locals 属性访问时更新,但 在此类调用或属性访问时更新。变量赋值时不会自动更新,在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 条目,即使我们没有保存返回值。第三个和第四个prints表示赋值变量不会更新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__ 中没有任何局部变量。

【讨论】:

  • 部分“以及对字典的任何分配都不会反映在实际的本地命名空间中”可能会写成a bit to definite
  • 奇怪的是,如果您使用 eval(),您可以访问添加到函数内调用的 vars()locals() 字典中的变量。例如:def test(): huh = locals(); huh['d'] = 4; print eval('d') 在执行 test() 时打印 4!
  • 实际上分配给dict(由locals()返回)恰好反映在本地命名空间中,而对本地命名空间的更改恰好反映在dict中(在我的python中) .唯一的问题是规范不保证这种行为。
  • 术语 name scope 的用法对我来说似乎比 namespace 更容易。
  • @overexchange: import this 和谷歌site:docs.python.org namespace
猜你喜欢
  • 2014-06-01
  • 2019-07-20
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 2011-11-17
  • 2015-05-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多