接上一篇:
1、【Python】学点装饰器(1)
1. 不带参数的类装饰器
基于类的装饰器的实现,必须实现__call__
和__init__
两个内置函数:
-
__call__
:接收被装饰的函数; -
__init__
:实现装饰逻辑
1.1 类装饰器实现
日志打印装饰器
class logger(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[INFO]: the function {func}() is running...".format(func=self.func.__name__))
return self.func(*args, **kwargs)
1.2 类装饰器应用
@logger
def say_some(something):
print("I say {}!".format(something))
if __name__ == "__main__":
say_some("你好")
运行结果:
[INFO]: the function say_some() is running...
I say 你好!
2. 带参数的类装饰器
- 不带参数的装饰器,只能打印出
INFO
级别的日志,那如果需要打印WARNING
或DEBUG
等级别的日志的话,就需要给类装饰器传入参数,给这个函数指定级别; - 带参数和不带参数的装饰器有很大区别:
-
__init__
:不再接收被装饰函数,而是接收传入参数; -
__call__
:接收被装饰函数,实现装饰逻辑;
-
2.1 带参数的类装饰器例子实现
class LoggerDecorator(object):
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print("[{level}]: the function {func}() is running...".format(level=self.level,func=func.__name__))
func(*args, **kwargs)
return wrapper
@LoggerDecorator(level='DEBUG')
def say_some(some):
print("say {}!".format(some))
if __name__ == "__main__":
say_some("hello")
运行结果:
- 这里执定
level
级别为DEBUG
;
[DEBUG]: the function say_some() is running...
say hello!
3. 使用偏函数和类实现装饰器
Python 对某个对象是否能通过装饰器( @decorator
)形式使用只有一个要求:decorator 必须是一个“可被调用(callable)的对象。对于这个callable对象,我们最熟悉的就是函数了,绝大多数装饰器都是基于函数和闭包实现的。除函数之外,类也可以是 callable 对象,只要实现了__call__
函数,偏函数其实也是 callable 对象。
3.1 实现
import time
import functools
# 延时类
class DelayFunc(object):
def __init__(self, duration, func):
self.duration = duration
self.func = func
def __call__(self, *args, **kwargs):
print(f'Wait for {self.duration} seconds...')
time.sleep(self.duration)
return self.func(*args, **kwargs)
def eager_call(self, *args, **kwargs):
print('Call without delay')
return self.func(*args, **kwargs)
# 延时装饰器
def delay(duration):
"""
装饰器:推迟某个函数的执行。
同时提供 .eager_call 方法立即执行
"""
# 此处为了避免定义额外函数,
# 直接使用 functools.partial 帮助构造 DelayFunc 实例
return functools.partial(DelayFunc, duration)
# 业务函数
@delay(duration=1)
def add(a, b):
return a+b
if __name__ == "__main__":
test_add = add(5, 6)
print(test_add)
print("add: {}".format(add))
print("add.func: {}".format(add.func))
print(">>>>>>>>>>>>>>>>>>>>")
test_without_delay = add.eager_call(5, 5)
print("test_without_delay: {}".format(test_without_delay))
3.2 运行结果
Wait for 1 seconds...
11
add: <__main__.DelayFunc object at 0x000001FD6763E668>
add.func:
>>>>>>>>>>>>>>>>>>>>
Call without delay
test_without_delay: 10
Process finished with exit code 0