9.4 定义一个带�数的装饰器¶
问题¶
ä½ æƒ³å®šä¹‰ä¸€ä¸ªå�¯ä»¥æŽ¥å�—å�‚数的装饰器
解决方案¶
我们用一个例å�详细é˜�述下接å�—å�‚数的处ç�†è¿‡ç¨‹ã€‚ å�‡è®¾ä½ æƒ³å†™ä¸€ä¸ªè£…é¥°å™¨ï¼Œç»™å‡½æ•°æ·»åŠ æ—¥å¿—åŠŸèƒ½ï¼Œå�Œæ—¶å…�许用户指定日志的级别和其他的选项。 下é�¢æ˜¯è¿™ä¸ªè£…饰器的定义和使用示例:
from functools import wraps
import logging
def logged(level, name=None, message=None):
"""
Add logging to a function. level is the logging
level, name is the logger name, and message is the
log message. If name and message aren't specified,
they default to the function's module and name.
"""
def decorate(func):
logname = name if name else func.__module__
log = logging.getLogger(logname)
logmsg = message if message else func.__name__
@wraps(func)
def wrapper(*args, **kwargs):
log.log(level, logmsg)
return func(*args, **kwargs)
return wrapper
return decorate
# Example use
@logged(logging.DEBUG)
def add(x, y):
return x + y
@logged(logging.CRITICAL, 'example')
def spam():
print('Spam!')
åˆ�看起æ�¥ï¼Œè¿™ç§�实现看上去很å¤�æ�‚ï¼Œä½†æ˜¯æ ¸å¿ƒæ€�想很简å�•。
最外层的函数 logged() 接��数并将它们作用在内部的装饰器函数上�。
内层的函数 decorate() 接�一个函数作为�数,然�在函数上�放置一个包装器。
这里的关键点是包装器是å�¯ä»¥ä½¿ç”¨ä¼ 递给 logged() çš„å�‚数的。
讨论¶
定义一个接å�—å�‚数的包装器看上去比较å¤�æ�‚主è¦�æ˜¯å› ä¸ºåº•å±‚çš„è°ƒç”¨åº�åˆ—ã€‚ç‰¹åˆ«çš„ï¼Œå¦‚æžœä½ æœ‰ä¸‹é�¢è¿™ä¸ªä»£ç �:
@decorator(x, y, z)
def func(a, b):
pass
装饰器处ç�†è¿‡ç¨‹è·Ÿä¸‹é�¢çš„è°ƒç”¨æ˜¯ç‰æ•ˆçš„;
def func(a, b):
pass
func = decorator(x, y, z)(func)
decorator(x, y, z) 的返回结果必须是一个�调用对象,它接�一个函数作为�数并包装它,
å�¯ä»¥å�‚考9.7å°�节ä¸å�¦å¤–一个å�¯æŽ¥å�—å�‚数的包装器例å�。