Python:如何使 set/dict 将相同类型的可比较可哈希对象视为单个对象?

Python: how to make comparable hashable objects of the same type to be treated by set/dict as the single object?

我希望set/dict把同类型的对象当成单个对象,这样[=14中的同类型对象不会超过一个=]/dict.

我还希望这些对象能够以非平凡的方式进行比较,例如针对它们的内部状态:C(value=1) == C(value=2) 必须 return FalseC(value=1) == C(value=1) 必须 return 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

是否可以将用户定义的 class 对象存储在 set/dict 中,使得 set/dict 中不超过一个具有相同对象的对象class,但让这些对象仍然具有非平凡的可比性?

我知道我可以使用类型作为键将对象存储在 dict 中:

d = {
    Base: Base(1),
    Derived: Derived(2),
}

但是这种方式不能解决set/frozenset的问题。

比较相等的对象应该具有相同的散列值——这并不排除在设计上比较不同的对象也具有相同的散列值。

但是,如果对象的哈希值相同,Python 然后求助于 __eq__ 来区分对象 - 这是哈希概念的一部分,因为哈希冲突可能发生在任何地方。如果出现相等的哈希值和不同的相等性,则对象被认为对于字典和集合效果不同。

为了实现只允许字典或集合中的每种对象类型之一的目标,它们也必须全部比较相等。

因此,给你的简短回答是:你想要的是不可能的。

我建议您的一个解决方法是不要使用 __eq__ 来比较这些对象,而是比较然后在需要时使用其他方法,(就像 Java 人们必须做的那样.equals 几乎所有的方法)。

您可以有一个辅助包装器 class 以便在您想要比较它们时使用:

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