假设我具有以下功能:
def do_something(arg_1, arg_2, arg_3):
logger.info('arg_1: {0} arg_2: {1} arg_3: {2}'.format(arg_1, arg_2, arg_3))
print('Doing something..')
是否有一种优雅的方式来记录函数的所有参数而不列出参数名称?
答案 0 :(得分:3)
我相信,这是钻研装饰工的绝佳时机。看一下以下内容:
<view:NavigationView DataContext="{Binding NavigationViewModel}" />
def log_args(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
logger.info(', '.join(str(x) for x in args))
return function(*args, **kwargs)
return wrapper
行是可选的
现在像这样装饰您的功能:
@functools.wraps
说明:@log_args
def do_something(arg1, arg2):
print('doing something..')
行与这样做相同:
@log_args
现在,此do_something = log_args(do_something)
接受函数并输入其本地范围。在此范围内,定义了另一个函数,称为包装器。该函数包含将args格式化为字符串的记录器。然后,从包装器返回函数的结果。为了确保log_args
仍然是一个函数,我返回了do_something
。现在,当调用wrapper
时,实际上将调用包装器,并且将发生上述过程。
之所以使用装饰器,是因为我可以保留函数定义中的显式名称参数,但是,在装饰器中,我可以使用do_something
将这些参数打包到列表中,即使函数本身仅命名为args。 注意:关于保留参数的最后一点,我不确定100%。实际上,我根本不认为这是真的。
答案 1 :(得分:1)
要扩展@NChauhan的答案,如果您希望不仅可以记录位置参数的值,还可以记录位置参数和关键字参数的名称以及它们的给定值和默认值,那么:
@log_args
def do_something(arg_1, arg_2, arg_3='world'):
pass
do_something(2, arg_2='hello')
可以输出:
do_something called with arg_1: 2, arg_2: 'hello', arg_3: 'world'
您可以将inspect.signature
与装饰器一起使用:
import inspect
from functools import wraps
def log_args(func):
@wraps(func)
def wrapper(*args, **kwargs):
bound = sig.bind(*args, **kwargs)
bound.apply_defaults()
print('{} called with {}'.format(func.__name__, ', '.join('{}: {}'.format(name, repr(value)) for name, value in bound.arguments.items())))
return func(*args, **kwargs)
sig = inspect.signature(func)
return wrapper