一、基础复习
二、函数中参数的作用域
作用域:一个变量可以被访问的范围,一个变量的作用域总是由它在代码中被赋值的位置来决定的。
1.局部作用域
局部变量:如果一个变量定义的位置是在一个函数的里面,那么它的作用域就仅限于该函数中。
>>> def myfunc():
x=520
print(x)
>>> myfunc() # x为局部变量
520
>>>
>>> print(x) # 在外部访问会报错
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
print(x)
NameError: name 'x' is not defined
2.全局作用域
全局变量:如果是在任何函数的外部定义一个变量,那么它的作用域就是全局的。
>>> x=880
>>> def myfunc():
print(x)
>>> myfunc() # x为全局变量
880
在一个函数中,局部变量和全局变量同名都为x时,局部变量就会覆盖掉全局变量。
>>> x=880
>>> def myfunc():
x=520
print(x)
>>> myfunc() #打印局部变量x的值
520
>>> print(x) #出了函数,打印全局变量
880
>>>
通过id()函数查看全局变量和局部变量。
#例1:
函数内部如果没有同名的局部变量覆盖的话,它打印的这个id()就是上面全局变量的id
>>> x=880
>>> id(x)
2579527195760
>>> def myfunc():
print(id(x))
>>> myfunc() #函数内部如果没有同名的局部变量覆盖的话,它打印的这个id()就是上面全局变量的id
2579527195760
>>>
#例2:
局部变量的id值和全局变量的id值不同。
>>> x=880
>>> id(x)
2579527195760
>>> def myfunc():
x=520
print(id(x))
>>> myfunc() # id值不同
2579527920528
>>>
3.global语句
global语句在函数内部修改全局变量的值。
使用global语句,可以让函数内的局部变量全局可用,并且在别的文件里也可以引用到。
>>> x=880
>>> def myfunc():
global x # global语句可以让函数内的局部变量全局可用。
x=520
print(x)
>>> myfunc()
520
>>> print(x) # 全局变量x=880被global语句修改为520
520
4.嵌套函数
函数嵌套函数
#内部函数无法被调用
>>> def funA():
x=520
def funB():
x=880
print("In funB,x=",x)
print("In funA,x=",x)
>>> funB() #内部函数无法被调用
Traceback (most recent call last):
File "<pyshell#47>", line 1, in <module>
funB()
NameError: name 'funB' is not defined
要想调用funB()函数,在定义时就要调用。
>>> def funA():
x=520
def funB():
x=880
print("In funB,x=",x)
funB() # 调用funB()函数,在定义时就要调用。
print("In funA,x=",x)
>>> funA()
In funB,x= 880
In funA,x= 520
>>>
5.nonlocal语句
nonlocal语句:在内部函数修改外部函数的变量。
nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量。
>>> def funA():
x=520
def funB():
nonlocal x # nonlocal语句修改了外部变量x=520的这个值。
x=880
print("In funB,x=",x)
funB()
print("In funA,x=",x)
>>> funA()
In funB,x= 880
In funA,x= 880
>>>
6.LEGB规则
函数作用域之间的影响范围存在相互覆盖的情况,冲突出现时遵从LEGB规则。
L>E>G>B
- L是local,局部作用域
- E是Enclosed,是嵌套函数外层函数作用域
- G是Global,是全局作用域。
- B是Build-In,是内置作用域。
当全局作用域和局部作用域发生冲突时,python使用局部作用域的变量(除非使用global语句进行特殊说明)。
当函数嵌套发生的时候,局部作用域又会覆盖外层函数这个作用域(除非使用nonlocal语句进行说明)
B是Build-In,只要起一个变量名和它相同,就足以把这个内置函数给毁了。
>>> str="小甲鱼把str给毁咯"
>>> str(520) #前面已经把str作为变量名赋值,现在它相当于一个全局变量。+
Traceback (most recent call last):
File "<pyshell#58>", line 1, in <module>
str(520)
TypeError: 'str' object is not callable
>>> str
'小甲鱼把str给毁咯'
课后题:
1.为什么小甲鱼在视频中说,Python 的阻止局部变量覆盖全局变量的做法,是一种出于对代码的 “保护” 的表现?
答:大家不妨设想一下,当一个程序很庞大的时候,自然就会有很多全局变量和函数,那么在函数中,很容易就会出现局部变量和全局变量同名的情况,如果没有这种“保护”,全局变量将面目全非,而且这种BUG非常不好调试!
2.学了这节课,你觉得除了通过参数给函数传递信息之外,还有什么途径可以传递信息到函数内部呢?
答:还可以通过全局变量传递信息。
3. 请问下面代码会打印什么呢?
>>> x = [1, 2, 3]
>>> def invert(x):
... x = x[::-1]
...
>>> invert(x)
>>> print(x)
>>> # 请问这里会打印什么内容?
答:[1, 2, 3]
解析:见下题解析。
4.请问下面代码会打印什么呢?
>>> x = [1, 2, 3]
>>> def invert(x):
... x[:] = x[::-1]
...
>>> invert(x)
>>> print(x)
>>> # 请问这里会打印什么内容?
答: [3, 2, 1]
解析:为什么上一题在函数内部执行 x = x[::-1] 语句,出了函数就还原;而这一题在函数内部执行 x[:] = x[::-1] 语句,则能够从根本上修改列表呢?
现在假设代码如下:
>>> x = [1, 2, 3]
>>> y = x
>>> x = x[::-1]
它在内存中的结构应该是下面这样:
如果假设代码如下:
>>> x = [1, 2, 3]
>>> y = x
>>> x[:] = x[::-1]
那么在内存中的结构则应该是下面这样:
5.请问下面代码会打印什么呢?
>>> x = 100
>>> def funA():
... global x
... x = 250
... def funB():
... nonlocal x
... x = 520
... funB()
...
>>> funA()
>>> print(x)
>>> # 请问这里会打印什么内容?
答:会报错!
解析:如果是在 IDLE 的交互模式下敲代码,没等你代码敲完就会报错了。
在 funA() 函数中,先将 x 变量定义为全局变量,接着在嵌套的 funB() 函数中,又试图通过 nonlocal 语句将内层的 x 变量定义为外层的同名变量……
但是,此时外层的 x 变量已经被提前一步定义为全局变量了(也就相当于外层不存在一个叫 x 的局部变量),于是找不到外层的同名的 x 变量,所以便会报错(SyntaxError: no binding for nonlocal ‘x’ found)。
如果在全局中并没有存在变量 x,然后我们在函数中通过 global x 声明,像这样:
>>> # 已知全局中不存在变量 x
>>> def myfun():
... global x
... x = 250
这个就不会报错,并且 myfun() 函数成功调用后,全局中会多出一个变量 x,并且被赋值为 250。
题目来自小甲鱼python函数IV