web-dev-qa-db-fra.com

Les objets avec le même id sont-ils toujours égaux lors de leur comparaison avec ==?

Si j'ai deux objets o1 et o2, et nous savons que

id(o1) == id(o2)

renvoie vrai.

Ensuite, cela suit-il que

o1 == o2

Ou n'est-ce pas toujours le cas? Le document sur lequel je travaille dit que ce n'est pas le cas, mais à mon avis, cela devrait être vrai!

59
Jonas Kaufmann

Pas toujours:

>>> nan = float('nan')
>>> nan is nan
True

ou formulé de la même manière que dans la question:

>>> id(nan) == id(nan)
True

mais

>>> nan == nan
False

NaN est une chose étrange. Par définition, il n'est ni égal, ni inférieur, ni supérieur à lui-même. Mais c'est le même objet. Plus de détails sur la raison pour laquelle toutes les comparaisons doivent renvoyer False dans this SO question .

129
Mike Müller

Le papier a raison. Considérer ce qui suit.

class WeirdEquals:
    def __eq__(self, other):
        return False

w = WeirdEquals()
print("id(w) == id(w)", id(w) == id(w))
print("w == w", w == w)

La sortie est la suivante:

id(w) == id(w) True
w == w False
58
recursive

id(o1) == id(o2) n'implique pas o1 == o2.

Jetons un œil à ce Troll qui remplace __eq__ pour toujours renvoyer False.

>>> class Troll(object):
...     def __eq__(self, other):
...         return False
... 
>>> a = Troll()
>>> b = a
>>> id(a) == id(b)
True
>>> a == b
False

Cela étant dit, il devrait y avoir très quelques exemples dans la bibliothèque standard où les identifiants d'objet correspondent mais __eq__ peut renvoyer False de toute façon, bravo à MarkMüller pour avoir trouvé un bon exemple.

Donc, soit les objets sont fous, très spéciaux (comme nan), soit la concurrence vous mord. Considérez cet exemple extrême, où Foo a un _ plus raisonnable __eq__ méthode (qui "oublie" de vérifier les identifiants) et f is f est toujours True.

import threading

class Foo(object):
    def __init__(self):
        self.x = 1

    def __eq__(self, other):
        return isinstance(other, Foo) and self.x == other.x

f = Foo()

class MutateThread(threading.Thread):
    def run(self):
        while True:
            f.x = 2
            f.x = 1

class CheckThread(threading.Thread):
    def run(self):
        i = 1
        while True:
            if not (f == f):
                print 'loop {0}: f != f'.format(i) 
            i += 1

MutateThread().start()
CheckThread().start()

Production:

$ python eqtest.py
loop 520617: f != f
loop 1556675: f != f
loop 1714709: f != f
loop 2436222: f != f
loop 3210760: f != f
loop 3772996: f != f
loop 5610559: f != f
loop 6065230: f != f
loop 6287500: f != f
...
25
timgeb