python 类装饰器 class decorator

python 类装饰器 class decorator

b站:【python】一个公式解决所有复杂的装饰器,理解了它以后任何装饰器都易如反掌!

类装饰器

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import time

class Timer:
def __init__(self, func):
self.func = func

def __call__(self, *args, **kwargs):
start = time.time()
ret = self.func(*args, **kwargs)
print(f"Time: {time.time() - start}")
return ret

@Timer
def add(a, b):
return a + b

# 完全等价
add = Timer(add)

print(add(2, 3))


# 执行该python程序,输出
Time: 1.1920928955078125e-06
5

add = Timer(add) 这句话,Timer装饰器,把add从一个函数,变成了Timer类的对象(赋给右边add),因为Timer是一个类,相当于创建了一个类的对象。因此创建对象,括号内的add就会传入Timer类的__init__函数里,所以add作为一个参数被保存在了self.func里。然后整个Timer对象被保存在add这个变量名字里。

add(2, 3) 执行这句话时,相当于做了对象的调用,因此调用了Timer的__call__函数,因此参数(2, 3)就传入了__call__里,开始执行函数内部,self.func就是原来的add函数。

带参数的类装饰器

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import time

class Timer:
def __init__(self, prefix):
self.prefix = prefix

def __call__(self, func):
def wrapper(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
print(f"{self.prefix}{time.time() - start}")
return ret
return wrapper

@Timer(prefix="curr_time: ")
def add(a, b):
return a + b

# 完全等价
add = Timer(prefix="curr_time: ")(add)

print(add(2, 3))

想实现一个功能,先打印一个prefix字符串,再打印时间。

Timer输入参数prefix,返回一个函数,比如把Timer(prefix)记为k,也就是k=Timer(prefix),这个函数k当call时,也就是k(add)时,也要输出一个函数(再赋给add),因此在Timer类的__call__()方法里return的是一个函数对象,也就是wrapper(*args, **kwargs)

执行add(2, 3)时,也就是执行wrapper(*args, **kwargs)的函数内部代码。

类的装饰器

上面更像是装饰器的类,这里介绍类的装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def add_str(cls):
def __str__(self): #通过重载__str__来改变它print的值
return str(self.__dict__)
cls.__str__ = __str__
return cls

@add_str
class MyObject:
def __init__(self, a, b):
self.a = a
self.b = b

# 完全等价
# MyObject = add_str(MyObject)

o = MyObject(1, 2)
print(o)

# 输出
{'a': 1, 'b': 2}

在python里面,一个自定义类class的对象,当 print 它时,它不会打印出什么,只会打印出这个对象是一个什么类。

可以通过重载它的__str__函数,来改变它print出来的结果

但是每个class都改很麻烦,于是写一个装饰类的装饰器。

上面的例子中,add_str输入是一个class,返回也是这个class(同一个class),只不过重载了它的print方法,把cls的__str__函数替换成了自定义的__str__函数。