Python的程序结构[3] -> 变量/Variable[1] -> LEGB 法则
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。
# Local -- L
A = 7
def errorFuncLocal():
print('\n-------------Func: errorFuncLocal----------------')
try:
print('The global value of A is %d' % A)
except NameError:
print('Function <errorFuncLocal> raises a NameError')
A = 6 def correctFuncLocal():
print('\n-------------Func: correctFuncLocal------------')
global A
try:
print('The global value of A is %d' % A)
except NameError:
print('Function <correctFuncLocal> raises a NameError')
# A = 6 def correctFuncLocal_2():
print('\n-------------Func: correctFuncLocal_2------------')
A = 5
try:
print('The local value of A is %d' % A)
except NameError:
print('Function <correctFuncLocal> raises a NameError')
Note: 在 errorFuncLocal 函数中,需要在局部变量中对变量 A 进行操作,否则局部没有变量 A 的操作,则 L 搜索找不到 A,而 G 搜索中会找到 A,从而引入全局变量 A,而无法引发局部变量 A 的 NameError。
if __name__ == '__main__':
errorFuncLocal()
correctFuncLocal()
correctFuncLocal_2()
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 搜索,
# Enclosing -- E
A = 7
def errorFuncEnclosing():
print('\n-------------Func: errorFuncEnclosing-----------')
def foo():
print('The enclosing value of A is %d' % A)
try:
foo()
A = 6
except NameError:
print('Function <errorFuncEnclosing> raises a NameError') def correctFuncEnclosing():
print('\n-------------Func: correctFuncEnclosing-----------')
def foo():
print('The enclosing value of A is %d' % A)
try:
A = 6
foo()
except NameError:
print('Function <errorFuncEnclosing> raises a NameError')
运行函数
if __name__ == '__main__':
errorFuncEnclosing()
correctFuncEnclosing()
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 查找
定义一个函数用于验证全局变量查找,
# Global -- G
A = 7 def correctFuncGlobal():
print('\n-------------Func: correctFuncGlobal-----------')
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 搜索才可以查找到内建变量,因此可以直接引用内建变量。
# Built-in -- B
def correctFuncBuildin():
print('\n-------------Func: correctFuncBuildin-----------')
print('The value of built-in variable __name__ is:', __name__) if __name__ == '__main__':
correctFuncBuildin()
结果如下,
-------------Func: correctFuncBuildin-----------
The value of build-in variable __name__ is: __main__
参考链接
http://www.jb51.net/article/84206.htm
Python的程序结构[3] -> 变量/Variable[1] -> LEGB 法则的更多相关文章
- Python的程序结构[3] -> 变量/Variable[0] -> 变量类型
变量类型 / Variable Type 在 Python 中,变量主要有以下几种,即全局变量,局部变量和内建变量, 全局变量 / Global Variable 通常定义于模块内部,大写变量名形式存 ...
- Python基本程序结构
条件判断: 计算机之所以能做很多自动化的任务,因为它可以自己做条件判断.比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,用if语句实现:
- 【Go语言系列】2.3、Go语言基本程序结构:变量及常量
1.什么变量 变量来源于数学,从根本上说,变量相当于是对一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后可以通过引用变量名来使用这块存储空间. 1.1变量声明 Go 语言变 ...
- Python的程序结构[4] -> 函数/Function[2] -> 匿名函数
匿名函数 / Anonymous Function 匿名函数是一种不需要绑定函数名的函数 (i.e. functions that are not bound to a name).匿名函数通过 la ...
- Python的程序结构[5] -> 模块/Module[0] -> 内建模块 builtins
builtins 内建模块 / builtins Module 在Python的模块中,有一种特殊模块,无需导入便可以使用,其中包含了许多内建函数与类. builtins 模块内容 / builtin ...
- Python的程序结构[7] -> 生成器/Generator -> 生成器浅析
生成器 / Generator 目录 关于生成器 生成器与迭代器 生成器的建立 通过迭代生成器获取值 生成器的 close 方法 生成器的 send 方法 生成器的 throw 方法 空生成器的检测方 ...
- Python的程序结构[8] -> 装饰器/Decorator -> 装饰器浅析
装饰器 / Decorator 目录 关于闭包 装饰器的本质 语法糖 装饰器传入参数 1 关于闭包 / About Closure 装饰器其本质是一个闭包函数,为此首先理解闭包的含义. 闭包(Clos ...
- Go语言程序结构之变量
初识Go语言之变量 var声明创建一个具体类型的变量,然后给它附加一个名字,设置他的初始值,这种声明都是一个通用的形式: var name type = expression 在实际的开发中,为了方便 ...
- Python的程序结构[0] -> 属性/Property[0] -> 类属性、实例属性和私有属性
类属性.实例属性和私有属性 Python中类的属性主要包括类属性,实例属性和私有属性,下面是对三种属性的简单介绍 类属性 / Class Property 类属性在__init__()之外初始化,在外 ...
随机推荐
- 剑指Offer - 九度1372 - 最大子向量和(连续子数组的最大和)
剑指Offer - 九度1372 - 最大子向量和(连续子数组的最大和)2013-11-23 16:25 题目描述: HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天JOBDU测试组开完会后, ...
- Django笔记 —— 视图
最近在学习Django,打算玩玩网页后台方面的东西,因为一直很好奇但却没怎么接触过.Django对我来说是一个全新的内容,思路想来也是全新的,或许并不能写得很明白,所以大家就凑合着看吧- 本篇笔记(其 ...
- Springboot 启动问题
每次以debug方式启动springboot之后都会在SilentExitExceptionHandler类中的throw new SilentExitException() 解决办法 :window ...
- win10系统安装之GHOST还原(转+编辑)
注意*:在以下操作中,你可能需要分区你的原来系统盘,如果是重装的话.现在我们使用SSD固态做系统盘盘,这个分区的话,点选mbr重新引导,以及对齐复选框. 如果前面过程都没问题,在安装过程中出现 ...
- 孤荷凌寒自学python第六十六天学习mongoDB的基本操作并进行简单封装5
孤荷凌寒自学python第六十六天学习mongoDB的基本操作并进行简单封装5并学习权限设置 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第十二天. 今天继续学习mongo ...
- Adaptive Boosting
Boosting boosting和bagging很类似,所使用的多个分类器类型都是一致的.另外,他们的主要区别点如下: boosting中不同的分类器是通过串行得到的,每个分类器都是根据已经训练出来 ...
- JSP/Servlet Web 学习笔记 DayFour
Servlet概述 Servelt是使用Java Servlet应用程序接口及相关类和方法的Java程序. Servlet是用Java编写的Server端程序,它与协议和平台无关.Servlet运行于 ...
- 关于ECDSA/ECC(密钥加密传输)和ECDSA/ECDH(密钥磋商)
关于ECDSA/ECC(密钥加密传输)和ECDSA/ECDH(密钥磋商) 来源: https://blog.csdn.net/xueyepiaoling/article/details/6243337 ...
- [TJOI2017][bzoj4889] 不勤劳的图书管理员 [线段树套线段树]
题面 传送门 思路 考虑两本书的位置交换对答案的贡献: (为了方便描述,用"左边那本"和"右边那本"称呼两本我们要交换的书,"中间那本"是我 ...
- BZOJ5299 [Cqoi2018]解锁屏幕 【状压dp】
题目链接 BZOJ5299 题解 就一个毒瘤卡常题..写了那么久 设\(f[i][s]\)表示选了集合\(s\)中的点,最后一个是\(i\),进行转移 要先预处理出两点间的点,然后卡卡常就可以过了 # ...