在 Python 中,自定义类可以实现 __eq__ 和 __ne__ 方法来定义 == 和 != 运算符的等价性,分别。虽然比较字典属性的传统方法很简单,但它存在一定的局限性。
考虑以下场景:
class Number: def __init__(self, number): self.number = number n1 = Number(1) n2 = Number(1) # Default comparison fails: they are different objects assert n1 != n2
解决此问题,我们可以重写 __eq__ 方法:
class Number: def __init__(self, number): self.number = number def __eq__(self, other): if isinstance(other, Number): return self.number == other.number return False
但是,对于 Python 2,我们还需要实现 __ne__ 以确保交换行为:
class Number: def __init__(self, number): self.number = number def __eq__(self, other): if isinstance(other, Number): return self.number == other.number return False def __ne__(self, other): return not self.__eq__(other)
这确保 n1 == n2 按预期计算为 True。
引入子类会使等价比较复杂化:
class SubNumber(Number): pass n3 = SubNumber(1) # Subclass comparison fails for classic-style classes assert n1 == n3 # False (for classic-style classes) assert n3 == n1 # True # Non-commutative comparison assert n1 != n3 # True (for classic-style classes) assert n3 != n1 # False
对于经典风格的类,比较方法根据第一个操作数的类型调用,导致不可交换的行为。为了解决这个问题,我们可以为不支持的操作数类型返回 NotImplemented,它将比较委托给其他操作数的方法:
def __eq__(self, other): if isinstance(other, Number): return self.number == other.number return NotImplemented
最后,请注意,集合使用对象标识符散列,这可能会导致不正确的结果:
assert len(set([n1, n2, n3])) == 3 # Incorrectly reports 3 unique numbers
要解决此问题,我们可以覆盖__hash__ 方法:
def __hash__(self): return hash(tuple(sorted(self.__dict__.items())))
通过这些增强功能,等价性和唯一性行为变得正确且一致,确保集合中的稳健比较和准确表示:
assert len(set([n1, n2, n3])) == 1 assert len(set([n1, n2, n3, n4])) == 2
以上是如何确保自定义 Python 类的一致且稳健的等价比较,尤其是在处理子类和集合时?的详细内容。更多信息请关注PHP中文网其他相关文章!