在编写自定义类时,允许使用==和!=操作符进行等价通常是很重要的。在Python中,这可以通过分别实现__eq__和__ne__特殊方法实现。我发现最简单的方法是以下方法:

class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

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

你知道更优雅的方法吗?你知道使用上面比较__dict__的方法有什么特别的缺点吗?

注意:一点澄清——当__eq__和__ne__未定义时,你会发现这样的行为:

>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
False

也就是说,a == b的计算结果为False,因为它实际上运行的是a is b,这是一个身份测试(即,“a和b是同一个对象吗?”)。

当__eq__和__ne__被定义时,你会发现这样的行为(这是我们所追求的行为):

>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
True

当前回答

'is'测试将使用内置的'id()'函数测试身份,该函数本质上返回对象的内存地址,因此不可重载。

然而,在测试类的相等性的情况下,你可能想对你的测试更严格一点,只比较你类中的数据属性:

import types

class ComparesNicely(object):

    def __eq__(self, other):
        for key, value in self.__dict__.iteritems():
            if (isinstance(value, types.FunctionType) or 
                    key.startswith("__")):
                continue

            if key not in other.__dict__:
                return False

            if other.__dict__[key] != value:
                return False

         return True

这段代码将只比较类的非函数数据成员,并跳过任何私有的东西,这通常是你想要的。在普通旧Python对象的情况下,我有一个实现__init__, __str__, __repr__和__eq__的基类,所以我的POPO对象不承担所有额外的(在大多数情况下相同)逻辑的负担。

其他回答

你需要小心继承:

>>> class Foo:
    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

>>> class Bar(Foo):pass

>>> b = Bar()
>>> f = Foo()
>>> f == b
True
>>> b == f
False

更严格地检查类型,像这样:

def __eq__(self, other):
    if type(other) is type(self):
        return self.__dict__ == other.__dict__
    return False

除此之外,你的方法也可以很好地工作,这就是特殊方法的用途。

你描述的方式就是我一直用的方式。由于它是完全泛型的,所以您总是可以将该功能分解到mixin类中,并在需要该功能的类中继承它。

class CommonEqualityMixin(object):

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

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

class Foo(CommonEqualityMixin):

    def __init__(self, item):
        self.item = item

这包含了对Algorias的答案的评论,并通过单个属性比较对象,因为我不关心整个字典。hasattr(other,“id”)必须为真,但我知道它是真的,因为我在构造函数中设置了它。

def __eq__(self, other):
    if other is self:
        return True

    if type(other) is not type(self):
        # delegate to superclass
        return NotImplemented

    return other.id == self.id

从这个答案:https://stackoverflow.com/a/30676267/541136我已经证明,虽然它是正确的定义__ne__术语__eq__ -而不是

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

你应该使用:

def __ne__(self, other):
    return not self == other

'is'测试将使用内置的'id()'函数测试身份,该函数本质上返回对象的内存地址,因此不可重载。

然而,在测试类的相等性的情况下,你可能想对你的测试更严格一点,只比较你类中的数据属性:

import types

class ComparesNicely(object):

    def __eq__(self, other):
        for key, value in self.__dict__.iteritems():
            if (isinstance(value, types.FunctionType) or 
                    key.startswith("__")):
                continue

            if key not in other.__dict__:
                return False

            if other.__dict__[key] != value:
                return False

         return True

这段代码将只比较类的非函数数据成员,并跳过任何私有的东西,这通常是你想要的。在普通旧Python对象的情况下,我有一个实现__init__, __str__, __repr__和__eq__的基类,所以我的POPO对象不承担所有额外的(在大多数情况下相同)逻辑的负担。