Python名称空间与作用域
Posted 吃了好多肉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python名称空间与作用域相关的知识,希望对你有一定的参考价值。
名称空间:
-
存放名字与值的关系的空间
-
在python解释器开始执行, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来,
-
当遇到函数定义的时候, 解释器只是把函数名读入内存, 并检查语法是否正确,表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的。
-
只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间.
内置名称空间:
- 存放Python解释器内置的名字,如input,print,list等
- 存活周期:Python解释器启动则产生,Python解释器关闭则销毁
全局命名空间:
- 运行代码伊始所产生的名字,或者说不是函数内定义、也不是内置的剩下的都是全局名称空间
- 存活周期:Python文件执行产生,文件执行结束销毁
临时名称空间:
- 在函数体的运行中开辟的临时的空间,也叫做局部命名空间,同一个函数调用多次会产生多个局部名称空间。
- 存活周期:函数体执行时产生,函数运行结束,这个空间也会清空
加载到内存的顺序:
-
1.内置名称空间
-
2.全局名称空间
-
3.临时名称空间
取值顺序:(就近原则:LEGB原则)单向不可逆
- (从局部开始找时)局部名称空间 --> 全局名称空间 --> 内置名称空间
input = 333
print(input) # 此时是从全局开始取值,input()函数则不会被查找到
# 333
LEGB原则:
- local本地 --> enclosed嵌套函数的外层函数内部 --> global全局 --> buildin内置
def func():
print(x)
x = 111
func() # 局部没有则在全局查找,在函数执行前x被赋值,所以并不会报错
# 111
x = 1
def func():
print(x)
def foo():
x = 222
func()
foo() # 名称空间的‘嵌套‘关系是以函数定义阶段为准,与调用位置无关
# 1
input = 111
def f1():
def f2():
input = 333
print(input)
input = 222
f2()
f1() # 名称空间的‘嵌套‘关系是以函数定义阶段为准,与调用位置无关
# 333
注:名称空间实际上是相互独立的一个个空间,并没有包含关系,嵌套关系仅为了帮助理解
作用域:
- 变量的生效范围,分为全局作用域和局部作用域
全局作用域:
- 内置名称空间,全局名称空间,在整个文件的任何位置都可以执行(遵循从上到下逐行执行)
局部作用域:
- 局部名称空间,在函数内部可以使用。
- 局部作用域可以引用全局作用域的变量,但不可改变:
- 因为当Python读取到局部作用域时,发现对变量进行了更改,
解释器会认为这个变量在局部已经定义,就会从局部名称空间寻找这个变量,
然而局部空间并没有定义这个变量,所以报错。
- 因为当Python读取到局部作用域时,发现对变量进行了更改,
count = 1
def func():
count = 100 # 这是在局部名称空间重新创建变量count,并非修改了全局名称空间的count
print(count)
func()
# 100
count = 1
def func():
count += 1 # 不可更改
print(count)
func()
# local variable ‘count‘ referenced before assignment
高阶函数:
- 函数内嵌套函数。
作用域相关的内置函数:
- globals():返回的是字典,里面的键值对为全局作用域的所有内容
print(globals())
- locals():返回的是字典,里面的键值对为当前作用域的所有内容
print(globals())
函数中变量引用的坑:
- 在函数中,如果你定义了一个变量,但是在定义之前引用了此变量,那么解释器会认为,语法错误。应该在引用之前先定义。
count = 1
def func():
print(count)
count = 2
func()
# local variable ‘count‘ referenced before assignment
关键字:
- global:
- 在局部作用域声明一个全局变量。
- 如果局部想要修改全局的名字对应的值(不可变数据类型),也需要用global。
?
name = ‘杜甫‘
def func():
global name # 变量赋值前先声明name是全局名称,不要再造新名称
name = ‘李白‘
func() # 函数调用后,函数内声明的全局变量才生效
print(name)
# 李白
?
- 如果局部想要修改全局的名字对应的值(可变类型),则不需要global:
l1 = [111,222]
def func():
l1.append(333)
func()
print(l1)
# [111, 222, 333]
- nonlocal:
- 在嵌套函数中,内层函数对上一层函数内名称的修改(不可变类型),需要nonlocal
- nonlocal的使用必须是内层函数对非全局的外层函数,如果外层函数没有找到被声明的名称,则会报错
x = 0
def f1():
x = 11 # 如果f1内的x注释掉,nonlocal则报错
def f2():
nonlocal x
x = 22
f2()
print(‘f1内的x:‘,x)
f1()
# f1内的x: 22
x = 0
def f1():
x = [11,]
def f2():
x.append(22) # 如果是可变类型则不需要nonlocal,可直接修改
f2()
print(‘f1内的x:‘,x)
f1()
# f1内的x: [11, 22]
以上是关于Python名称空间与作用域的主要内容,如果未能解决你的问题,请参考以下文章