Python LEGB (Local, Enclosing, Global, Build in) 规则

 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 规则下作用域
时间: 2024-08-12 11:21:57

Python LEGB (Local, Enclosing, Global, Build in) 规则的相关文章

python: local variable 'xxx' referenced before assignment

问题发现 xxx = 23 def PrintFileName(strFileName): if xxx == 23: print strFileName xxx = 24 PrintFileName("file") 报错 Traceback (most recent call last): File "C:/Users/Desktop/del.py", line 7, in <module> PrintFileName("file"

[Python]threading local 线程局部变量小测试

概念 有个概念叫做线程局部变量,一般我们对多线程中的全局变量都会加锁处理,这种变量是共享变量,每个线程都可以读写变量,为了保持同步我们会做枷锁处理.但是有些变量初始化以后,我们只想让他们在每个线程中一直存在,相当于一个线程内的共享变量,线程之间又是隔离的.python threading模块中就提供了这么一个类,叫做local. 多线程中共享变量和局部变量的区别我画两个小图,简单描述下(作图能力一般,请见谅,概念性的东西大家可以google下,很多好文章) 全局变量 线程局部变量 对比: 下面是

TLS 与 python thread local

TLS 先说TLS( Thread Local Storage),wiki上是这么解释的: Thread-local storage (TLS) is a computer programming method that uses static or global memory local to a thread. 线程本地存储(TLS)是一种电脑编程技术, 它用静态或者全局的存储器来保存线程本地的变量(意译). 其目的是为了实现变量隔离,即“同一个”全局变量,对于不同的线程,其值可以不同(类似

Use Local Or Global Index?

经常我们需要将大表根据分区键进行分区,当建立索引的时候,我们到底使用local 还是global 索引呢 先看看两种索引的特点: 本地索引特点: 1. 本地索引一定是分区索引,分区键等同于表的分区键,分区数等同于表的分区说,一句话,本地索引的分区机制和表的分区机制一样. 2. 如果本地索引的索引列以分区键开头,则称为前缀局部索引. 3. 如果本地索引的列不是以分区键开头,或者不包含分区键列,则称为非前缀索引. 4. 前缀和非前缀索引都可以支持索引分区消除,前提是查询的条件中包含索引分区键. 5.

python thread local的用法

python 中多线程的并发跟其他语言一样,需要考虑多线程并发访问去全局变量所带来的问题,python的local类解决了这个问题,通过它让每个线程内部有一个相对独立的local保存数据,某一个线程修改了数据,不影响其他线程中保存的数据. 1 from threading import Thread 2 import threading 3 import time 4 local_value=threading.local() 5 local_value.x='en' 6 class threa

python 局部local和全局global变量

global和local变量 虽然简单,但是还是记录一下,主要是转载 转载自:http://blog.sina.com.cn/s/blog_436992740102ux8z.html 先看一段代码: 可见 old_price 是个全局变量, final_price 是局部变量 运行结果是: 局部变量拿到外面来如果没有定义的话就不能用的 那全局变量在 def 函数里 可以用吗? 运行结果: 可见, def 定义的函数里可以打印 全局变量 如果想要在 def 定义的函数里,对全局变量 global

python中的关键字global和nonlocal

知识点: global将一个变量变为全局变量 nonlocal改变最近的变量,又不是全局作用. 1.global 在python中,当引用一个变量的时候,对这个变量的搜索按找本地作用域(Local).嵌套作用域(Encolosing function locals).全局作用域(Global).内置作用域(builtins模块)的顺序来进行的,即所谓的LEGB规则. m = 1 #全局 def fun1(): m = 2 #嵌套 def fun2(): m = 3 #本地 fun2() fun1

python 局部变量和全局变量 global

当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的.这称为变量的 作用域 .所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始. 使用局部变量 例7.3 使用局部变量 #!/usr/bin/Python# Filename: func_local.py def func(x):    print 'x is', x    x = 2    print 'Changed local x to', x x = 50func(

Python局部变量和全局变量global

当你在函数定义声明变量的时候,它们与函数外具有相同名称的其它变量没有任何关系,即变量名称对于函数来说是 局部  的.这称为变量的 作用域 .所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始. 使用局部变量 例子:func_local.py #!/usr/bin/python #encoding:utf-8 def func(x): print 'x is', x x=2 print 'Changed local x to', x x=50 func(x) print 'x is s