【问题标题】:How to quickly compute a hash for a collection of objects?如何快速计算对象集合的哈希?
【发布时间】:2014-07-29 21:45:18
【问题描述】:

考虑一个函数f(*x),它接受很多参数*x。基于这些参数(对象),函数f 组成一个相当复杂的对象o 并返回它。 o 实现了__call__,所以o 本身就是一个函数。由于o 的组合非常耗时,而且在我的场景中,基于相同的参数*x 拥有多个o 实例是没有意义的,它们将被缓存。

现在的问题是:如何有效地计算基于多个参数*x 的哈希?目前我正在使用 python 字典,我连接每个 xstr() 表示来构建每个键。它适用于我的场景,但感觉相当尴尬。我需要以非常高的频率调用生成的对象o,所以我怀疑重复调用str() 和字符串连接会浪费大量计算时间。

【问题讨论】:

  • *x中的参数有哪些类型?
  • 就我而言,参数有多种类型。我通常有整数元组、一些浮点数和至少一个来自另一个库的上下文对象的 str() 表示。
  • 那么我建议简单地在各个参数上调用hash(),以便使用 Python 在内部使用的相同哈希值来比较字典键。

标签: python caching hash hashmap


【解决方案1】:

您可以使用hash 内置函数,将x 中项目的哈希值组合在一起。执行此操作的典型方法(例如,参见 the documentation)是在单个对象的所有散列中使用 xor

建议以某种方式混合在一起(例如,使用异或)对象组件的哈希值,这些组件也参与对象比较

使用operatorreduce 以功能方式实现它:

from functools import reduce # only required in Python 3.x
from operator import xor

def hashed(*x):
    return reduce(xor, map(hash, x))

另见this question

【讨论】:

    【解决方案2】:

    从 3.2 版开始,Python 已经包含了一个 LRU 缓存的实现,您可以使用它 根据参数缓存函数的结果: functools.lru_cache

    例子:

    from functools import lru_cache
    
    @lru_cache(maxsize=32)
    def f(*args):
        """Expensive function
        """
        print("f(%s) has been called." % (args, ))
        return sum(args)
    
    
    print(f(1, 2, 3))
    print(f(1, 2, 3, 4))
    print(f(1, 2, 3))
    print(f.cache_info())
    

    输出:

    f((1, 2, 3)) has been called.
    6
    f((1, 2, 3, 4)) has been called.
    10
    6
    CacheInfo(hits=1, misses=2, maxsize=32, currsize=2)
    

    (注意f(1, 2, 3) 只被调用一次)

    按照 cmets 中的建议,最好简单地使用参数的 hash()es 来为参数构建缓存键 - 这就是 lru_cache 已经为您所做的。

    如果您仍在使用 Python 2.7,Raymond Hettinger 已发布了一些 recipes with LRU caches,您可以在自己的代码中使用它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-11
      • 2011-01-04
      • 2011-08-26
      • 2016-11-08
      • 2016-10-27
      • 1970-01-01
      • 2010-12-11
      • 1970-01-01
      相关资源
      最近更新 更多