正如其他人在此处所写,装饰器是函数的语法糖(即,使程序更易于阅读、编写或理解),它接收另一个函数作为参数并从内部激活它。
所以,用装饰器调用这个“Add()”函数,像这样:
@wrapper()
def Add(x: int, y: int):
return x + y
这就像使用“Add”函数作为变量调用“wrapper”函数一样。像这样:
wrapper(Add)(x,y) # pass x,y to wrapper that pass it to Add function.
因此,(我发现)向装饰器添加参数的最佳方法是将其全部嵌套在另一个包含子装饰器的函数下。例如:
@deco_maker(msg: str)
def Add(x: int, y: int):
return x + y
会是这样的:
deco_maker(msg)(wrapper(Add))(x,y)
所以,这里有一个简单的包装装饰器,它记录函数调用,不带参数,如下所示:
def wrapper(func: Callable):
def wrapper_func(*args, **kwargs):
logging.DEBUG f"Function '{func.__name__}' called with args: {[str(arg) for arg in args]}."
value = func(*args, **kwargs)
return value
return wrapper_func
这里是带有相关日志记录参数的扩展装饰器(日志名称和级别以获得更大的灵活性):
def log_func_calls(logger_name: str, log_level: int):
def wrapper(func: Callable):
def wrapper_func(*args, **kwargs):
logger = logging.getLogger(logger_name)
logger.log(
level=log_level,
msg=f"Function '{func.__name__}' called with args: {[str(arg) for arg in args]}."
)
value = func(*args, **kwargs)
return value
return wrapper_func
return wrapper
这是一个用于记录函数调用的参数化装饰器的完整代码示例,并在其后打印日志文件输出。
示例:
import logging
from typing import Callable
# define app logger with file and console handlers
def setup_logging():
logger = logging.getLogger('test_app')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('test.log')
fh.setLevel(logging.DEBUG)
# create formatter and add it to the file handler
formatter = logging.Formatter('{asctime} | {name} | {levelname:^8s} | {message}', style='{')
fh.setFormatter(formatter)
# add the handler to the logger
logger.addHandler(fh)
return logger
# define a log decorator to trace function calls
def log_func_calls(logger_name: str, log_level: int):
def wrapper(func: Callable):
def wrapper_func(*args, **kwargs):
logger = logging.getLogger(logger_name)
logger.log(
level=log_level,
msg=f"Function '{func.__name__}' called with args: {[str(arg) for arg in args]}."
)
value = func(*args, **kwargs)
return value
return wrapper_func
return wrapper
# sample usage 1
@log_func_calls(logger_name='test_app', log_level=logging.DEBUG)
def Add(x: int, y: int):
return x + y
# sample usage 2
@log_func_calls(logger_name='test_app', log_level=logging.DEBUG)
def Sub(x: int, y: int):
return x - y
# a test run
def main():
logger = setup_logging()
logger.info("<<< App started ! >>>")
print(Add(50,7))
print(Sub(10,7))
print(Add(50,70))
logger.info("<<< App Ended ! >>>")
if __name__ == "__main__":
main()
还有日志输出:
...
2022-06-19 23:34:52,656 | test_app | DEBUG | Function 'Add' called with args: ['50', '7'].
2022-06-19 23:34:52,656 | test_app | DEBUG | Function 'Sub' called with args: ['10', '7'].
2022-06-19 23:34:52,657 | test_app | DEBUG | Function 'Add' called with args: ['50', '70'].
...