我在@Menglong Li的答案中提到了一些问题并简化了代码。
import inspect
import functools
def ignore_unmatched_kwargs(f):
"""Make function ignore unmatched kwargs.
If the function already has the catch all **kwargs, do nothing.
"""
if contains_var_kwarg(f):
return f
@functools.wraps(f)
def inner(*args, **kwargs):
filtered_kwargs = {
key: value
for key, value in kwargs.items()
if is_kwarg_of(key, f)
}
return f(*args, **filtered_kwargs)
return inner
def contains_var_kwarg(f):
return any(
param.kind == inspect.Parameter.VAR_KEYWORD
for param in inspect.signature(f).parameters.values()
)
def is_kwarg_of(key, f):
param = inspect.signature(f).parameters.get(key, False)
return param and (
param.kind is inspect.Parameter.KEYWORD_ONLY or
param.kind is inspect.Parameter.POSITIONAL_OR_KEYWORD
)
以下是一些测试用例:
@ignore_unmatched_kwargs
def positional_or_keywords(x, y):
return x, y
@ignore_unmatched_kwargs
def keyword_with_default(x, y, z = True):
return x, y, z
@ignore_unmatched_kwargs
def variable_length(x, y, *args, **kwargs):
return x, y, args,kwargs
@ignore_unmatched_kwargs
def keyword_only(x, *, y):
return x, y
print(
positional_or_keywords(x = 3, y = 5, z = 10),
positional_or_keywords(3, y = 5),
positional_or_keywords(3, 5),
positional_or_keywords(3, 5, z = 10),
keyword_with_default(2, 2),
keyword_with_default(2, 2, z = False),
keyword_with_default(2, 2, False),
variable_length(2, 3, 5, 6, z = 3),
keyword_only(1, y = 3),
sep='\n'
)
print(
sep = '\n'
)
f(10, b=20)
在这里会打印出10
,如果你只使用**kwargs
是不正确的。 - abarnerta=None
。另外还有一个替代版本是:使用**_
代替**kwargs
。 - undefined