在编写自定义类时,允许使用==和!=操作符进行等价通常是很重要的。在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

当前回答

你不必同时覆盖__eq__和__ne__,你可以只覆盖__cmp__,但这将对==,!==,<,>等的结果产生影响。

测试对象标识。这意味着当a和b都持有对同一对象的引用时,a是b将为True。在python中,你总是在变量中保存一个对象的引用,而不是实际的对象,所以本质上,a是b,它们中的对象应该位于相同的内存位置。最重要的是,你要如何覆盖这种行为?

编辑:我不知道__cmp__已从python 3中删除,因此请避免使用它。

其他回答

我认为你要找的两个术语是相等(==)和同一性(is)。例如:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a == b
True       <-- a and b have values which are equal
>>> a is b
False      <-- a and b are not the same list object

你不必同时覆盖__eq__和__ne__,你可以只覆盖__cmp__,但这将对==,!==,<,>等的结果产生影响。

测试对象标识。这意味着当a和b都持有对同一对象的引用时,a是b将为True。在python中,你总是在变量中保存一个对象的引用,而不是实际的对象,所以本质上,a是b,它们中的对象应该位于相同的内存位置。最重要的是,你要如何覆盖这种行为?

编辑:我不知道__cmp__已从python 3中删除,因此请避免使用它。

我喜欢使用泛型类装饰器,而不是使用子类化/mixins

def comparable(cls):
    """ Class decorator providing generic comparison functionality """

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

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

    cls.__eq__ = __eq__
    cls.__ne__ = __ne__
    return cls

用法:

@comparable
class Number(object):
    def __init__(self, x):
        self.x = x

a = Number(1)
b = Number(1)
assert a == b

你需要小心继承:

>>> 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