对于从其他语言转到Python的人来说,下面这段代码显得很诡异:
1 2 3 |
for i in range(3): print(i) print(i) |
你期望的是i
变量不存在报错,而实际上打印结果是:
1 2 3 4 |
0 1 2 2 |
这是因为,在Pyhton中,是没有block这个概念的。
Python中的作用域只有四种,即LEGB规则:
L, local – 在lambda函数内或者def函数内部的变量
E, Enclosing-function – 闭包的作用域(了解Python的闭包可以看《闭包初探》)
G,Global – 全局作用域
B, Build-in – 内建作用域
举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
In [3]: def func(): ...: a = 1 # Local ...: def inner(): ...: print(a) # 和外部函数的a构成了闭包 ...: foo = 'hello' # 这里foo是local局部变量 ...: for foo in ["hello", "python"]: # for循环并没有作用域,foo也是局部变量,会覆盖上面的foo ...: print(foo) ...: print(foo) # 局部变量foo依然存在,打印"python" ...: global s # s变成全局变量 ...: s = 12 ...: inner() ...:
In [4]: func() 1 hello python python
In [5]: s Out[5]: 12 |
由此看来,for循环的作用域会污染局部作用域,Python2的列表生成式也会有这个副作用,但是已经在Python3中得到了修复。