我已经成功地使用了以下组合hash
and zlib.adler32
。最直接的实现是这样的:
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
使用 Python 3.4.3,这比调用普通函数慢很多hash
,大约需要 0.07 us。对于一个规则的物体来说,hashkey
需要 ~1.0 usc。 0.8 微秒bytes
0.7 为str
.
开销大致如下:
- 函数调用需要 0.1 usec (
hash(obj)
vs def pyhash(obj): return hash(obj)
)
- 0.2 usec 到 0.5 usec 用于选择哈希函数
isinstance
- 0.75 用于
zlib.adler32
or zlib.crc32
vs hash
:~0.160 usec vs ~ 0.75 usec(adler 和 crc 为 +/- 4 usec)
- 0.15 微秒
obj.encode()
of str
对象("foobar"
)
- 1.5 微秒
str(obj).encode()
of datetime.datetime
objects
最优化来自于排序if
声明。如果人们主要期望普通对象,那么以下是我能想到的最快的:
def hashkey_c(obj, salt=0):
if obj.__class__ in hashkey_c.types:
if obj is None:
return 0
if obj.__class__ is str:
return zlib.adler32(obj.encode(), salt) & 0xffffffff
elif obj.__class__ is bytes:
return zlib.adler32(obj, salt) & 0xffffffff
elif obj.__class__ is datetime_type:
return zlib.adler32(str(obj).encode(), salt) & 0xffffffff
return hash(obj) & 0xffffffff
hashkey_c.types = {str, bytes, datetime_type, type(None)}
总时间:~0.7 usstr
and bytes
, 糟糕透顶datetime
, 0.35 usec 用于对象、整数等。dict
将类型映射到可比较的散列,如果对dict
键(又名类型)分别(即不obj.__class__ in hashkey.dict_types
but obj.__class__ in hashkey.explicit_dict_types
).
一些附加说明:
-
hash
对于使用默认值的任何对象,跨解释器启动都不稳定__hash__
实施,包括None
- 它对于不可变容器(定义了
__hash__
) 含有盐分类型,例如(1, 2, 'three')