在编写自定义类时,允许使用==和!=操作符进行等价通常是很重要的。在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对象不承担所有额外的(在大多数情况下相同)逻辑的负担。
'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对象不承担所有额外的(在大多数情况下相同)逻辑的负担。