我有一个类MyClass,它包含两个成员变量foo和bar:

class MyClass:
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar

我有这个类的两个实例,每个实例都有相同的foo和bar值:

x = MyClass('foo', 'bar')
y = MyClass('foo', 'bar')

然而,当我比较它们是否相等时,Python返回False:

>>> x == y
False

我如何使python认为这两个对象相等?


当前回答

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

    def __repr__(self):
        return str(self.value)

    def __eq__(self,other):
        return self.value == other.value

node1 = Node(1)
node2 = Node(1)

print(f'node1 id:{id(node1)}')
print(f'node2 id:{id(node2)}')
print(node1 == node2)
>>> node1 id:4396696848
>>> node2 id:4396698000
>>> True

其他回答

你应该实现方法__eq__:

class MyClass:
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar
        
    def __eq__(self, other): 
        if not isinstance(other, MyClass):
            # don't attempt to compare against unrelated types
            return NotImplemented

        return self.foo == other.foo and self.bar == other.bar

现在它输出:

>>> x == y
True

注意,实现__eq__将自动使类的实例不可哈希,这意味着它们不能存储在集和字典中。如果你不是建模一个不可变的类型(例如,如果属性foo和bar可能会在你的对象的生命周期内改变值),那么建议把你的实例保留为不可哈希的。

如果你正在建模一个不可变类型,你还应该实现数据模型钩子__hash__:

class MyClass:
    ...

    def __hash__(self):
        # necessary for instances to behave sanely in dicts and sets.
        return hash((self.foo, self.bar))

一般的解决方案,比如循环__dict__并比较值的想法,是不可取的——它永远不可能真正通用,因为__dict__可能包含不可比较或不可哈希的类型。

注意:在Python 3之前,你可能需要使用__cmp__而不是__eq__。Python 2用户可能还想实现__ne__,因为在Python 2中不会自动创建一个合理的不等式默认行为(即反转相等结果)。

根据具体情况,你可以这样做:

>>> vars(x) == vars(y)
True

参见对象字段中的Python字典

下面通过在两个对象层次结构之间进行深度比较来工作(在我有限的测试中)。In处理各种情况,包括对象本身或其属性是字典的情况。

def deep_comp(o1:Any, o2:Any)->bool:
    # NOTE: dict don't have __dict__
    o1d = getattr(o1, '__dict__', None)
    o2d = getattr(o2, '__dict__', None)

    # if both are objects
    if o1d is not None and o2d is not None:
        # we will compare their dictionaries
        o1, o2 = o1.__dict__, o2.__dict__

    if o1 is not None and o2 is not None:
        # if both are dictionaries, we will compare each key
        if isinstance(o1, dict) and isinstance(o2, dict):
            for k in set().union(o1.keys() ,o2.keys()):
                if k in o1 and k in o2:
                    if not deep_comp(o1[k], o2[k]):
                        return False
                else:
                    return False # some key missing
            return True
    # mismatched object types or both are scalers, or one or both None
    return o1 == o2

这是一个非常棘手的代码,所以请在注释中添加任何可能不适合你的情况。

类的实例与==比较是非相等的。最好的方法是将cmp函数赋给你的类,它会做这些事情。

如果你想通过内容进行比较你可以使用cmp(obj1,obj2)

在你的例子中,cmp(doc1,doc2)如果它们的内容相同,它将返回-1。

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

    def __repr__(self):
        return str(self.value)

    def __eq__(self,other):
        return self.value == other.value

node1 = Node(1)
node2 = Node(1)

print(f'node1 id:{id(node1)}')
print(f'node2 id:{id(node2)}')
print(node1 == node2)
>>> node1 id:4396696848
>>> node2 id:4396698000
>>> True