变量引用顺序

Python 引用变量的顺序:当前作用域局部变量->外层作用域变量->当前模块中的全局变量->Python内置变量。

1、global

global 关键字用来在函数或其他局部作用域中使用全局变量,如果不对全局变量进行修改,那么可以不使用global关键字;如果想要在函数或局部作用域中对全局变量进行修改操作,那么必须在函数或局部作用域中使用global关键字进行声明,否则报错:UnboundLocalError

count = 1

def foo():

global count#如果不加这个那么就会报错

count += 1
print(count)
foo()

2、nonlocal

使用情况:闭包,嵌套函数中

如果内部函数想要对外部函数的局部变量进行修改时,需要在内部函数中声明:

nonlocal

nonlocal语句会搜索当前调用栈中的下一层函数的定义。

def a():

count = 1
def b():
nonlocal count
count += 1
print(count)
return b
a()()

3、装饰器

介绍:装饰器的作用是将被修饰的函数当作参数传递给与装饰器对应的函数,并返回包装后的被装饰的函数。装饰器其实是闭包的一种特殊情况

def a(func):

return func
@a
def b():
pass
b()

执行示意图:


解析过程:

发现@a,那么就将会执行a(b),返回b

b(),这一步调用的其实是a返回的同一名的b函数,并且开始执行b函数中的操作

4、闭包

闭包概念:在计算机科学中,闭包(Closure)是词法闭包的简称,是引用了自由变量的函数,这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

简单介绍:可以理解为一个封闭的包裹,这个包裹就是一个函数和函数内部对应的逻辑,包裹里面的东西就是自由变量,自由变量可以随着包裹到处游荡,比如:装饰器是一个闭包,随着装饰器进行传递的函数名就是自由变量(函数),装饰器和内部逻辑结构就是闭包中的函数和内部逻辑。

def func(name):

def inner_func(age):
print(‘name:’+name+’ age:’+age)
return inner_func
a = func(‘liyang’)
a(20)#>>> name:liyang age:20

上面的例子中:调用func函数时就产生了闭包inner_func,该闭包所持有的自由变量是name。

当函数func的生命周期结束之后,name这个变量依然存在,因为它被闭包引用了,所以不会被回收。

5、延迟绑定

Python函数的作用域是由代码决定的,也就是静态的,但是使用是动态的,是在执行时确定的

闭包中遇到的问题

fs = [lambda x: x*I for i in range(4)]
print(fs[0](1))#>>> 3

期望输出结果是:0,但是结果却是:3

这是因为只有在函数foo被执行的时候才会搜索变量i的值,由于循环已结束,i指向最终值3,所以最终会发现结果都是一样。

使用下面的闭包方式,就会得到期望的结果:

def foo(i):

return lambad x: x*i
fs = [foo(i) for i in range(4)]
print(fs[0](1))