一、名称空间
定义:名称空间(namespace):存放名字的地方,是对栈区的划分。
有了名称空间之后,就可以在栈区中存放相同的名字,详细的,名称空间。
名称空间是各自独立的,没有包含关系
1.1、内置名称空间
存放的名字:存放的是解释器内置的名字
>>> print
<built-in function print>
>>> input
<built-in function input>
存活周期:python解释器启动则产生,python解释器关闭则销毁
1.2、全局名称空间
存放的名字:不是函数内部定义,也不是内置的,剩下的是全局名称空间
x = 10 ,if判断都是全局名称空间
def func(): # func = 函数的内存地址,所以是全局内存空间
a = 111 # a,b在函数内部定义,属于全局名称空间
b = 222
存活周期:python文件执行产生则产生,python文件运行完毕后销毁
1.3、局部名称空间
存放的名字:在调用函数时,运行函数体代码过程中产生的函数内的名字
存活周期:在调用函数时存活,函数调用完毕后则销毁
1.4、名称空间的加载顺序
内置名称空间>全局名称空间>局部名称空间
1.5、名称空间的销毁顺序
局部名称空间>全局名称空间>内置名称空间
1.6、名字的查找优先级
当前所在的位置向上一层一层查找
如果当前在局部名称空间:局部名称空间–>全局名称空间–>内置名称空间
input = 333
def func():
input= 444
print(input)
func() # 打印结果 444
input = 333
def func():
# input= 444 注释掉
print(input)
func() # 打印结果 333
# input = 333 注释全局名称
def func():
# input= 444
print(input)
func() # 打印结果 <built-in function input>
如果当前在全局名称空间:全局名称空间–>内置名称空间
input = 333
def func():
input= 444
func()
print(input) # 在全局,会从全局找 打印333
# input = 333 注释,全局没有,开始从内建找
def func():
input= 444
func()
print(input) # 在全局,而全局没有,开始从内建找 打印<built-in function input>
示例1:
x = 111
def func():
print(x)
func() #打印 111
def func():
print(x)
x = 111
func() # 111
# 在运行 func()之前,x=111已经运行过,所以会打印出来
示例2:名称空间的“嵌套”关系(名称空间不存在嵌套关系,这里只是为了理解)
x = 1
def func():
print(x)
def foo():
x = 222
func()
foo() # 打印1
# 没有打印 222 ,说明名称空间的嵌套关系是以函数定义阶段为准的(在函数定义时就已经确定),与调用位置无关。
示例3:函数嵌套定义
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4NxzTUVY-1625063372039)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210630203833323.png)]
input = 111
def f1():
input = 222
def f2():
input=333
print(input)
f2()
f1() # 打印 333
input = 111 # 这里注释,在内置名称空间找 打印<built-in function input>
def f1():
input = 222 # 这里注释,会在全局里面找,打印111
def f2():
# input=333 注释
print(input)
f2()
f1() # 打印 222
示例4:
x = 111
def func():
print(x) # 这里把x识别成了一个局部的东西,这是因为在扫描语法时,下面有一个x,确定x = 222 在局部名称空间,在定义阶段确定,而在调用时,发现x并未定义,应该将x放到print之前
x = 222
func()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8VpF68aC-1625063372041)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210630204650126.png)]
二、作用域
作用域–>作用范围
2.1、全局作用域
全局作用域:内置名称空间,全局名称空间
特点:全局存活
全局有效:被所有函数共享
# 不同的函数内的名字彼此都是独立的,但他们的全局是一直存在
x = 111
def foo():
print(x,id(x))
def bar():
print(x,id(x))
foo()
bar()
print(x,id(x))
111 2050010768
111 2050010768
111 2050010768
2.2、局部作用域
局部作用域:局部名称空间的名字
特点:临时存活,函数调用结束就死掉
局部存活:函数内有效
三、LEGB
通过LEGB规则对变量名进行作用域解析
我们已经知道了多个命名空间可以独立存在,而且可以在不同的层次上包含相同的变量名。“作用域”定义了Python在哪一个层次上查找某个“变量名”对应的对象。接下来的问题就是:“Python在查找‘名称-对象’映射时,是按照什么顺序对命名空间的不同层次进行查找的?”
答案就是:使用的是LEGB规则,表示的是Local -> Enclosed -> Global -> Built-in,其中的箭头方向表示的是搜索顺序。
#b builing
#g global
def f1():
#enclosing
def f2():
# enclosing
def f3():
# local
pass
Local 可能是在一个函数或者类方法内部。
Enclosed 可能是嵌套函数内,比如说 一个函数包裹在另一个函数内部。
Global 代表的是执行脚本自身的最高层次。
Built-in 是Python为自身保留的特殊名称。