Python:如何使用set / dict作为单个对象来处理相同类型的可比较的hashable对象?

时间:2016-03-09 13:57:07

标签: python dictionary hash set equality

我希望set / dict处理与单个对象相同类型的对象,因此set中不会有多个相同类型的对象/ dict

我还希望这些对象能够以非平凡的方式进行比较,例如与其内部状态相比:C(value=1) == C(value=2)必须返回FalseC(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的问题。

1 个答案:

答案 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): ...