本文共 3200 字,大约阅读时间需要 10 分钟。
装饰器是python基础语法中比较晦涩难懂的地方,借此机会,谈谈自己对装饰器的理解。
装饰:给别的函数添加功能
器:就是具有某种作用的工具
装饰器:给其他函数添加功能的工具,本质也是函数,而且是一个闭包函数。
一、函数传参的另外一种形式
之前我们学的函数传参都是类似于如下:
def func(a,b): print(a,b)
有了装饰器之后我们可以这样传参:
这里是为deco传的参数,这里的deco就是一个装饰器,他需要一个参数是func,即被装饰函数的地址def wrapper(func): def deco(*args,**kwargs): print('in the wrapper') res = func(*args,**kwargs) return res return decodef func2(): print(123)
那为什么不这样写?
def deco(func,*args,**kwargs): print('in the wrapper') res = func(*args,**kwargs) return res
我将在下面解释
二、在不改变函数源代码和调用方式的情况下为函数添加功能,具体用法在下面介绍
def wrapper(func): def deco(*args,**kwargs): print('in the wrapper') res = func(*args,**kwargs) return res return decodef func2(): print(123)
前面已经说过,deco就是一个装饰器,本质是闭包函数。对于闭包函数简单一提,在python中万物皆对象,因此函数也可以作为其他函数的参数、返回值、也可以作为容器类型的元素
x = 4def deco(): x = 1 def func(): print(x)
闭:可以理解为一个麻袋把函数套起来,这里的麻袋就是deco
包:可以理解为麻袋里面的东西,这里的x就是麻袋里的东西,这里打印的x是1
闭包函数的名字的查找关系是以函数定义阶段为准,可以理解为局部变量覆盖了全局变量
形式:@函数名
def wrapper(func): def deco(*args,**kwargs): print('in the wrapper') res = func(*args,**kwargs) return res return deco@wrapperdef func2(): print(123)
这里func2被deco装饰,@wrapper等价于func2 = wrapper(func2),为func2多加了一个功能,即打印了in the wrapper,那为什么不能在定义deco的时候多一个函数参数呢,那是因为实际上func2变成了 deco,真正调用func2的时候会是这样
func2()
func2被装饰后,运行的就是deco了,但是用户丝毫不清楚这个过程,因为调用方式没变,函数(指的是func2)的代码也没变,如果加上一个函数参数,那么在调用的时候会出错,说是少了一个参数。这里的deco参数和func2的函数应该保持一致。
有参装饰器,简单一提(其实可以不用语法糖实现,省略,因为比较low)
def outter(x): def wrapper(func): print(x) def deco(*args,**kwargs): print('in the wrapper') res = func(*args,**kwargs) return res return deco return wrapper@outter(1)def func2(): print(123)func2()
多层装饰器的加载顺序是从下往上,运行顺序是从上往下。
def deco1(func1): # func1 = wrapper2的内存地址 def wrapper1(*args,**kwargs): print('正在运行===>deco1.wrapper1') res1=func1(*args,**kwargs) return res1 return wrapper1def deco2(func2): # func2 = wrapper3的内存地址 def wrapper2(*args,**kwargs): print('正在运行===>deco2.wrapper2') res2=func2(*args,**kwargs) return res2 return wrapper2def deco3(x): def outter3(func3): # func3=被装饰对象index函数的内存地址 def wrapper3(*args,**kwargs): print('正在运行===>deco3.outter3.wrapper3') res3=func3(*args,**kwargs) return res3 return wrapper3 return outter3# 加载顺序自下而上(了解)@deco1 # index=deco1(wrapper2的内存地址) ===> index=wrapper1的内存地址@deco2 # index=deco2(wrapper3的内存地址) ===> index=wrapper2的内存地址@deco3(111) # ===>@outter3===> index=outter3(index) ===> index=wrapper3的内存地址def index(x,y): print('from index %s:%s' %(x,y))# 执行顺序自上而下的,即wraper1-》wrapper2-》wrapper3index(1,2) # wrapper1(1,2)
更加伪装:
from functools import wrapsdef outter(func): @wraps(func) def wrapper(*args, **kwargs): """这个是主页功能""" res = func(*args, **kwargs) # res=index(1,2) return res # 手动将原函数的属性赋值给wrapper函数 # 1、函数wrapper.__name__ = 原函数.__name__ # 2、函数wrapper.__doc__ = 原函数.__doc__ # wrapper.__name__ = func.__name__ # wrapper.__doc__ = func.__doc__ return wrapper
python
转载地址:http://ifxki.baihongyu.com/