函数1——作用域相关
为何使用函数?
减少代码冗余和增加代码的可读性
1.函数的一些概念
- def 是可执行的代码。def是一个可执行的语句——函数并不存在,直到函数运行了def 后(函数被调用后)才存在。def语句在模块文件中编写,在模块文件第一次被导入的时候生成定义的函数。
- def创建了一个对象并将其赋值给某一变量名(即函数名)。当运行到def语句时,它将会生成一个新的函数对象并将其赋值给这个函数名,就像所有的赋值一样,函数名变成了某一函数的引用。
- return将一个结果对象发送给调用者。当函数被调用时,其调用者停止运行直到这个函数完成他的工作,函数才将控制权返回调用者。函数是通过return语句将计算的值传递给调用者的。
- yield向调用者返回一个结果对象,并记住它离开的状态
- global声明一个模块级的变量。
- nonlocal声明一个封闭的函数变量。nonlocal语句允许一个函数来赋值一条语法封闭的def语句的作用域中已经有的名称。
2.作用域
python创建、改变或或查找变量名都是在命名空间(一个保存变量名地地方)中进行的。也就是说,在代码中变量名被赋值的位置决定了变量名能被访问到地范围。(在代码中给一个变量赋值的地方决定了这个变量存在与那个命名空间)。
在默认情况下,一个函数的所有变量名都是与函数命名空间相关联的:
1.一个在def内定义的变量名能够被def内的代码使用。不能在函数外部引用这样的变量名。
def add(value1, value2):
result = value1 + value2
add(2, 4)
print(result)
报错:
NameError: name 'result' is not defined
2.def内的变量名和def外的变量名不冲突,它们是完全不同的变量。
result = 0
def add(value1, value2):
result = value1 + value2
print(result)
add(2, 4)
print(result)
运行结果:
6
0
3.变量可以在3个不同的地方分配,对应3种不同的作用域:
一个变量在def内赋值,它被定位在这个函数内
一个变量在一个嵌套的def内赋值,对于嵌套的函数来说,它是非本地的
在def之外赋值,它就是整个文件全局的
x = 0 # 全局变量 def func1(): x = 1 # 对于func2来说,x = 1是非本地的 def func2(): x = 2 #本地的
2. 1 作用域法则
内嵌的模块是全局作用域(外部的全局变量成为一个模块对象的属性(后续的反射),在一个模块中能像变量一样使用
全局作用域的作用范围仅限于单个文件
每次对函数的调用都创建了一个新的本地作用域
赋值的变量名除非声明为全局变量或非本地变量,否则均为本地变量
x = 0 def func(): global x x = 1 func() print(x) #结果: 1 #func函数被执行了,并声明了一个全局变量x,x=1,作用与全局,覆盖了之前的x=0 #如果func函数没有被执行,结果为0
3.变量名解析:LEGB原则(或LNGB)
在函数中使用变量名时,python依次搜索4个作用域——本地作用域(L),上一层def或lambda的本地作用域(E)(对于内层来说是非本地,N,nocal),全局作用域(G),最后是内置作用域(B)
当在函数中给一个变量名赋值时(而不是在一个表达式中对其引用),Python总是创建或改变本地作用域的变量名,除非它已经在函数中声明为全局变量。
4.global和nonlocal
全局变量名在函数的内部不经过声明也可以被引用(LEGB规则中的一部分)
全局变量如果在函数内被赋值的话,必须先声明。(当你想在函数内创建(或修改)一个全局变量时)
nolocal x 只能作用于一层最近的外层嵌套函数的本地作用域中的变量x,如果查找不到会报错
a = 1
def func():
a = a + 1
func()
#报错:
UnboundLocalError: local variable 'a' referenced before assignment
#局部变量a在引用前没有定义
nonlocal理解本地和非本地,nonlocal就很好使用了
a = 0
def func1():
a = 1
def func2():
print(a)
func2()
func1()
#a=1对于func1是本地,a =1对于func2是非本地本地,但a=0,对于func1不是非本地。
5.闭包(closure)
闭包又叫工厂函数:一个能够记住嵌套作用域的变量值的函数
def f1();
x = 1
def f2():
print(x)
return f2
a = f1()
a()
#命名为函数f2的函数的调用是在f1运行之后,f2记住了f1中嵌套作用域中的x,尽管f1已经不处于激活状态。
def f1(m):
def f2(n):
print(m*n)
return f2
t1 = f1(2)
t2 = f1(3)
t1(2) # 4
t2(3) #9
#内嵌的函数f2记住了f1函数内部地变量n的值,尽管在调用执行t1(还有t2)时f1已经返回了值并推出,
def fun(x):
inner = (lambda y:x*y)
return inner
t = fun(2)
print(t(5)) #10