我有一个类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认为这两个对象相等?
在Python 3.7(及以上版本)中的数据类中,对象实例的相等性比较是一个内置特性。
Python 3.6提供了数据类的后端端口。
(Py37) nsc@nsc-vbox:~$ python
Python 3.7.5 (default, Nov 7 2019, 10:50:52)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from dataclasses import dataclass
>>> @dataclass
... class MyClass():
... foo: str
... bar: str
...
>>> x = MyClass(foo="foo", bar="bar")
>>> y = MyClass(foo="foo", bar="bar")
>>> x == y
True
总结如下:
It's advised to implement __eq__ rather than __cmp__, except if you run python <= 2.0 (__eq__ has been added in 2.1)
Don't forget to also implement __ne__ (should be something like return not self.__eq__(other) or return not self == other except very special case)
Don`t forget that the operator must be implemented in each custom class you want to compare (see example below).
If you want to compare with object that can be None, you must implement it. The interpreter cannot guess it ... (see example below)
class B(object):
def __init__(self):
self.name = "toto"
def __eq__(self, other):
if other is None:
return False
return self.name == other.name
class A(object):
def __init__(self):
self.toto = "titi"
self.b_inst = B()
def __eq__(self, other):
if other is None:
return False
return (self.toto, self.b_inst) == (other.toto, other.b_inst)
你应该实现方法__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中不会自动创建一个合理的不等式默认行为(即反转相等结果)。
下面通过在两个对象层次结构之间进行深度比较来工作(在我有限的测试中)。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
这是一个非常棘手的代码,所以请在注释中添加任何可能不适合你的情况。