1.闭包定义:
------------------- 内部函数对外部函数作用域里变量的引用
先来看一个例子,这个例子之前看到过,自己测试了下
#-*-coding:utf-8-*-
origin = [0, 0] # 坐标系统原点
legal_x = [0, 50] # x轴方向的合法坐标
legal_y = [0, 50] # y轴方向的合法坐标
def create(pos=origin):
print(pos)
def player(direction, step):
# 这里应该首先判断参数direction,step的合法性,比如direction不能斜着走,step不能为负等
# 然后还要对新生成的x,y坐标的合法性进行判断处理,这里主要是想介绍闭包,就不详细写了。
new_x = pos[0] + direction[0] * step
new_y = pos[1] + direction[1] * step
pos[0] = new_x
pos[1] = new_y
# 注意!此处不能写成 pos = [new_x, new_y],否则外层参数pos也不会改变,执行完就会释放内部函数参数pos,原来的pos也不会改变。
return pos
return player
player = create() # 创建棋子player,起点为原点
print(player([1, 0], 10)) # 向x轴正方向移动10步
del player
player1 = create()
输出结果:
[0, 0]
[10, 0]
[10, 0]
分析:可以看到我删除函数后再次调用,pos的值竟然没有被释放。这便是闭包的作用:携带环境(包)。
2.装饰器
意义:不影响原有函数的功能,还能添加新的功能
如果只有两层函数
那么在闭包函数最外层用来接收被装饰函数,以及你这个 包 想存放内容,最内层可以接收被装饰函数的参数,返回值需要是fun()才会执行被装饰函数。
def fun1(fun):#定义一个fun来接收被装饰函数
def fun2(*args, **kwargs):#接收被装饰函数参数
...
return fun(*args, **kwargs)#执行被装饰函数
return fun2
@fun1()
def hello(a,b):
pass
如果装饰器里带有参数,那么则在外部多加一层用来接收参数,如下
def fun1(a):
...
def fun2(fun):
def fun3(*args, **kwargs):
...
return fun(*args, **kwargs)
return fun3
return fun2
@fun1(a = 'a')
def hello(b,c):
pass
@fun(a = ‘a’)相当于fun(a=‘a’)(),因此执行@fun(a= ‘a’)得到的结果的其实就是fun3,
这个时候我再调用函数的时候直接执行fun3(),必须返回值是我传入函数的调用fun(*args, **kwargs),而不是函数名fun,才会执行被装饰的函数。
代码运行:
装饰器会改变被装饰函数的一些原信息,比如此处,调用
hello(x,y)
print(hello.__name__),输出变成了fun3,而不是hello,这个便是装饰器的问题,所以才有了Flask中@wrap使用保留被装饰函数一些特有信息。
那么装饰器的作用:
函数添加装饰器后,设置断点调试可以看到调用hello()会直接进入执行fun3()函数,那么我们可以在fun3中定义一些在执行被装饰函数之前的一些入口条件。这便是装饰器的作用
这里没有赘述很多原理,只是从简单的作用来解释闭包和装饰器,仅作参考