装饰器(Decorator)---- 是在代码运行期间动态增加功能的方式。本质上,decorator就是一个返回函数的高阶函数。
在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。
decorator可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。
1.无参数的装饰器
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2018-12-11')
运行结果
2.有参数的装饰器
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print('2018-12-11')
运行结果:
此时,会发现经过decorator装饰之后的函数,它们的__name__
已经从原来的'now'
变成了'wrapper'
:
Python内置的functools.wraps
()可以帮我们解决这个问题,代码改进如下:
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print('2018-12-11')
运行结果:
3.练习
(1)请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间
import time, functools
import functools
def metric(fn):
@functools.wraps(fn)
def wrapper(*args, **kw):
t0 = time.time()
result = fn(*args, **kw)
print('%s executed in %.4f ms' % (fn.__name__, time.time() - t0))
return result # return fn(*args, **kw)
return wrapper
# 测试
@metric
def fast(x, y):
time.sleep(0.0012)
return x + y;
@metric
def slow(x, y, z):
time.sleep(0.1234)
return x * y * z;
f = fast(11, 22)
s = slow(11, 22, 33)
if f != 33:
print('测试失败!')
elif s != 7986:
print('测试失败!')
(2)请编写一个decorator,能在函数调用的前后打印出'begin call'
和'end call'
的日志
def log(func):
def wrapper(*args,**kw):
print('begin call:%s ' % func.__name__)
c = func(*args,**kw)
print('end call:%s ' % func.__name__)
return c
return wrapper
@log
def now():
print('2018-12-11')
运行结果:
(3) 出一个@log
的decorator,使它既支持
@log
def f():
pass
又支持:
@log('execute')
def f():
pass
代码如下:
import functools
def log(text=''):
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print('%s %s ' % (text,func.__name__))
return func(*args,**kw)
return wrapper
return decorator
@log('execute')
def now():
print('2018-12-11')
@log()
def now1():
print('2018-12-11')
运行结果: