装饰器其实一点都不难,两个例子基本够了:
第一个例子:
def dec(func):
def com(a,b):
i=func(a,b)
return i+a+b
return com
@dec
def add(x,y):
return x+y
add(1,2)
读这种代码的要点在于掌握“ 装饰器是把函数作为参数传入,并重新赋值给原函数 ”这个要点,即:
#上一条代码中
@dec
#这条语句相当于是:
add=dec(add)
重写一下代码,两者其实是等价的:
def dec(func):
def com(a,b):
i=func(a,b)
return i+a+b
return com
def add(x,y):
return x+y
add=dec(add)
add(1,2)
那么,在遇到这种简单的装饰器的时候,阅读的时候掌握小窍门,看见add(1,2), 要分开看,仿佛看见是看见了add和(1,2),而不是add(1,2)这个整体。
那么上面的代码看起来就很简单了:
看见add(1,2),相当于看见了dec(add)(1,2)
因为dec(add)的返回值为com,所以dec(add)(1,2)相当于com(1,2)
然后直接根据com()的定义去算即可,注意一下func其实就是输入的add就可以了。
第二个例子:
和第一个例子差不多,只是多了一个参数在装饰器里传递:
def bcd(c):
def dick(func):
def y(a,b):
i=func(a,b)+c
return i
return y
return dick
@bcd(2)
def abc(a,b):
return a+b
abc(1,2)
这种情况下,相当于是:
def bcd(c):
def dick(func):
def y(a,b):
i=func(a,b)+c
return i
return y
return dick
def abc(a,b):
return a+b
abc=bcd(2)(abc)
abc(1,2)
也就是说,看见abc(1,2),相当于看见bcd(2)(abc)(1,2)
因为bcd(2)返回值为dick,所以相当于dick(abc)(1,2)
因为dick(abc)返回值为y,所以相当于y(1,2)
然后就把1,2代入y(a,b)计算,注意一下func是传入的add,c是传入的2即可
最后,我们来看参数变多的情况:
def dec(func):
def com(a,b,c=2):
i=func(a,b)+c
return i+a+b
return com
@dec
def add(x,y):
return x+y
add(1,2,4)
上面的语句,如果不掌握装饰器,就会很让人懵逼:明明add(x,y)只有两个参数,为什么add(1,2,4)有三个参数还不报错?
其实很简单,无非是装饰器对add函数做了改写:
add(1,2,4)在装饰器的作用下,相当于dec(add)(1,2,4)
因为dec(add)返回为com,所以相当于com(1,2,4). 这里可以发现com其实是带了三个参数位置的,所以add(1,2,4)的写法没有错。
但是下面这种写法不行,原因也很简单,因为func在这里其实就是add(x,y),只有两个参数位,不能写第三个:
def dec(func):
def com(a,b,c=2):
i=func(a,b,1)+c
return i+a+b
return com
@dec
def add(x,y):
return x+y
add(1,2,4)
#运行结果如下:
-------------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [5], in <cell line: 11>()
7 @dec
8 def add(x,y):
9 return x+y
---> 11 add(1,2,4)
Input In [5], in dec.<locals>.com(a, b, c)
2 def com(a,b,c=2):
----> 3 i=func(a,b,1)+c
4 return i+a+b
TypeError: add() takes 2 positional arguments but 3 were given