jua*_*nza 18 python memoization
我还没有看到一种既定的方法来记忆一个带有关键字参数的函数,即类型的东西
def f(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
因为通常一个memoizer有一个dict缓存给定输入参数集的结果,并且kwargs是一个dict因此不可用的.我在这里讨论后尝试过使用
(args, frozenset(kwargs.items()))
Run Code Online (Sandbox Code Playgroud)
作为缓存的关键dict,但这仅在值为kwargshashable 时才有效.此外,正如下面的答案中所指出的那样,frozenset它不是有序的数据结构.因此,此解决方案可能更安全:
(args, tuple(sorted(kwargs.items())))
Run Code Online (Sandbox Code Playgroud)
但它仍然无法应对不可清除的元素.我所看到的另一种方法是使用string的表示kwargs在缓存中的关键:
(args, str(sorted(kwargs.items())))
Run Code Online (Sandbox Code Playgroud)
我看到的唯一缺点是散列可能非常长的字符串的开销.据我所知,结果应该是正确的.有人能发现后一种方法有什么问题吗?下面的答案之一指出,这假定了关键字参数值的函数__str__或__repr__函数的某些行为.这似乎是一个显示阻止.
还有另一种更成熟的实现备忘的方法,可以应对**kwargs和不可消除的论证价值吗?
nin*_*cko 11
key = (args, frozenset(kwargs.items())
Run Code Online (Sandbox Code Playgroud)
这是您在不对数据进行假设的情况下可以做到的"最佳".
然而,想要在字典上执行memoization似乎是可以想象的(尽管有点不寻常),如果你需要它,你可以特殊情况.例如,您可以frozenset(---.items())在复制字典时递归应用.
如果你这样做sorted,你可能处于一个糟糕的情况,你有无法解决的密钥.例如," 子集和相等比较不会推广到完整的排序函数.例如,任何两个不相交的集合都不相等而且不是彼此的子集,所以以下所有都返回False:ab.因此,集合做没有实现cmp()方法. "
>>> sorted([frozenset({1,2}), frozenset({1,3})])
[frozenset({1, 2}), frozenset({1, 3})]
>>> sorted([frozenset({1,3}), frozenset({1,2})]) # THE SAME
[frozenset({1, 3}), frozenset({1, 2})] # DIFFERENT SORT RESULT
# sorted(stuff) != sorted(reversed(stuff)), if not strictly totally ordered
Run Code Online (Sandbox Code Playgroud)
编辑: Ignacio说:"虽然你不能在任意的dicts上使用sorted(),但是kwargs会有str键." 这是完全正确的.因此,这对于密钥来说不是问题,但如果您(或者不太可能的代表)依赖于某种方式进行排序,则可能需要记住值.
关于使用str:
它是这样大多数数据将很好地工作,但它是可能的对手(例如,在安全漏洞上下文)制作一个碰撞.这并不容易让你repr高兴,因为大多数默认使用很多好的分组和逃脱.事实上,我无法找到这样的碰撞.但是有可能是草率的第三方或不完整的repr实现.
还要考虑以下内容:如果您存储的密钥类似于((<map object at 0x1377d50>,), frozenset(...))和((<list_iterator object at 0x1377dd0>,<list_iterator object at 0x1377dd0>), frozenset(...)),则只需调用相同的项目,缓存就会无限增长.(你可以使用正则表达式来解决这个问题...)并且尝试使用生成器会搞乱你正在使用的函数的语义.这可能是期望的行为,但是如果你想要记住is风格上的平等而不是==风格的平等.
str({1:object()})在解释器中执行某些操作每次都会在内存中的同一位置返回一个对象!我认为这是工作中的垃圾收集器.这将是灾难性的,因为如果您碰巧是哈希<some object at 0x???????>并且您碰巧在稍后的同一内存位置创建了相同类型的对象(由于垃圾回收),您将从memoized函数获得不正确的结果.如前所述,一个可能非常糟糕的解决方法是使用正则表达式检测此类对象.