Python 变量作用域 LEGB (下)
上篇:Python 变量作用域 LEGB (上)—— Local,Global,Builtin
https://www.cnblogs.com/yvivid/p/python_LEGB_1.html
下篇 没想到 拖这么久,距离上篇完成 都一年多了。
一、闭包常规形态下的 locals作用域
典型的闭包 如下:
def outer(x = 3): def inner(y): print("yvivid's test") print("Locals =", locals()) print("Globals =", globals()) return x+y return inner
运行结果如下:
>>> Enclose_Func = outer(73)>>> Enclose_Func(10)yvivid's testLocals = {'y': 10, 'x': 73}Globals = {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'outer': <function outer at 0x0000018AFDB0CD90>, 'Enclose_Func': <function outer.<locals>.inner at 0x0000018AFB091EA0>}83
可以看到,在 闭包内查看 locals() 时,可以看到 x 和 y。
为了进一步看,x 和 y 是否变化,yvivid将代码变更为如下:
def outer(x = 3): def inner(y): print("yvivid's test") print("Locals =", locals()) print("Globals =", globals()) print(id(x), id(y)) return x + y return inner
即,仅增加了 id 的判定。考虑到 python 数字引用机制,使用大于255的数字进行测试。
运行结果如下:
>>> Enclose_Func = outer(500)>>> Enclose_Func(322)yvivid's testLocals = {'y': 322, 'x': 500}Globals = {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'outer': <function outer at 0x0000021A09E8CD90>, 'Enclose_Func': <function outer.<locals>.inner at 0x0000021A09E86158>}2310858531312 2310858531600822
>>> Enclose_Func(322)yvivid's testLocals = {'y': 322, 'x': 500}Globals = {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'outer': <function outer at 0x0000021A09E8CD90>, 'Enclose_Func': <function outer.<locals>.inner at 0x0000021A09E86158>}2310858531312 2310858531920822
可以看到 运行两次,其中 id(y) 是不变更的,而 id(x) 发生了变更,因此 每次 x 是作为形参传入的。而 y 是在 Enclose_Func = outer(500) 时 确定的。
二、闭包特殊形态下的 locals作用域
在 Python 中 部分特殊的 闭包形式。
1、列表推导
>>> [ 'Locals =' + repr(locals()) for i in range(4)]["Locals ={'i': 0, '.0': <range_iterator object at 0x000002C2563CE330>}", "Locals ={'i': 1, '.0': <range_iterator object at 0x000002C2563CE330>}", "Locals ={'i': 2, '.0': <range_iterator object at 0x000002C2563CE330>}", "Locals ={'i': 3, '.0': <range_iterator object at 0x000002C2563CE330>}"] >>> print("Globals =", globals())'Globals =', {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>} >>> iTraceback (most recent call last):File "<pyshell#99>", line 1, in <module>iNameError: name 'i' is not defined
可以看到 在yvivid做的 列表推导测试中,globals() 中 是看不到 列表推导中 变量 i 的。
这个和 for 循环有很大的不同。
2、生成器
yvivid_generator = ('Locals =' + repr(locals()) for i in range(4))
3、集合推导
yvivid_set = {'Locals =' + repr(locals()) for i in range(4)}
-------
A、代码 都基于 Python 3.6 环境。
B、参考书籍 《Python学习手册(第四版)》
【原创文档,引用请声明出处,yvivid】https://www.cnblogs.com/yvivid/p/python_LEGB_2.html
赞 (0)