不重载比较运算符的Python对象是否等于自身?

13 投票
3 回答
8219 浏览
提问于 2025-04-17 08:46
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 个回答

-1

答案是有时候是,也有时候不是。

来看下面这个例子:

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

这个代码会从列表中移除元素,前提是它们是同一个对象。如果它们是不同的对象,但值是一样的,那就不会被移除。

2

在Python中,默认情况下,一个对象总是等于它自己(唯一的例外是 float("nan"))。如果你创建了一个自定义的类,那么这个类的对象不会和其他任何对象相等,除非你自己定义了一个比较函数。

你可以查看更多信息,访问这个链接:http://docs.python.org/reference/expressions.html#notin

12

是的。在你的例子中,q.remove(y) 会移除第一个与 y 相等的对象。不过,根据类 A 的定义,实际上你不应该有任何变量与 y 相等,除了那些也指向同一个 y 实例的其他名字。

相关的文档部分可以在 这里 找到:

如果没有定义 __cmp__(), __eq__() 或 __ne__() 操作,类的实例会通过对象的身份(“地址”)来比较。

所以,对于 A 的实例,比较是通过身份来进行的(在 CPython 中是通过内存地址实现的)。在 y 的生命周期内,没有其他对象可以与 id(y) 相等,也就是说,只要你持有对 y 的引用(如果你想从列表中移除它,你必须这样做!)

从技术上讲,确实还有可能有其他内存位置的对象与 y 相等,比如 mock.ANY 就是一个这样的例子。但这些对象需要重写它们的比较操作符来强制结果。

撰写回答