【发布时间】:2011-06-19 09:59:25
【问题描述】:
我第一次在这里发帖,所以希望我以正确的方式提出了我的问题,
将元素添加到 Python 字典后,是否可以让 Python 告诉您添加该元素是否会导致冲突? (以及在找到放置元素的位置之前,碰撞解决策略探测了多少个位置?)
我的问题是:我在一个更大的项目中使用字典,经过大量分析后,我发现代码中最慢的部分是处理使用字典实现的稀疏距离矩阵。
我使用的键是 Python 对象的 ID,它们是唯一的整数,所以我知道它们都散列到不同的值。但是原则上将它们放入字典仍然可能导致冲突。我不认为字典冲突会拖慢我的程序,但我想从查询中消除它们。
因此,例如,给定以下字典:
d = {}
for i in xrange(15000):
d[random.randint(15000000, 18000000)] = 0
你能让 Python 告诉你在创建它时发生了多少次冲突吗?
我的实际代码与应用程序纠缠在一起,但上面的代码生成的字典看起来与我正在使用的字典非常相似。
重复一遍:我不认为碰撞会降低我的代码速度,我只是想通过证明我的字典没有太多碰撞来消除这种可能性。
感谢您的帮助。
编辑:一些代码来实现@Winston Ewert 的解决方案:
n = 1500
global collision_count
collision_count = 0
class Foo():
def __eq__(self, other):
global collision_count
collision_count += 1
return id(self) == id(other)
def __hash__(self):
#return id(self) # @John Machin: yes, I know!
return 1
objects = [Foo() for i in xrange(n)]
d = {}
for o in objects:
d[o] = 1
print collision_count
请注意,当您在类上定义 __eq__ 时,如果您没有同时定义 __hash__ 函数,Python 会为您提供 TypeError: unhashable instance。
它没有像我预期的那样运行。如果你有__hash__ 函数return 1,那么你会得到大量的冲突,正如预期的那样(在我的系统上,n=1500 有 1125560 次冲突)。但是对于return id(self),有 0 次冲突。
有人知道为什么说 0 次碰撞吗?
编辑: 我可能已经想通了。
是不是因为 __eq__ 仅在两个对象的 __hash__ 值相同时才被调用,而不是它们的“压缩版本”(如@John Machin 所说)?
【问题讨论】:
-
您的意思是您想知道内部 dict 算法是否通过任何哈希表探测来查找元素?这就是你所说的“碰撞”吗?
-
一些半相关信息:
hash(-1)==hash(-2)。除此之外,区间-sys.maxint-1 <= x <= sys.maxint中的所有整数 x 都具有唯一的哈希值。这里描述了散列长整数的算法:effbot.org/zone/python-hash.htm -
"哈希值 -1 是保留的(用于标记 C 实现中的错误)。如果哈希算法生成此值,我们只需使用 -2 代替。哎哟。
-
@unutbu:(1) OP 的键是对象 ID,而不是长整数。不一样的故事。 (2) 城市神话:唯一的哈希意味着没有冲突。是错的。看我的回答。
-
@S.Lott:是的,这正是我的意思。
标签: python optimization dictionary