Python快速散列可变对象

标签 python bytearray

我有一个字节数组,我需要将其用作字典的键。理想情况下,我想在不复制字节数组大小的内存的情况下执行此操作。有没有办法做到这一点? 基本上,

b = some bytearray
d[byte(b)] = x

有没有更快的方法来做到这一点? byte(b) 是一个 O(len(bytearray)) 操作,这是不受欢迎的。

最佳答案

任何实际正确完成其工作的哈希算法都将使用 O(len(b)) 时间。所以“有没有更快的方法来做到这一点”的答案是否定的。

如果您真正关心的是内存 使用,那么原则上您可以将__hash__ 方法添加到bytearray 的子类。但这是一个非常糟糕的主意。看看会发生什么:

>>> class HashableBytearray(bytearray):
...     def __hash__(self):
...         return hash(str(self))
... 
>>> h = HashableBytearray('abcd')
>>> hash(h)
-2835746963027601024
>>> h[2] = 'z'
>>> hash(h)
-2835746963002600949

所以同一个对象可能散列到字典中的两个不同位置,这是不应该发生的。情况变得更糟:

>>> d = dict()
>>> hb1 = HashableBytearray('abcd')
>>> hb2 = HashableBytearray('abcd')
>>> d[hb1] = 0
>>> d[hb2] = 1
>>> d
{bytearray(b'abcd'): 1}

好的,到目前为止,还不错。值相等,因此字典中应该只有一项。一切都按预期工作。现在让我们看看当我们更改 hb1 时会发生什么:

>>> hb1[2] = 'z'
>>> d[hb2] = 2
>>> d
{bytearray(b'abzd'): 1, bytearray(b'abcd'): 2}

看看虽然 hb2 一点都没变,但这次它在字典中创建了一个新的键值对?

每次我将 key 传递给 d 时,该 key 等于 'abcd'。但是因为第一个键的值在添加到字典后发生了变化,Python 无法判断新键的值是否与添加时旧键的值相同。现在字典中有两个键值对,而应该只有一个。

这只是使用可变值作为键可能导致不可预测和非常错误的行为的众多方式之一。只需将 bytearray 转换为不可变类型,或者首先使用不可变类型。


对于好奇者:当然,buffer 缓存了第一个散列,但这根本没有帮助。只有两个键值,所以这应该只生成两个字典条目:

>>> a, b, c = bytearray('abcd'), bytearray('abcd'), bytearray('abzd')
>>> a_buf, b_buf, c_buf = buffer(a), buffer(b), buffer(c)
>>> d = {b_buf:1, c_buf:2}
>>> b[2] = 'z'
>>> d[a_buf] = 0

但它生成三个:

>>> d
{<read-only buffer for 0x1004a2300, size -1, offset 0 at 0x100499cb0>: 1, 
 <read-only buffer for 0x1004a2420, size -1, offset 0 at 0x100499cf0>: 0, 
 <read-only buffer for 0x1004a22d0, size -1, offset 0 at 0x100499c70>: 2}

关于Python快速散列可变对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13041352/

相关文章:

python - 了解 Python 中的数据封装

python - 我想要一些关于将其打包为鸡蛋并将其上传到 pypi 的建议

python - 升级到 Python 3 后是否应该手动安装所有系统范围的软件包?

读取大文本文件时的 Java OutOfMemoryError

objective-c - 如何在Objective-C中将字节数组转换为图像

Python 的 'with' 语句与 'with .. as'

python - 如何应用函数式编程去除两个嵌套的for i in?

java - 如何将数组字节转换为 org.w3c.dom.Document

java - Java中字节数组的空闲内存

jsf - 未调用 PrimeFaces fileDownload 方法?