上篇: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 test
Locals = {'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 test Locals = {'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 2310858531600
822
>>> Enclose_Func(322)
yvivid's test Locals = {'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 2310858531920
822
可以看到 運行兩次,其中 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)>}
>>> i
Traceback (most recent call last):
File "<pyshell#99>", line 1, in <module>
i
NameError: 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
