若您将参数始终用作位置或始终用作关键字,则Thorsten解决方案可以很好地工作。但是,如果要考虑给参数提供相同值的相等调用,而不考虑参数的传递方式,则必须执行更复杂的操作:import inspect
def make_key_maker(func):
args_spec = inspect.getargspec(func)
def key_maker(*args, **kwargs):
left_args = args_spec.args[len(args):]
num_defaults = len(args_spec.defaults or ())
defaults_names = args_spec.args[-num_defaults:]
if not set(left_args).symmetric_difference(kwargs).issubset(defaults_names):
# We got an error in the function call. Let's simply trigger it
func(*args, **kwargs)
start = 0
key = []
for arg, arg_name in zip(args, args_spec.args):
key.append(arg)
if arg_name in defaults_names:
start += 1
for left_arg in left_args:
try:
key.append(kwargs[left_arg])
except KeyError:
key.append(args_spec.defaults[start])
# Increase index if we used a default, or if the argument was provided
if left_arg in defaults_names:
start += 1
return tuple(key)
return key_maker
上面的函数尝试将关键字参数(和默认值)映射到位置,并使用结果元组作为键。我测试了一下,它在大多数情况下都能正常工作。
当目标函数也使用**kwargs参数时,它将失败。在
^{pr2}$