LEGB法则
python变量的作用域遵从LEGB法则,即:
- Local(L):定义在方法或类内部的变量,如 def 或 lambda 函数内部
- Enclosed(E):闭包内部变量(仅限闭包)
- Global(G):全局变量
- Built-in(B):python内置的关键字

对任意一个变量,python会按照上述顺序依次查找
这意味着python中有且仅有这四个作用域,最小作用域范围就是方法,而没有其他语言中的块作用域,例如下述代码:
def func():
if True:
v = 'bingo'
print(v)
这段代码如果在java中执行就会无法编译,因为v的作用域局限在if的代码块中。而在python中就不会,因为python的最小作用域是func。同样,对于for、while这些代码块也是没有作用域的
闭包
英文名为 enclosing function,我更喜欢称之为“嵌套函数”,因为其本身就是“函数内部定义的函数”
def outlier():
def inner(): # 这个函数就是闭包
...
...
# 你可以在outlier函数内部直接调用inner函数,也可以直接将inner函数作为返回值
这样做的目的是什么呢?我觉得就是创建出一个作用域。如果不看python内置变量的话,在没有闭包的情况下,python仅仅只有两个作用域,对于一个变量,要么在func内部找,要么去全局里面找。这样做的话,对于func内部变量还好说,因为变量已经被func根据不同的功能隔离开了,但对于全局变量的管理就比较混乱了,各种不同功能的全局变量一股脑都在全局环境中。但引入闭包就不同了,它又将func视作一个全局变量环境(仅针对闭包来说),一层一层嵌套,就能更好地管理“全局变量”(并非真的全局变量,仅仅对闭包而言)
这就好比是:在以前,村民有什么问题都去找酋长。现在这种责任关系通过进一步的细分,村民有问题找村长,村长解决不了找县长,县长解决不了找市长。。。
一个综合一点的题目
为什么输出结果是这样?
arr = []
for i in range(3):
def inner(num):
return num * i
arr.append(inner)
for func in arr:
print(func(2))
# 输出结果:4 4 4
分析:
从作用域来说,由于for是没有作用域的,故代码其实等价于:
arr = []
i = 0 # 由于for没有定义域,故for内部定义的变量i等价于在外部定义
def inner(num): # 由于for没有定义域,故for内部定义的函数inner等价于在外部定义
return num * i
for counter in range(3): # for会先给外部变量i赋值,再将函数添加到arr中
i = counter
arr.append(inner)
for func in arr:
print(func(2))
看到没,对于函数inner来说,i就是全局变量,而对于main来说,它是局部变量。这个作用域太大了,而我们仅仅是希望将其限制在for和inner之间。所以,一个解决方法是使用闭包:
arr = []
for i in range(3):
def outlier(idx): # 使用闭包增加一个作用域
def inner(num):
return num * idx
return inner
arr.append(outlier(i)) # i这个变量将被储存在该作用域内
for func in arr:
print(func(2))
这又有点像docker这种容器化技术了,原本我使用物理机完成某件事,但所有资源放在物理机上不好管理,我就可以创造出很多的容器,每个容器依照功能不同可以传递不同的参数,该参数在整个容器中生效。