Соответствует ли объект Python, который не переопределяет операторы сравнения, самому себе? - PullRequest
12 голосов
/ 21 декабря 2011
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 такова: same as del s[s.index(x)], что подразумевает выполнение теста на равенство.

Так будет ли объект равен самому себе, если вы не переопределите __cmp__, __eq__ или __ne__?

Ответы [ 3 ]

11 голосов
/ 21 декабря 2011

Да . В вашем примере q.remove(y) удалит первое вхождение объекта, который сравнивается равным y. Однако, как определяется класс A, вы никогда не должны сравнивать переменную, равную y - за исключением любых других имен, которые также связаны с тем же y пример.

Соответствующий раздел документации: здесь :

Если операция __cmp__(), __eq__() or __ne__() не определена, класс экземпляры сравниваются по идентификатору объекта («адресу»).

Таким образом, сравнение для A экземпляров выполняется по идентификатору (реализовано как адрес памяти в CPython). Ни один другой объект не может иметь идентичность, равную id(y) в течение жизни y, то есть для , пока вы держите ссылку на y (что вы должны, если вы собираетесь удалить его из списка!)

Технически, все еще возможно иметь объекты в других местах памяти, которые сравниваются равными - mock.ANY является одним из таких примеров. Но эти объекты должны переопределить свои операторы сравнения, чтобы форсировать результат.

2 голосов
/ 21 декабря 2011

В python по умолчанию объект всегда равен самому себе (единственное исключение, о котором я могу думать, это float("nan"). Объект пользовательского класса не будет равен любому другому объекту, если вы не определите функцию сравнения.

См. Также http://docs.python.org/reference/expressions.html#notin

0 голосов
/ 21 декабря 2011

Ответ - да и нет.

Рассмотрим следующий пример

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

Он удалит из списка, если это один и тот же объект. Если это разные объекты с одинаковым значением, он не будет удален.

...