作用域
.
- 描述
作用域是针对变量而出现。当变量被赋值的时候,变量当前的位置就决定了变量能够被访问到的范围,这个范围就叫变量的作用域
官方文档:
A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.
.
- 四种作用域(LEGB)
a.L(Local):最内层,包含局部变量,比如一个函数/方法内部
b.E(Enclosing):包含了非局部也非全局的变量
c.G(Global):当前脚本的最外层,比如当前模块的全局变量
d.B(Built-in):包含了内建的变量/关键字等
.
- 作用域的规则
a.本地作用域是函数内部属于本函数的作用范围,因为函数可以嵌套函数,嵌套的内层函数有自身的内层范围
b.嵌套函数的本地作用域是属于内层函数的范围,不属于外层
c.全局作用域是文件级别的,或者说是模块级别的,每个py文件中处于顶层的变量都是全局作用域范围内的变量
d.内置作用域是预先定义好的,在__builtins__模块中。这些名称主要是一些关键字,例open、range、list等
.
- 实例
x = 1
def out1(i):
x = 2
y = 'a'
print(x)
print(i)
def in1(n):
print(n)
print(x,y)
in1(3)
out1(2)
输出结果:
2
2
3
2 a
a.处于全局作用域范围的变量有:x、out1
b.处于out1本地作用域范围的变量有:i、x、y、in1
c.处于嵌套在函数out1内部的函数in1的本地作用域范围的变量有:n
注:函数名out1和in1也是一种变量
.
- 搜索规则
当在某个范围引用某个变量的时候,将从它所在的层次开始搜索变量是否存在,不存在则向外层继续搜索
例如函数f()中嵌套了一个函数g(),g()中有一个语句print(x)
,它将首先检查g()函数的本地作用域内是否有x,如果没有则继续检查外部函数f()的本地作用域范围内是否有x,如果没有则再次向外搜索全局范围内的变量x,如果还是没有,则继续搜索内置作用域像‘x’这种变量名,在内置作用域范围内是不存在的,所以最终没有搜索到,报错
.
- 全局变量
a.每个py文件(模块)都有一个自己的全局范围
b.文件内部顶层的,不在def区块内部的变量,都是全局变量
c.def内部声明(赋值)的变量默认是本地变量,要想让其变成全局变量,需要使用global关键字声明
d.def内部如果没有申明(赋值)某变量,则引用的这个变量是全局变量
x = 2
def f():
x = 3
print(x)
f() #输出结果:3
print(x) #输出结果:2
使用global关键字
x = 2
def f():
global x
x = 3
print(x)
f() #输出结果:3
print(x) #输出结果:3
.
- 变量掩盖和修改规则
a.如果在函数内部引用了一个和全局变量同名的变量,且不是重新定义、重新赋值,那么函数内部引用的是全局变量
x = 3
def g():
print(x) #引用了全局变量
#输出结果:3
b.如果函数内部重新赋值了一个和全局变量名称相同的变量,则这个变量是本地变量,他会掩盖全局变量
注:掩盖而非覆盖,出了函数的范围(函数退出),全局变量就会恢复
x = 3
def g():
x = 2 #定义并赋值本地变量x
print(x) #引用本地变量x
#输出结果:2
c.在函数内修改和全局变量同名的变量前,必须先修改,在使用该变量
x = 1
def g():
print(x)
x = 2
g()
输出结果:UnboundLocalError: local variable 'x' referenced before assignment
python是逐行解释的,但每个函数属于一个区块,这个区块范围是一次性解释的,读完整个区块再解释。所以读完整个g()区块后,首先就记住了重新定义了本地变量x=2
,于是g()中所有使用变量x的时候,都是本地变量x,所以print(x)中的x也是本地变量,但这违反了使用变量前先赋值的规则,所以会报错
.
- 代码块
代码块可以使得一段python代码作为一个单元、一个整体执行
类型:
a.模块文件是一个代码块
b.函数体是一个代码块
c.class的定义是一个代码块
d.交互式(python idle)的每一个命令行都是一个独立的代码块
e.脚本文件是一个代码块
f.脚本命令是一个代码块
g.eval()和exec()中的内容也都是各自的代码块
.
- 课堂拓展
a.全局变量的不安全性
b.访问其他模块中的全局变量
c.其他访问全局变量的方法
d.nonlocal关键字
e.访问外层函数变量的其他方法
来源:https://blog.csdn.net/m0_45198298/article/details/101147465