Python!=操作vs「ありません」


250

この質問へのコメントで、私は使用を推奨する声明を見ました

result is not None

result != None

私は違いが何であるのか、そしてなぜ一方が他方よりも推奨されるのか疑問に思っていましたか?



1
うーん。両方の質問への答えは同じ概念ですが、ここでの賛成票と詳細な答えは、同一性と同等性のテストの概念に独立して貢献していると思います。
viksit 2010

回答:


301

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

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

のようなシングルトンに対してis(およびis not)を使用します。たとえばNone、ふりをする可能性のあるオブジェクトが気にならない場合Noneや、と比較したときにオブジェクトが壊れないように保護する場合ですNone


3
答えてくれてありがとう-なしと比較して、オブジェクトが壊れる可能性がある状況について詳しく説明してもらえますか?
viksit 2010

3
@viksit。 Noneメソッドはほとんどなく、属性はほとんどありません。__eq__テストでメソッドまたは属性が想定されていた場合、それが壊れる可能性があります。 def __eq__( self, other ): return self.size == other.size。たとえば、otherたまたまあると壊れますNone
S.Lott

36
これを理解するための私のお気に入りの方法は、Python isはJavaのようなもの==です。Python ==はJavaに似ています.equals()。もちろん、これはJavaを知っている場合にのみ役立ちます。
MatrixFrog 2010

4
@MatrixFrog:でPHPやJavaScriptは、我々はそれが言うisようなものです===(非常に等しい)、逆is notに似ている!==(正確に一致しません)。
Orwellophile 2017

3
あるis not一人のオペレータは、またはそれだけの結果を否定されたisように、内部not foo is bar
Asad Moosvi 2017

150

最初に、いくつかの用語について説明します。質問への回答を希望する場合は、「質問への回答」までスクロールしてください。

定義

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

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

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

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

同等性比較の根拠

理論的根拠: 2つのオブジェクトはまったく同じデータを持っていますが、同一ではありません。(これらはメモリ内の同じオブジェクトではありません。) 例:文字列

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

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

ここでは、2つのUnicode文字列とがaありbます。内容はまったく同じですが、メモリ内の同じオブジェクトではありません。ただし、それらを比較する場合は、同等に比較する必要があります。ここで起こっていることは、ユニコードオブジェクトが__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

注:__eq__on unicodeは間違いなくこれよりも効率的に実装されています。

理論的根拠: 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

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

class Monitor(object):
    # ...

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

あなたの質問に答える

と比較する場合はNone、常にを使用してくださいis not。Pythonのシングルトンはありません。メモリに存在するインスタンスは1つだけです。

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

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

実装しませんでした__eq__か?次に、Pythonはおそらく__eq__メソッドを見つけobjectて代わりに使用します-これはとにかくオブジェクトのアイデンティティをチェックするだけです。

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


42

以下を検討してください。

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)

1
これは非常に役立つ単純な例です。ありがとうございました。
msarafzadeh

18

Noneはシングルトンであるため、恒等比較は常に機能しますが、オブジェクトはを介して等価比較を偽造できます.__eq__()


面白いですね!ところで、等号比較を偽って見せたいのはどのような状況でしょうか?これは何らかの形でセキュリティに影響を与えると思います。
viksit

1
それは平等を偽造することではなく、平等を実現することです。オブジェクトを別のオブジェクトと比較する方法を定義する理由はたくさんあります。
Thomas Wouters、

1
セキュリティの問題よりも混乱の問題のほうが多いと思います。
グレッグヒューギル

2
私はとの等価性を偽る理由には出会いませんでしたがNoneNone他の型に対する等価性を実装することの副作用として、に関する不正な動作が発生する可能性があります。それは正確さの意味合いであるので、それはそれほどセキュリティの意味合いではありません。
Ignacio Vazquez-Abrams

ああ、そうか。明確化のためのThx。
viksit 2010

10
>>>()は()
本当
>>> 1は1
本当
>>>(1、)==(1、)
本当
>>>(1、)は(1、)です
誤り
>>> a =(1、)
>>> b = a
>>> aはb
本当

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


4
これらのほとんどは、偶然/実装の詳細によってのみ機能します。()そして1本質的にシングルトンではありません。
マイクグラハム

1
CPythonの実装では、短整数(-NSMALLNEGINTS <= n <= NSMALLPOSINTS)と空のタプルシングルトンです。実際、文書化も保証もされていませんが、変更される可能性はほとんどありません。
ephemient

3
それはそれがどのように実装されるかですが、それは意味のあるものでも、有用でも、教育的でもありません。
マイクグラハム

1
特に、Pythonの実装はCPythonだけではありません。Pythonの実装によって異なる可能性のある動作に依存することは、一般的に私にとってはBad Idea™のようです。
me_and 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.