python语法之名称空间
名称空间与作用域
什么是名称空间
回忆:我们定义变量时,发生了什么
name = 'leethon' """ 赋值符号右边,产生了一个数据值'leethon',我们在内存中划定一个区域,将其存进去 内存空间很大,数据值的位置需要被记录,所以记录在了变量名name中 """
提问:变量名以及数据值的位置存在什么地方呢?
实际上,变量名及其绑定的数据值的位置也存在内存中,它们被集中放在内存中方便寻找的某一处,这个地方就是名称空间。
名称空间不仅会存储变量名,还会存储函数名等所有名字。
三大名称空间介绍
-
内置名称空间
解释器级别的名称空间,存了所有内置函数和关键字的名字如:print、len、def
-
全局名称空间
文件级别的名称空间,当运行py文件时,会产生一个全局名称空间,存储文件中定义的变量名、函数名还有类名(之后会讲)。
-
局部名称空间
函数级别的名称空间,在调用某个函数时,会产生一个局部名称空间,存储函数中定义的变量名、函数名等。
三个名称空间在内存中是三块空间,其中存储的名字分别是自己的,但是高级别的名称空间的名称的应用范围更广。
名称空间存活周期和作用域
- 存活周期
- 内置名称空间:python解释器启动则创建,关闭则销毁。
- 全局名称空间:py文件执行则创建,运行结束则销毁。
- 局部名称空间:函数体代码运行创建,函数体代码结束则销毁。
- 作用域
- 内置名称空间:只要是python程序,其中的名字都可以使用。
- 全局名称空间:只要是当前的py文件,其中的名字在定义完就可以使用。
- 局部名称空间:当前函数体代码内有效。
名字的查找顺序
有时候,我们可能在函数内定义了某个变量名而在全局也定义了这个变量名,但我们在全局调用某个函数时,它内部的变量名我们并不能考虑的到,所以规则上,函数体内的局部变量名和全局中的全局变量名不应该互相影响。
所以,python规定了名称空间的作用域,而我们在使用变量时,也要搞清楚变量名在哪个名称空间中。
-
局部名称空间内使用名字:
局部名称空间 ---> 全局名称空间 ---> 内置名称空间
-
全局名称空间内使用名字:
全局名称空间 ---> 内置名称空间
ps:所以我们在变量名命名时,会规定变量名不能使用系统提供给我们的关键字,因为会优先使用局部和变量的名称而使关键字失去原本的功能。
# 例子1:两个局部变量的名称空间是独立的,互相不影响
def func1():
name = 'jason'
print(age)
def func2():
age = 18
print(name)
下图是几个名称空间的作用域示意图和查找顺序:
当在局部作用域中使用名字,会按照从低到高的名称空间级别去找。
两个局部名称空间是独立的,不会使用对方空间中的名字,如果没在局部找到则到全局名称空间找,如果全局没找到就会去内置名称空间找。
# 例子2
x = 1
def func1():
x=2
def func2():
# x = 3
print(x)
func2()
func1()
名字x的查找过程:
func2局部名称空间 ---> func1局部名称空间(找到了)
名字print的查找过程:
func2局部名称空间 ---> func1局部名称空间 ---> 全局名称空间---> 内置名称空间
global与nonlocal
这个关键字能让我们突破上述名称空间的限制,修改变量的值。
- global声明全局关键字
x = 100 def func(): global x # 声明这个x是全局变量的x变量 x = 666 # 这里的x不是定义一个局部变量的x变量了,就是修改全局变量x的值了 print(x) # 100 func() print(x) # 666 # x的值被修改了
- nonlocal声明外层函数关键字
x = 100 def func1(): x = 200 # 目标改动值,不在全局,不在func2中,在func2外的func1中 def func2(): nonlocal x # 声明这个x为外层函数空间中的变量x而非本函数的新变量x x = 300 # 性质从定义x变为修改外层函数的变量x print(x) # 200 func2() print(x) # 300 # x在func2的函数体内被改变了 func1() # 依次打印200 和 300 print(x) # 100 # 全局的x没有受影响
练习
判断下列打印的 money的值是多少并说明理由,试着用global和nonlocal改变打印的结果。
# t1
money = 100
def index():
money = 666
index()
print(money)
"""
会打印100
index函数体内的money是函数体内新定义的x,它从属于局部名称空间,无法作用于全局的money
如果想在函数内对全局的x进行修改,则要在index内部先声明global x。
"""
# t2
money = 100
def func1():
money = 666
def func2():
money = 888
func2()
print(money)
func1()
"""
会打印666
大概原理是和t1一样的,外层函数的名称空间无法被内部函数的同名变量修改,
只有在func2中先声明nonlocal x才能修改外层函数空间中的x。
"""