识别等效的varargs函数调用以进行记忆 [英] Identifying equivalent varargs function calls for memoization
问题描述
我正在使用此装饰器的变体来进行记忆:>
I'm using a variant of the this decorator for memoization:
# note that this decorator ignores **kwargs
def memoize(obj):
cache = obj.cache = {}
@functools.wraps(obj)
def memoizer(*args, **kwargs):
if args not in cache:
cache[args] = obj(*args, **kwargs)
return cache[args]
return memoizer
我想知道,有没有一种合理的方式同时基于 args
和 kwargs
进行记忆,特别是在两个函数调用的参数指定位置和位置不同的情况下通过关键字,但参数完全相同?
I'm wondering, is there a reasonable way to memoize based on both args
and kwargs
, particularly in cases where two function calls specified with arguments assigned differently positionally and through keyword, but have the exact same arguments?
推荐答案
如果您总是将参数用作位置或关键字,则Thorsten解决方案可以很好地工作.但是,如果要考虑给参数赋予相同值的相等调用,而与参数的传递方式无关,那么您就必须做一些更复杂的事情:
If you are using parameters either always as positionals or always as keywords, Thorsten solution works fine. But, if you want to consider equal calls that give to the parameters the same values, indipendently of how the parameters are passed, then you have to do something more complex:
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
参数时,它将失败.
The above functions tries to map keyword arguments(and defaults) to positional and uses the resultant tuple as key. I tested it a bit and it seems to work properly in most cases.
It fails when the target function also uses a **kwargs
argument.
>>> def my_function(a,b,c,d,e=True,f="something"): pass
...
>>> key_maker = make_key_maker(my_function)
>>>
>>> key_maker(1,2,3,4)
(1, 2, 3, 4, True, 'something')
>>> key_maker(1,2,3,4, e=True) # same as before
(1, 2, 3, 4, True, 'something')
>>> key_maker(1,2,3,4, True) # same as before
(1, 2, 3, 4, True, 'something')
>>> key_maker(1,2,3,4, True, f="something") # same as before
(1, 2, 3, 4, True, 'something')
>>> key_maker(1,2,3,4, True, "something") # same as before
(1, 2, 3, 4, True, 'something')
>>> key_maker(1,2,3,d=4) # same as before
(1, 2, 3, 4, True, 'something')
>>> key_maker(1,2,3,d=4, f="something") # same as before
(1, 2, 3, 4, True, 'something')
这篇关于识别等效的varargs函数调用以进行记忆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!