我解决了@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 any(param.kind == inspect.Parameter.VAR_KEYWORD for param in inspect.signature(f).parameters.values()):
return f
#
@functools.wraps(f)
def inner(*args,**kwargs):
# For each keyword arguments recognised by f,
# take their binding from **kwargs received
filtered_kwargs = {
name:kwargs[name]
for name,param in inspect.signature(f).parameters.items() if (
param.kind is inspect.Parameter.KEYWORD_ONLY or
param.kind is inspect.Parameter.POSITIONAL_OR_KEYWORD
) and
name in kwargs
}
return f(*args,**filtered_kwargs)
return inner
这里有一些广泛的测试用例:
@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
# these test should run without error
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'
)
# these test should raise error
print(
#positional_or_keywords(3,5,6,4),
#keyword_with_default(2,2,3,z=False),
#keyword_only(1,2),
sep='\n'
)