首先要明白装饰器是用来给函数增加额外功能的。
常用的工具函数
import time
from functools import wraps
import inspect
import sys
import logging
def timeit(func):
"""统计函数运行时间"""
t0 = time.perf_counter()
func()
return time.perf_counter() - t0
def count(func):
"""统计递归函数执行次数"""
# @wraps(func)
def counted(args):
counted.call_count += 1
return func(args)
counted.call_count = 0
return counted
def memorize(f):
"""缓存"""
cache = {}
@wraps(f)
def memorized(args):
if args not in cache:
cache[args] = f(args)
return cache[args]
return memorized
def trace(func):
"""跟踪函数,便于查看过程。"""
def afunc(args):
print("call", func.name, "with", args)
v = func(args)
print(func.name, "return ",v)
return v
return afunc
def main(fn):
"""@main ---> name == "main" """
if inspect.stack()[1][0].f_locals['name'] == 'main':
args = sys.argv[1:] # Discard the script name from command line
fn(*args) # Call the main function
return fn
带参数的装饰器
def logged(level, name=None, message=None):
def decorate(func):
logname = name if name else func.module
log = logging.getLogger(logname)
@wraps(func)
def wrapper(*args, *kwargs):
logmsg = "{}--call --{}".format(func.name, args)
log.log(level, logmsg)
return func(args, **kwargs)
return wrapper
return decorate
统计调用次数 增加缓存 增加debug 功能。
@logged(logging.DEBUG)
@count
@memorize
def fib(x):
return x if x < 2 else fib(x-1) + fib(x-2)
print(fib(10), fib.dict)
非常好的实现
flask 和 bottle 中的路由绑定
将add_url_rule 进行了一层包装,能够很简洁的使用装饰器的语法来绑定路由
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
@route('/')
def example():
pass