[英]Validated Function Arguments in Python
我有一个功能
def func(a,b,c,d):
...
我正在尝试编写一个了解参数的装饰器,并将其中一些记录到另一个系统中。
def decorator(func):
def new_func(*args, **kwargs):
if (func.__name__ == 'func'):
a = ?
b = ?
c = ?
d = ?
else:
a = ?
b = ?
c = ?
d = ?
log_to_system(a, b, c, d)
return func(*args, **kwargs)
return new_func
问题是装饰器没有一种简单的方法从args和kwargs中提取a,b,c,d值,因为用户可以使用位置或关键字参数传递这些值。 我也希望保持这种通用性,因为这个装饰器可以用于各种不同的功能。
是否有一个库或实用程序可以轻松地从args和kwargs中提取参数的值?
一个简单的方法是让你的log_to_system
函数接受变量参数和变量关键字参数以及它实际记录的已知参数,这样你就可以简单地将变量参数和变量关键字参数从装饰函数传递给log_to_system
并让解释器为您提取参数a
, b
, c
和d
:
def log_to_system(a, b, c, d, *args, **kwargs):
print(a, b, c, d)
def decorator(func):
def new_func(*args, **kwargs):
log_to_system(*args, **kwargs)
return func(*args, **kwargs)
return new_func
@decorator
def func(a, b, c, d, e):
pass
func(1, 2, c=3, d=4, e=5)
这输出:
1 2 3 4
或者,您可以使用inspect.signature
在将给定的变量参数和关键字参数绑定到装饰函数的签名之后获取参数的dict,以便您可以仅使用所需的参数调用log_to_system
:
import inspect
def log_to_system(a, b, c, d):
print(a, b, c, d)
def decorator(func):
sig = inspect.signature(func)
def new_func(*args, **kwargs):
arguments = sig.bind(*args, **kwargs).arguments
log_to_system(**{k: arguments[k] for k in log_to_system.__code__.co_varnames})
return func(*args, **kwargs)
return new_func
@decorator
def func(a, b, c, d, e):
pass
func(1, 2, c=3, d=4, e=5)
这输出:
1 2 3 4
您可以使用inspect
,工作示例:
import inspect
def deco(func):
signature = inspect.signature(func)
def _deco(*args, **kwargs):
binded = signature.bind(*args, **kwargs)
arguments = binded.arguments # OrderedDict
print(arguments.items())
return func(*args, **kwargs)
return _deco
@deco
def foo(a, b, c, d):
pass
@deco
def bar(d, c, b, a):
pass
foo(1, 2, c=3, d=4) # odict_items([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
bar(1, a=2, b=3, c=4) # odict_items([('d', 1), ('c', 4), ('b', 3), ('a', 2)])
您可以使用此通用装饰器来转储参数值:
def dump_args(func):
# Decorator to print function call details - parameters names and effective values
def wrapper(*func_args, **func_kwargs):
arg_names = func.__code__.co_varnames[:func.__code__.co_argcount]
args = func_args[:len(arg_names)]
defaults = func.__defaults__ or ()
args = args + defaults[len(defaults) - (func.__code__.co_argcount - len(args)):]
params = list(zip(arg_names, args))
args = func_args[len(arg_names):]
if args: params.append(('args', args))
if func_kwargs: params.append(('kwargs', func_kwargs))
return func(*func_args, **func_kwargs)
return wrapper
Credits属于@aliteralmind,他在这篇StackOverflow 帖子中建议了这个装饰器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.