1
Local 一个函数定义了一个 local 作用域; PyFrameObject 中的 f_local 属性
2 Global 一个 module 定义了一个 global 作用域; PyFrameObject 中的 f_global 属性.
3 BuiltIn open, dir 的作用域等等, python 最顶层的作用域
4 Enclosing
5 例子,
6 b = 2
7 def funcO():
8 b = 3
9 def funcI():
10 print(b)
11 return funcI
12
13 f = funcO()
14 f() #1
15
16 Output,
17 3 #1
18
19 例子的输出结果是 '3' 而不是代码块儿最外层所定义的 'b = 2'.
20 f() 实际调用的内嵌在 funcO 中的 funcI 函数. funcI 位于 funcO 之内, 所以函数 funcI 的作用域内嵌于函数 funcO 的作用域内.
21 即, 函数 funcO 的作用域是内嵌函数 funcI 的'直接外围作用域', 所以例子的结果是 '3' 而不是 '2'.
22 单纯按照代码块儿的结构来说, 在 #1 处 'b = 3' 这个约束已经不再对 'f()' 这个调用起作用, 但是从打印的结果来看显然不是这样(依然起作用).
23 Python 虚拟机在执行 'f = funcO()' 的时候会执行 'def funcI():' (因为 函数 funcO return 了 funcI 函数对象),
24 就在这个时候 约束'b = 3' 与函数对象 funcI 捆绑了一起, 并把捆绑后的街哦过返回, 这个捆绑起来的整体被称为 '闭包'('捆绑' 一词可以理解为 '直接外围作用域' 的绑定过程).
25 闭包是 LEGB 规则中的 E -> enclosing 的首字母, 表示的是 '直接外围作用域' 这个概念.
26
27 global 关键字,
28 例子,
29 c = 1
30 def func1():
31 print(c)
32
33 def func2():
34 print(c)
35 c = 3
36 print(c)
37
38 func1()
39 func2()
40
41 Output,
42 1 # func1() 的打印
43 func2() # func2() 的打印
44 print(c)
45 UnboundLocalError: local variable 'c' referenced before assignment
46
47 func1 和 func2 同是对'直接外围作用域'的搜索, 为什么一个正确搜索约束 'c = 1',另一报错呢?
48 先来了解一个名字的定义 - '最内嵌套作用域规则'.
49 最内嵌套作用域规则:由一个赋值语句引进的名字在这个赋值语句所在的作用域里是可见(起作用)的,
50 而且在其内部嵌套的每个作用域里也可见,除非它被嵌套于内部的,
51 引进同样名字的另一条赋值语句所遮蔽/覆盖。
52
53 从 exception 中得知, 变量 c 没有被定义. 上述问题就出现在'定义'的后半句,‘除非’分句 - '除非它被嵌套于内部的,
54 引进同样名字的另一条赋值语句所遮蔽/覆盖。' 恰巧紧接着报错处, 通过赋值语句引进了一个同名约束('c = 3'),进而破坏了'最内嵌套作用域规则'.
55
56 现在尝试修改这个引用错误,
57 c = 1
58 def func1():
59 print(c) #1
60
61 def func2():
62 global c #2 在引用之前通过 global 关键字指定作用域
63 print(c) #2
64 c = 3
65 print(c) #3
66
67 func1()
68 func2()
69 print(c) #4
70
71 Output,
72 1 #1
73 1 #2 python 理解了编程者的意图
74 3 #3
75 3 #4
76 进一步再看一个闭包的例子,
77 d = 1
78 def func2():
79 d = 3
80 def func2I():
81 global d
82 print(d) #1
83 d += 4 #2 重写直接外层作用域
84 print(d) #2
85 return func2I
86
87 abc = func2()
88 abc()
89 print(d) #3
90
91 Output,
92 1 #1 global 关键字 打破 LEGB 规则, 限定引用直接外层作用于
93 5 #2 直接外层作用于被重写
94 5 #3 被重写的‘直接外作用域’(代码块儿最外层的 'd = 1' 这个约束)作用于 LEGB 规则下作用域