web-dev-qa-db-ja.com

==と比較すると、同じIDのオブジェクトは常に等しいですか?

2つのオブジェクトo1とo2があり、

id(o1) == id(o2)

trueを返します。

その後、それは続きますか

o1 == o2

それとも常にそうではないのですか?私が取り組んでいる論文は、これは事実ではないと述べていますが、私の意見ではそれは真実であるはずです!

59
Jonas Kaufmann

常にではない:

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

または質問と同じ方法で定式化:

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

だが

>>> nan == nan
False

NaN は奇妙なことです。定義によれば、それはそれ自体と同じでも、それ以下でも以下でもありません。しかし、それは同じオブジェクトです。 this SO question ですべての比較がFalseを返す必要がある理由の詳細。

129
Mike Müller

論文は正しいです。以下を検討してください。

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

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

出力はこれです:

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

id(o1) == id(o2)o1 == o2を意味しません。

常にTrollを返すように__eq__をオーバーライドするこのFalseを見てみましょう。

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

そうは言っても、標準ライブラリにはveryの例がいくつかあり、オブジェクトIDは一致しますが、__eq__Falseを返すことができます。良いものを見つけるために@MarkMüllerを称賛例。

そのため、オブジェクトが非常識で、非常に特殊(nanのような)であるか、同時実行性があなたを噛みます。この極端な例を考えてみましょう。ここで、Fooにはより合理的な__eq__メソッド(IDのチェックを忘れている)があり、f is fは常に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()

出力:

$ 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