我希望set
/ dict
处理与单个对象相同类型的对象,因此set
中不会有多个相同类型的对象/ dict
。
我还希望这些对象能够以非平凡的方式进行比较,例如与其内部状态相比:C(value=1) == C(value=2)
必须返回False
而C(value=1) == C(value=1)
必须返回True
。
天真的方法失败了:
class Base(object):
KEY = 'base'
def __init__(self, value):
self.value = value
def __hash__(self):
# hash is the same for all objects of the same type
return hash(type(self).KEY)
def __eq__(self, other):
# objects are compared against `.value` attribute
return bool(self.value == other.value)
def __repr__(self):
return '{}({})'.format(type(self).__name__, self.value)
class Derived(Base):
KEY = 'derived'
print {Base(1), Base(2), Derived(3), Derived(4)}
# actual: set([Base(1), Base(2), Derived(3), Derived(4)])
# desired: set([Base(?), Derived(?)]) -- "?" for arbitrary value
print {Base(1): 1, Base(2): 2}
# actual: {Base(1): 1, Base(2): 2}
# desired: {Base(?): ?} -- "?" for arbitrary value
是否可以在set / dict中存储用户定义类的对象,使得set / dict中只有一个对象具有相同的类,但保持这些对象仍然是非平凡的可比?
我知道我可以使用type作为键来存储dict
中的对象:
d = {
Base: Base(1),
Derived: Derived(2),
}
但这种方法无法解决set
/ frozenset
的问题。
答案 0 :(得分:2)
比较相等的对象应该具有相同的哈希值 - 根据设计,这并不排除比较不同的对象也具有相同的哈希值。
然而,对象的散列是相同的,然后Python转向__eq__
以区分对象 - 这是哈希开始的想法的一部分,因为哈希冲突可能发生在任何地方。如果发生相等的哈希并且发生不同的相等,则对象被认为是字典和集合效果的不同。
为了实现只允许字典或集合中每个对象类型之一的目标,它们的所有内容都要相等。
因此,对你的简短回答是:你不可能得到你想要的东西。
我建议您不要使用__eq__
来比较这些对象,而是在需要时使用其他方法进行比较(就像Java人员与.equals
一样几乎所有事情的方法。)
您可以在需要比较它们时使用辅助包装类:
class E(object):
def __init__(self, obj):
self.obj = obj
def __eq__(self, other):
return self.obj.value == getattr(other, "obj", other).value
他们,只要你需要进行比较,就行:if E(Base(1)) == Base(2): ...