装饰器基础二装饰类的装饰器
类可以做装饰器,也可以被装饰器装饰,被装饰器装饰,那这个装饰器可以接收一个类,返回一个类
1、装饰类的装饰器-输入类返回类
def add_str(cls):
def __str__(self):
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(type(o))
print(o)
2、先实现普通函数装饰器
def log_func(func):
def wrapper(*args, **kwargs):
print('func start!')
print(f'args: {args}')
res = func(*args, **kwargs)
print('func end!')
return res
return wrapper
@log_func
def fib(n):
if n <= 1:
return 0
return fib(n - 1) + fib(n - 2)
# print(fib(3))
2.1、普通函数装饰器用类包起来, 直接实例化类调用装饰器
class Decorator:
def log_func(self, func):
def wrapper(*args, **kwargs):
print('func start!')
print(f'args: {args}')
res = func(*args, **kwargs)
print('func end!')
return res
return wrapper
d = Decorator()
@d.log_func
def fib(n):
if n <= 1:
return 0
return fib(n - 1) + fib(n - 2)
print(fib(4))
2.2、使用类方法装饰器
class Decorator:
@classmethod
def log_func(cls, func):
def wrapper(*args, **kwargs):
print('func start!')
print(f'args: {args}')
res = func(*args, **kwargs)
print('func end!')
return res
return wrapper
@Decorator.log_func
def fib(n):
if n <= 1:
return 0
return fib(n - 1) + fib(n - 2)
print(fib(4))
2.3、使用静态方法装饰器
class Decorator:
@staticmethod
def log_func(func):
def wrapper(*args, **kwargs):
print('func start!')
print(f'args: {args}')
res = func(*args, **kwargs)
print('func end!')
return res
return wrapper
@Decorator.log_func
def fib(n):
if n <= 1:
return 0
return fib(n - 1) + fib(n - 2)
print(fib(4))
总结:上面实现的是类装饰器给外部函数调用,内部的装饰器函数可以是静态方法,类方法,或者实例方法,那类内部这个装饰器可以给类内部实例方法使用吗?
答案是可以,但是需要像下面这么写。
3、给类方法使用的类装饰器
class Decorator:
# @staticmethod
def log_func(func):
def wrapper(*args, **kwargs):
print('func start!')
print(f'args: {args}')
res = func(*args, **kwargs)
print('func end!')
return res
return wrapper
@log_func
def fib(self, n):
if n <= 1:
return 0
return fib(n - 1) + fib(n - 2)
d = Decorator()
print(d.fib(4))
print('结束')
此时装饰器方法不是实例方法,类方法,静态方法,此时他可以说是类辅助函数装饰器,内部调用没有问题。
但是外部调用就出问题了~
# 外部调用
d = Decorator()
@d.log_func
def f(): # 会报TypeError
pass
外部调用会报TypeError,参数异常。 外部调用时解释器会把类中log_func这个辅助函数当成一个正常实例方法解读,而这个方法中缺少了self,而使用Decorator类的方式外部直接调用则不会报错。此时外部应该使用类直接调用。
@Decorator.log_func
def f(): # 正常输出
pass
4、哪有没有在类中或外部不管通过实例还是类方法均可调用呢,有的,需要在最后一行加如下代码: log_func = staticmethod(log_func) 或者在函数使用@staticmethod修饰成静态方法
class Decorator:
# @staticmethod
def log_func(func):
def wrapper(*args, **kwargs):
print('func start!')
print(f'args: {args}')
res = func(*args, **kwargs)
print('func end!')
return res
return wrapper
@log_func
def fib(self, n):
if n <= 1:
return 0
return fib(n - 1) + fib(n - 2)
log_func = staticmethod(log_func)
# 内部调用
d = Decorator()
print(d.fib(4))
# 对象实例调用
d = Decorator()
@d.log_func
def f(): # 会报TypeError
pass
# 类调用
@Decorator.log_func
def g(): # 正常输出
pass