不重载比较运算符的Python对象是否等于自身?
class A(object):
def __init__(self, value):
self.value = value
x = A(1)
y = A(2)
q = [x, y]
q.remove(y)
我想从列表中移除一个特定的对象,这个对象之前已经被添加到列表里,而且我仍然有它的引用。我不想进行相等性测试,而是想进行身份测试。这个代码在CPython和IronPython中似乎都能正常工作,但这个行为是语言保证的吗,还是说只是偶然现象?
关于list.remove
方法的文档是这样的:和 del s[s.index(x)] 一样
,这意味着会进行相等性测试。
那么,如果你没有重写__cmp__
、__eq__
或__ne__
,一个对象会和它自己相等吗?
3 个回答
答案是有时候是,也有时候不是。
来看下面这个例子:
>>> class A(object):
def __init__(self, value):
self.value = value
>>> x = A(1)
>>> y = A(2)
>>> z = A(3)
>>> w = A(3)
>>> q = [x, y,z]
>>> id(y) #Second element in the list and y has the same reference
46167248
>>> id(q[1]) #Second element in the list and y has the same reference
46167248
>>> q.remove(y) #So it just compares the id and removes it
>>> q
[<__main__.A object at 0x02C19AB0>, <__main__.A object at 0x02C19B50>]
>>> q.remove(w) #Fails because though z and w contain the same value yet they are different object
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
q.remove(w)
ValueError: list.remove(x): x not in list
这个代码会从列表中移除元素,前提是它们是同一个对象。如果它们是不同的对象,但值是一样的,那就不会被移除。
在Python中,默认情况下,一个对象总是等于它自己(唯一的例外是 float("nan")
)。如果你创建了一个自定义的类,那么这个类的对象不会和其他任何对象相等,除非你自己定义了一个比较函数。
你可以查看更多信息,访问这个链接:http://docs.python.org/reference/expressions.html#notin
是的。在你的例子中,q.remove(y)
会移除第一个与 y
相等的对象。不过,根据类 A
的定义,实际上你不应该有任何变量与 y
相等,除了那些也指向同一个 y
实例的其他名字。
相关的文档部分可以在 这里 找到:
如果没有定义
__cmp__(), __eq__() 或 __ne__()
操作,类的实例会通过对象的身份(“地址”)来比较。
所以,对于 A
的实例,比较是通过身份来进行的(在 CPython 中是通过内存地址实现的)。在 y
的生命周期内,没有其他对象可以与 id(y)
相等,也就是说,只要你持有对 y
的引用(如果你想从列表中移除它,你必须这样做!)
† 从技术上讲,确实还有可能有其他内存位置的对象与 y
相等,比如 mock.ANY
就是一个这样的例子。但这些对象需要重写它们的比较操作符来强制结果。