任意对象的python哈希函数的替代方法

2024-09-29 23:16:48 发布

您现在位置:Python中文网/ 问答频道 /正文

在python2.7中,我成功地使用hash()将对象放入持久存储在磁盘上的存储桶中。模型代码如下所示:

class PersistentDict(object):
  def __setitem__(self, key, value):
    bucket_index = (hash(key)&0xffffffff) % self.bucket_count
    self._store_to_bucket(bucket_index, key, value)

  def __getitem__(self, key):
    bucket_index = (hash(key)&0xffffffff) % self.bucket_count
    return self._fetch_from_bucket(bucket_index)[key]

在python3中,hash()使用随机或固定的盐,这使得它不可用/次优。显然,不可能使用fixed salt for specific invocations。所以,我需要另一种选择:

  • 必须在解释器调用之间保持稳定
  • 可能需要在执行时提供参数,例如在调用中设置salt
  • 必须支持任意对象(任何受dict/set支持的对象)

我已经尝试过使用hashlib(慢!)以及来自zlib的校验和(显然不适合散列,但meh)可以很好地处理字符串/字节。然而,它们只在字节类对象上工作,而hash()几乎可以处理所有的对象。在


[1]使用hash()来标识存储桶是:

  • 如果salt是随机的,则跨解释器调用不可靠
  • 防止应用程序使用随机加盐功能(如果盐是固定的)
  • 如果用不同的盐生成两个PersistentDict,则不可用

Tags: 对象key模型selfindex字节bucketvalue
1条回答
网友
1楼 · 发布于 2024-09-29 23:16:48

我已经成功地使用了hash和{}的组合。最直接的实现方法是:

def hashkey(obj, salt=0):
  """
  Create a key suitable for use in hashmaps

  :param obj: object for which to create a key
  :type: str, bytes, :py:class:`datetime.datetime`, object
  :param salt: an optional salt to add to the key value
  :type salt: int
  :return: numeric key to `obj`
  :rtype: int
  """
  if obj is None:
    return 0
  if isinstance(obj, str):
    return zlib.adler32(obj.encode(), salt) & 0xffffffff
  elif isinstance(obj, bytes):
    return zlib.adler32(obj, salt) & 0xffffffff
  elif isinstance(obj, datetime_type):
    return zlib.adler32(str(obj).encode(), salt) & 0xffffffff
  return hash(obj) & 0xffffffff

在Python3.4.3中,这比调用plain hash慢得多,这大约需要0.07 usec。对于常规对象,hashkey取而代之的是~1.0 usec。0.8用于bytes,0.7用于str。在

管理费用大致如下:

  • {cd7>{cd7>
  • 0.2 usec到0.5 usec,用于通过isinstance选择哈希函数
  • 0.75 usec用于zlib.adler32zlib.crc32vshash:~0.160 usec vs~0.75 usec(adler和crc为+/-4 usec)
  • 0.15 usec用于str对象("foobar")的obj.encode()
  • 1.5对datetime.datetime对象的str(obj).encode()使用

最大的优化来自于if语句的排序。如果一个人最希望看到的是普通物体,以下是我能想到的最快的方法:

^{pr2}$

总时间:strbytes使用~0.7,对于datetime非常糟糕,dict对象、int等使用0.35 usec。如果一个人分别对dict键(也称为类型)使用显式检查(即不是obj.__class__ in hashkey.dict_types而是obj.__class__ in hashkey.explicit_dict_types)。在


其他注意事项:

  • hash对于使用默认__hash__实现(包括None)的任何对象,在解释器启动期间都不稳定
  • 对于包含盐化类型(例如(1, 2, 'three'))的不可变容器(定义__hash__)来说,它不能正常工作

相关问题 更多 >

    热门问题