1.请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:
import functools
import time
def metric(fn):
@functools.wraps(fn)
def wrapper(*args, **kw):
start = time.time()
res = fn(*args, **kw)
end = time.time()
print('%s executed in %s ms' % (fn.__name__, end - start))
return res
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'
的日志。
import functools
def call(fn):
@functools.wraps(fn)
def wrapper(*args, **kw):
print('begin call')
res = fn(*args, **kw)
print('end call')
return res
return wrapper
3.再思考一下能否写出一个@log
的decorator,使它既支持:
@log
def f():
pass
又支持:
@log('execute')
def f():
pass
评论看到的可以实现的:
import functools
from types import FunctionType, MethodType
def log(param):
# 这是真正的装饰器,根据条件提供fn
def pre_decorator(fn, text=None):
@functools.wraps(fn)
def wrapper(*args, **kw):
print('func:%s log start...' % fn.__name__)
# 如果text不为空,则打印text
if text is not None:
print("param: %s" % param)
res = fn(*args, **kw)
print('func:%s log end...' % fn.__name__)
return res
return wrapper
# 如果param是可调用对象,直接返回装饰器
if param is isinstance(param, (FunctionType, MethodType)) or hasattr(param, '__call__'):
return pre_decorator(param)
def decorator(func):
return pre_decorator(func, param)
return decorator
@log
def log_1():
print('装饰器无参数测试.')
@log("qaaasd阿山东山东的山东撒到山东山东的撒到")
def log_2():
print('装饰器有参数测试.')
log_1()
print('---------------------------------------')
log_2()
自己尝试但失败的:
import functools
def log(text):
def decorator(fn):
@functools.wraps(fn)
def wrapper(*args, **kw):
print('%s begin call, log text:%s' % (fn.__name__, text))
res = fn(*args, **kw)
print('%s end call, log text:%s' % (fn.__name__, text))
return res
return wrapper
return decorator
@log()
def f1():
print('run f1')
@log('execute')
def f2():
print('run f2')
f2()
f1()