正如 Volatility 和 kindall 已经解释的那样,HT = [ [] ] * size
制作 10 个相同的 empty 副本list
,而不是 10 个不同的 empty list
s。list
身份总是会咬新程序员——有时甚至会咬专家。
他们已经向您展示了如何解决问题并获得 10 个不同的 empty list
s。但是还有另一种方法可以解决这个问题。如果您可以重写您的程序以完全不改变list
s,那么它们是否相同并不重要:
def add_HT(data):
index = hash(data) % size
HT[index] = HT[index] + [data]
现在:
>>> add_HT('hello')
>>> add_HT('goodbye')
>>> HT
[['goodbye'], ['hello'], [], [], [], [], [], [], [], []]
这里发生的情况是,您每次追加时都会创建一个新存储桶,并替换旧存储桶,因此这些存储桶是不可变的。(您可能希望将它们存储为tuple
s 而不是list
s,以确保您不会意外地改变它们。)
您可以更进一步,不仅使每个HT[i]
不可变,而且使其HT
自身:
def add_HT(data):
global HT
index = hash(data) % size
HT = [bucket if i != index else bucket + [data] for i, bucket in enumerate(HT)]
有时使事物不可变会使代码更简单,有时更复杂。(在这种情况下,我认为第一个不可变版本与可变版本一样简单,但第二个版本的可读性要差得多。)有时它使代码更快,有时更慢。(在这种情况下,快速测试显示第一个速度大致相同,但第二个速度慢 50 倍,并且使用更多内存。另一方面,使用 PyPy 而不是 CPython,它们分别是 15% 和 30%较慢,分别……)但它总是更容易推理——你不必担心对象身份。除非它使事情更容易编写、更容易阅读、更快,否则你必须考虑权衡。但值得知道如何去做。