web-dev-qa-db-ja.com

Python!=操作vs「ではない」

この質問 のコメントで、使用することを推奨するステートメントを見ました

result is not None

result != None

私は違いが何であり、なぜ一方が他方よりも推奨されるのだろうと思っていましたか?

203
viksit

==等価テストです。右側と左側が等しいオブジェクトであるかどうかをチェックします(それらの__eq__または__cmp__メソッドによる)。

is同一性テストです。右側と左側がまったく同じオブジェクトかどうかをチェックします。メソッド呼び出しは行われません。オブジェクトはis操作に影響を与えることはできません。

isのふりをしたいオブジェクトを気にしない場合、またはNoneと比較したときにオブジェクトが壊れないように保護する場合は、NoneなどのシングルトンにNone(およびis not)を使用します。

251
Thomas Wouters

まず、いくつかの用語を見てみましょう。質問に回答するだけの場合は、「質問への回答」までスクロールします。

定義

オブジェクトID:オブジェクトを作成するときに、変数に割り当てることができます。その後、別の変数に割り当てることもできます。そしてもう一つ。

>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True

この場合、cancelclose、およびdismissはすべて、メモリ内の同じオブジェクトを参照します。 Buttonオブジェクトを1つだけ作成し、3つの変数はすべてこの1つのオブジェクトを参照しています。 cancelclose、およびdismissはすべてidenticalオブジェクトを参照すると言います。つまり、1つのオブジェクトを参照します。

オブジェクトの等価性:2つのオブジェクトを比較する場合、通常、メモリ内の同じオブジェクトexactを参照していることは気にしません。オブジェクトの等価性により、2つのオブジェクトの比較方法について独自のルールを定義できます。 if a == b:と書くと、本質的にif a.__eq__(b):と言っていることになります。これにより、a__eq__メソッドを定義できるため、独自の比較ロジックを使用できます。

等価比較の理論的根拠

理由: 2つのオブジェクトのデータはまったく同じですが、同一ではありません。 (メモリ内の同じオブジェクトではありません。)例:文字列

>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True

注:Pythonはメモリに新しい文字列を作成せずに通常の文字列を再利用できるほどスマートなので、ここではUnicode文字列を使用します。

ここには、abという2つのUnicode文字列があります。内容はまったく同じですが、メモリ内の同じオブジェクトではありません。ただし、それらを比較するときは、同等に比較する必要があります。ここで起こっているのは、unicodeオブジェクトが__eq__メソッドを実装していることです。

class unicode(object):
    # ...

    def __eq__(self, other):
        if len(self) != len(other):
            return False

        for i, j in Zip(self, other):
            if i != j:
                return False

        return True

注:unicode__eq__は、これよりも確実に効率的に実装されます。

理由: 2つのオブジェクトのデータは異なりますが、一部のキーデータが同じ場合は同じオブジェクトと見なされます。 例:ほとんどのタイプのモデルデータ

>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True

ここには、abという2つのDellモニターがあります。彼らは同じメーカーとモデルを持っています。ただし、それらは同じデータもメモリ内の同じオブジェクトでもありません。ただし、それらを比較するときは、同等に比較する必要があります。ここで何が起きているかは、Monitorオブジェクトが__eq__メソッドを実装していることです。

class Monitor(object):
    # ...

    def __eq__(self, other):
        return self.make == other.make and self.model == other.model

質問に答える

Noneと比較するときは、常にis notを使用してください。 Pythonにはシングルトンはありません-メモリにはインスタンスが1つしかありません。

identityを比較することにより、これを非常に迅速に実行できます。 Pythonは、参照しているオブジェクトがグローバルNoneオブジェクトと同じメモリアドレスを持っているかどうかを確認します-2つの数値の非常に高速な比較。

equalityを比較することにより、Pythonはオブジェクトに__eq__メソッドがあるかどうかを調べる必要があります。そうでない場合は、各スーパークラスを調べて__eq__メソッドを探します。見つかった場合、Pythonはそれを呼び出します。これは、__eq__メソッドが遅く、他のオブジェクトがNoneであることに気付いたときにすぐに返らない場合、特に悪いです。

__eq__を実装しませんでしたか? Pythonは、おそらくobject__eq__メソッドを見つけ、代わりにそれを使用します-とにかくオブジェクトのIDをチェックするだけです。

Pythonで他のほとんどのものを比較するときは、!=を使用します。

127
Wesley

以下を考慮してください。

class Bad(object):
    def __eq__(self, other):
        return True

c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)
24
Alok Singhal

Noneはシングルトンなので、ID比較は常に機能しますが、オブジェクトは.__eq__()を介して等値比較を偽造できます。

 >>>()is()
 True 
 >>> 1 is 1 
 True 
 >>>(1、)== (1、)
 True 
 >>>(1、)は(1、)
 False 
 >>> a =(1、)
 >>> b = a 
 >>> a is b 
 True 

一部のオブジェクトはシングルトンであるため、isとそれらは==と同等です。ほとんどはそうではありません。

7
ephemient