我有一个bytearray,需要将其用作字典的键。理想情况下,我希望能够在不复制bytearray大小的内存的情况下实现此操作。有没有办法做到这一点? 基本上,
b = some bytearray
d[byte(b)] = x
有没有更快的方法来做这件事?byte(b)是一个O(len(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
没有任何变化,但它这次在字典中创建了一个新的键值对。每次我将一个键传递给d
时,该键都等于'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}
PyBufferObject
的b_hash
字段被初始化为-1,并在第一次调用tp_hash
时设置。但无论如何,这只是一个随意的评论。不要浪费时间追溯源代码等。 - Eryk Sunmemcmp
)。使用这些缓冲区创建一个包含2个项的字典。如果这些缓冲区再次变得相等,则它们都映射到同一项,而另一项将无法访问。 - Eryk Sun如果您担心时间问题,并且您使用的关键字始终是相同的对象,则可以使用其id
(在内存中的位置)作为字典中的关键字:
b = some byte array
d[id(b)] = x
b = some byte array
d[hashlib.sha1(b).hexdigest()] = x
我认为这可能接近你想要的。它相对快速,不会复制bytearray大小的内存,但是它确实是O(len(bytearray)) -- 因为我想不到任何避免这种情况并且始终产生唯一值的方法。
def byte(ba):
""" decode a bytearray as though it were a base 256 number """
return reduce(lambda a,d: a*256 + d, ba, 0)
ba = bytearray('this is a bytearray')
d = {}
d[byte(ba)] = 42
ba[8] = 'X' # now 'this is X bytearray'
d[byte(ba)] = 17 # accesses a separate entry in dict
print d
bytes
,然后哈希] 仍然是O(len(b))。 - jedwards