key = (args, frozenset(kwargs.items())
这是您无需对数据做出假设即可做到的“最佳”。
然而,想要对字典进行记忆似乎是可以想象的(虽然有点不寻常),如果你愿意的话,你可以特殊情况。例如,您可以在复制字典时递归地应用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
编辑: Ignacio 说:“虽然您不能在任意 dicts 上使用 sorted(),但 kwargs 将具有 str 键。”这是完全正确的。因此,这不是键的问题,但如果您(或不太可能的代表)以某种方式依赖排序,则可能需要牢记值。
关于使用str:
大多数数据会很好地工作,但对手(例如在安全漏洞环境中)可能会制造冲突。介意你并不容易,因为大多数默认的reprs 使用了很多好的分组和转义。事实上,我找不到这样的碰撞。但如果第三方草率或不完整的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 函数中得到不正确的结果。如前所述,一种可能非常棘手的解决方法是使用正则表达式检测此类对象。