LEGB法则 / LEGB Rule
LEGB 变量搜索顺序
---- 来源于《Python学习手册》/ Learning Python Page 419 ----
Python 的变量名解析机制称为 LEGB 法则。
L – Local: 本地作用域;
E – Enclosing: 上一层结构中 def 或 lambda 的本地作用域;
G – Global: 全局作用域;
B – Build-in: 内置作用域。
LEGB作用域查找原则:当引用一个变量时,Python 按以下顺序依次进行查找:从本地变量中,在任意上层函数的作用域,在全局作用域,最后在内置作用域中查找。第一个能够完成查找的就算成功。变量在代码中被赋值的位置通常就决定了它的作用域。在 Python3.0 中,nonlocal 声明也可以迫使名称映射到函数内部的作用域中,而不管是否对其赋值。这些规则仅对简单的变量名有效。
下面用代码示例来说明这一查找原则。
""" Python LEGB rule: local, enclosing, global, built-in """
L 查找
定义三个函数用于测试 Local 搜索,correct 函数在调用 A 之前进行了 global 声明,调用了全局变量 A,而 error 函数在调用之前没有进行 global 声明。使用 try/except 语句对报错进行捕获处理。correct_2 函数在调用前对 A 进行赋值,因为没有进行 Global 声明此处的 A 是局部变量 A,对其赋值不影响全局变量 A。
1 # Local -- L 2 A = 7 3 def errorFuncLocal(): 4 print(‘\n-------------Func: errorFuncLocal----------------‘) 5 try: 6 print(‘The global value of A is %d‘ % A) 7 except NameError: 8 print(‘Function <errorFuncLocal> raises a NameError‘) 9 A = 6 10 11 def correctFuncLocal(): 12 print(‘\n-------------Func: correctFuncLocal------------‘) 13 global A 14 try: 15 print(‘The global value of A is %d‘ % A) 16 except NameError: 17 print(‘Function <correctFuncLocal> raises a NameError‘) 18 # A = 6 19 20 def correctFuncLocal_2(): 21 print(‘\n-------------Func: correctFuncLocal_2------------‘) 22 A = 5 23 try: 24 print(‘The local value of A is %d‘ % A) 25 except NameError: 26 print(‘Function <correctFuncLocal> raises a NameError‘)
Note: 在 errorFuncLocal 函数中,需要在局部变量中对变量 A 进行操作,否则局部没有变量 A 的操作,则 L 搜索找不到 A,而 G 搜索中会找到 A,从而引入全局变量 A,而无法引发局部变量 A 的 NameError。
1 if __name__ == ‘__main__‘: 2 errorFuncLocal() 3 correctFuncLocal() 4 correctFuncLocal_2() 5 print(‘The global value of A is %d‘ % A)
运行上面的代码可以得到输出为,
-------------Func: errorFuncLocal---------------- Function <errorFuncLocal> raises a NameError -------------Func: correctFuncLocal------------ The global value of A is 7 -------------Func: correctFuncLocal_2------------ The local value of A is 5 The global value of A is 7
可以看到,
errorFuncLocal 函数中由于没有进行 global 声明,且又对变量 A 进行了赋值,最终导致了错误异常,
correctFuncLocal 函数中进行了 global 声明,因此没有产生报错,
correctFuncLocal_2 函数中,定义了 A 实际上是一个局部变量,可以看到,在函数内部 A 为 5,但函数外部的全局变量 A 依旧为 7,在使用时 L 搜索优先找到的是局部变量的 A。
E 查找
再定义两个函数用于测试 Enclosing 搜索,
1 # Enclosing -- E 2 A = 7 3 def errorFuncEnclosing(): 4 print(‘\n-------------Func: errorFuncEnclosing-----------‘) 5 def foo(): 6 print(‘The enclosing value of A is %d‘ % A) 7 try: 8 foo() 9 A = 6 10 except NameError: 11 print(‘Function <errorFuncEnclosing> raises a NameError‘) 12 13 def correctFuncEnclosing(): 14 print(‘\n-------------Func: correctFuncEnclosing-----------‘) 15 def foo(): 16 print(‘The enclosing value of A is %d‘ % A) 17 try: 18 A = 6 19 foo() 20 except NameError: 21 print(‘Function <errorFuncEnclosing> raises a NameError‘)
运行函数
1 if __name__ == ‘__main__‘: 2 errorFuncEnclosing() 3 correctFuncEnclosing() 4 print(‘The global value of A is %d‘ % A)
最终输出的结果如下,由于correct 函数的内层函数调用 A 之前,在外层函数中定义了 A,从而不会引发 NameError,而 error 函数在内层函数调用A之后才对 A 进行赋值操作,Enclosing 搜索在外层函数中找到了变量 A,但是在调用之前未进行赋值操作,因此会引发一个 NameError。
-------------Func: errorFuncEnclosing----------- Function <errorFuncEnclosing> raises a NameError -------------Func: correctFuncEnclosing----------- The enclosing value of A is 6 The global value of A is 7
G 查找
定义一个函数用于验证全局变量查找,
1 # Global -- G 2 A = 7 3 4 def correctFuncGlobal(): 5 print(‘\n-------------Func: correctFuncGlobal-----------‘) 6 print(‘The global value of A is %d‘ % A)
在函数内部直接调用 A,由于 LE 搜索都没找到变量 A,而 G 搜索找到了,因此此时的变量 A 是全局变量。
-------------Func: correctFuncGlobal----------- The global value of A is 7
B 查找
最后,B 查找搜索为内建变量查找,而对于内建变量,例如 __name__,在 LEG 搜索都没找到后启用 B 搜索才可以查找到内建变量,因此可以直接引用内建变量。
1 # Built-in -- B 2 def correctFuncBuildin(): 3 print(‘\n-------------Func: correctFuncBuildin-----------‘) 4 print(‘The value of built-in variable __name__ is:‘, __name__) 5 6 if __name__ == ‘__main__‘: 7 correctFuncBuildin()
结果如下,
-------------Func: correctFuncBuildin----------- The value of build-in variable __name__ is: __main__
参考链接
http://www.jb51.net/article/84206.htm