鑑於此程序:已經從一個Python改變刪除對象設置
class Obj:
def __init__(self, a, b):
self.a = a
self.b = b
def __hash__(self):
return hash((self.a, self.b))
class Collection:
def __init__(self):
self.objs = set()
def add(self, obj):
self.objs.add(obj)
def find(self, a, b):
objs = []
for obj in self.objs:
if obj.b == b and obj.a == a:
objs.append(obj)
return objs
def remove(self, a, b):
for obj in self.find(a, b):
print('removing', obj)
self.objs.remove(obj)
o1 = Obj('a1', 'b1')
o2 = Obj('a2', 'b2')
o3 = Obj('a3', 'b3')
o4 = Obj('a4', 'b4')
o5 = Obj('a5', 'b5')
objs = Collection()
for o in (o1, o2, o3, o4, o5):
objs.add(o)
objs.remove('a1', 'b1')
o2.a = 'a1'
o2.b = 'b1'
objs.remove('a1', 'b1')
o3.a = 'a1'
o3.b = 'b1'
objs.remove('a1', 'b1')
o4.a = 'a1'
o4.b = 'b1'
objs.remove('a1', 'b1')
o5.a = 'a1'
o5.b = 'b1'
如果我使用Python 3.4.2跑了幾次,有時它會成功,其他時間刪除2後拋出一個KeyError異常或3個對象:
$ python3 py_set_obj_remove_test.py
removing <__main__.Obj object at 0x7f3648035828>
removing <__main__.Obj object at 0x7f3648035860>
removing <__main__.Obj object at 0x7f3648035898>
removing <__main__.Obj object at 0x7f36480358d0>
$ python3 py_set_obj_remove_test.py
removing <__main__.Obj object at 0x7f156170b828>
removing <__main__.Obj object at 0x7f156170b860>
Traceback (most recent call last):
File "py_set_obj_remove_test.py", line 42, in <module>
objs.remove('a1', 'b1')
File "py_set_obj_remove_test.py", line 27, in remove
self.objs.remove(obj)
KeyError: <__main__.Obj object at 0x7f156170b860>
這是Python中的錯誤嗎?或者關於我不知道的集合的實現?
有趣的是,它似乎總是在Python 2.7.9中的第二個objs.remove()
調用失敗。
這句話很有意思。爲什麼執行'__eq__'(用於比較,即不改變對象)影響'__hash__'的實現? – DeepSpace
@DeepSpace:比較equal *的兩個對象必須*產生相同的散列。在這種情況下,默認的'__eq__'實現對同一對象的兩個引用返回true,所以即使更改這兩個屬性也不會改變相等測試結果。 –
@DeepSpace:散列用於在散列表中選取一個空位(在其中有限數量的空位中,因此使用散列模表大小),然後測試相等性以查看是否同一個對象已經位於該空位。如果你的平等測試仍然傳遞兩個具有不同散列值的對象,你將打破這個測試;你可以找到一個實際上並不存在的值。 –