1. 名称空间
名称空间,名称即名字,空间就是存放东西的地方。那么名称空间你可以理解为就是放名字的地方。我们之前说过
变量名是放在栈区的,变量值是放在堆区。这怎么又多出来个名称空间呢?我们慢慢来介绍。
实际上名称空间是对栈区的划分
,有了名称空间我们就可以在栈区中存放相同的名字了
,名称空间让他们相互隔离
开来。进而也实现了资源隔离。名称空间是一种虚拟化的划分,栈区是真是存在的。
我们讲名称空间只考虑名字 , 是不考虑值的 , 因为名字太重要了 , 通过名字可以引用到值
2. 三种名称空间
1.1 内置名称空间
存放python解释器内置的名字 , 比如 print input等
>>> print
<built-in function print>
>>> input
<built-in function input>
存活周期 :
python解释器启动则产生,python解释器关闭则销毁
1.2 全局名称空间
只要不是函数内定义、也不是内置的,剩下的都是全局名称空间的名字
import os # os是存放在全局名称空间的名字
x = 123 # x是存放在全局名称空间的名字
def func():
pass
func # func是存放在全局名称空间的名字
存活周期 :
python文件执行则产生,python文件运行完毕后销毁
1.3 局部名称空间
在调用函数时,运行函数体代码过程中产生的函数内的名字
def func():
x = 10
y = 20
func() # 函数调用就会产生x,y这两个名字,放在局部名称空间 函数结束,名字就会被销毁
存活周期 :
在调用函数时存活,函数调用完毕后则销毁
友情提示 :
# 函数的每次调用都会产生一个局部名称空间,哪怕是一个空函数,
# 或者一直调用同一个函数,也会每次都会产生不同的局部名称空间
3. 三种顺序
3.1 名称空间加载顺序
名称空间的加载顺序你也可以认为是名称空间的生成顺序
# 内置名称空间>全局名称空间>局部名称空间
3.2 名称空间销毁顺序
# 局部名称空间>全局名空间>内置名称空间
3.3 名字查找顺序
名字的查找顺序是以定义阶段为准的,从当前位置往外一层一层的找
# 当前所在的位置向上一层一层查找
# 内置名称空间 3层
# 全局名称空间 2层
# 局部名称空间 1层
# 这里的层是我个人抽象出来的
# 如果当前在局部名称空间:
# 局部名称空间->全局名称空间->内置名称空间
# 如果当前在全局名称空间
# 全局名称空间->内置名称空间
# 举个栗子
x = 1
def func():
print(x)
def foo():
x = 222
func()
foo() # 打印1
# 名称空间的"嵌套"关系是以函数定义阶段为准,与调用位置无关
x = 1
def foo():
x = 222
def func():
print(x)
func()
foo() # 打印222
虽然函数的定义不会执行代码,但是会在函数内部搞一个名字,会先存个名字,等到调用的时候在会具体赋值
input = 111
def f1():
def f2():
print(input)
input = 222
f2()
input = 333
f1() # 运行打印222
4. 作用域
域是指范围的意思,作用域就是作用范围的意思
按照名字作用范围的不同可以将三个名称空间划分为两个区域: 全局作用域与局部作用域
4.1 全局作用域
全局作用域 : 位于全局名称空间、内置名称空间中的名字属于全局范围,该范围内的名字全局存活(除非被删除,
否则在整个文件执行过程中存活)、全局有效(在任意位置都可以使用);
# 特点: 全局存活
# 全局有效 被所有函数共享
4.2 局部作用域
局部作用域:位于局部名称空间中的名字属于局部范围。该范围内的名字临时存活(即在函数调用时临时生成,函
数调用结束后就释放)、局部有效(只能在函数内使用)。
# 特点: 临时存活
# 局部有效 : 函数内有效
4.3 locals和globals
# locals() 函数返回局部作用域中所有的名字
# globals() 函数返回全局作用域中所有的名字
# 返回的内容格式是字典格式
def func():
x = 1
print(locals())
func() # {'x': 1}
5. global和nonlocal
5.1 global
在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值
为不可变类型
时,则需要用到global关键字
name = "ymn"
def func():
global name # 把全局中的名字加载到局部内
name = 'dl' # 修改对应的值,这个值不会因为函数的结束,就销毁了,因为它作用到全局
print(name) # 打印 dl
func()
print(name) # name的值已经被修改了,所以打印 dl
5.2 nonlocal
nonlocal 会从当前函数的外层函数开始一层层去查找名字,若是一直到最外层函数都找不到,则会抛出异常。
nonlocal的查询边界就是最外面的一层函数。
x = 0
def func():
x = 1
def func2():
nonlocal x
x = 2
func2() # 调用fcun(),修改func作用域中名字x的值
print(x) # 在func作用域查看x
func() # 结果2
print(x) # 打印0 打印的是全局作用域中x的值