【发布时间】:2018-09-02 05:01:53
【问题描述】:
我在两个类的对象之间存在递归关系:Foo 有一个 set 的 Bar 对象(在其 bars 属性中),每个 Bar 都有一个 list 的 Foo 对象(在其foos 属性中)。我已经实现如下 MWE 所示,但测试失败。为什么?
根据Python Glossary,一个set只能包含hashable对象和hashable对象:
一个对象是
hashable,如果它的哈希值在其生命周期内永远不会改变(它需要一个__hash__()方法),并且可以与其他对象进行比较(它需要一个__eq__()方法)。
我真的不知道我下面的 MWE 是否满足对象具有永远不会更改的散列,因为散列取决于列表中的其他对象并设置属性。有没有办法解决这个问题?
最小的工作示例:
import unittest
class Test(unittest.TestCase):
def test_foo_bar(self):
foo = Foo()
bar = Bar()
bar.add_foo(foo)
print(bar)
print(foo.bars)
print(hash(bar))
for bar in foo.bars:
print(hash(bar))
# The previous print lines print the following:
# <mwe2.Bar object at 0x105ba8080>
# {<mwe2.Bar object at 0x105ba8080>}
# -9223096319794529578
# -9223096319794529578
# The following assertion is OK
self.assertTrue(bar in {bar})
# The following assertion fails with AssertionError: False is not true
self.assertTrue(bar in foo.bars)
class Foo:
def __init__(self):
self.bars = set()
def __hash__(self) -> int:
return hash(self.__dict__.values())
class Bar:
def __init__(self):
self.foos = list()
def __hash__(self) -> int:
return hash(tuple(self.foos))
def add_foo(self, foo: "Foo"):
foo.bars.add(self)
self.foos.append(foo)
if __name__ == '__main__':
unittest.main()
我使用 CPython,Python 3.6.x。
【问题讨论】:
-
一般来说:一个可散列对象应该是不可变的,或者至少它的散列应该是稳定的并且不依赖于可变属性。您的对象的哈希值会随着时间而变化,这不是 Good™️。
-
对我来说,
add电话有效。为什么它不工作? -
啊,我的错。看,太混乱了! ;)
-
答案可能在于可变散列如何违背
set内部所做的假设。因此,问题可能是您的哈希值发生了变异。 -
@Erik:坦率地说,你可以大大减少你的代码。并且不需要类型提示,所有这些都适用于非 python 3.6 用户。我会放弃最统一的部分。只需打印结果...
标签: python list hash set hashable