出于好奇:为什么Python3没有使用__dict__作为默认的相等性实现比较?

4
在Python中(我使用的是v 3.4版本),可以像大多数其他语言一样使用this == that来测试两个对象是否相等。
当比较基于类的对象时,Python会引用该类的__eq__方法进行比较。
然而,执行以下示例代码:
class Foo:
    def __init__(self, bar):
        self.bar = bar

one = Foo('text')
two = Foo('text')

调用one == two会返回False,因为Python只检查标识(identity),而不是数据相等性。

这导致你最终需要实现很多__eq____ne__(不相等)方法恰好像这样:

def __eq__(self, other):
    return (isinstance(other, self.__class__)
        and self.__dict__ == other.__dict__)

def __ne__(self, other):
    return not self.__eq__(other)

为什么我们必须这样做?

有人知道为什么他们决定不将dict-compare方法作为类对象的默认方法吗?

这种方法可能存在哪些负面影响?


如果您在基类中定义了__eq____ne__方法,并使其他类继承该基类,则无需在许多地方重复定义。 - unutbu
1个回答

5
为什么我们要这样做呢?因为明确比隐式更好。您正在假设实例仅基于其属性相等; 这不一定是规则。例如,使用私有属性跟踪缓存数据的类。那么,对于具有大量属性但不需要支持相等性的类呢?为什么他们需要支付额外的性能惩罚呢?与其做出这种假设,Python 要求您显式定义相等。这有一个附加优点,即如果您不想支持实例之间的相等,则不需要再次禁用此类相等测试。对于简单的情况,使用 vars(self)或 self.__dict__ 就可以了。
def __eq__(self, other):
    if not isinstance(other, __class__):
        return NotImplemented
    return vars(self) == vars(other)

def __ne__(self, other):
    if not isinstance(other, __class__):
        return NotImplemented
    return not self.__eq__(other)

返回NotImplemented可以确保其他对象也有机会实现相等测试。


还是使用 def __ne__(self, other): return not self.__eq__(other) 来进行镜像操作? - Jon Clements
@JonClements:你仍然想要明确地返回“NotImplemented”。not NotImplemented 返回 False,而不是标记。 - Martijn Pieters
那很有道理。谢谢。还要感谢您的提示,使用NotImplemented。我不知道Python的默认行为涉及询问其他对象是否有一个__eq__方法,如果被抛出。这太棒了。 - Hr. Rabe
1
@Hr.Rabe:不是抛出异常,而是返回;它像None一样是一个单例对象,不是异常。 :-) - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接