Pythonでない場合== vs!=


183

これらの2行のコードの違いは何ですか?

if not x == 'val':

そして

if x != 'val':

1つは他よりも効率的ですか?

使用した方がいいですか

if x == 'val':
    pass
else:

101
読みやすい方が良いです。プログラムのボトルネックがここにあるとは思いません
Thomas Ayoub

1
この質問は、「x not in list」と「not x in list」のケースに興味があります
SomethingSomething

5
@SomethingSomethingそれらは同じように解釈されます。
jonrsharpe 2015年

4
上記のコメントに対する@SomethingSomethingリファレンス:stackoverflow.com/q/8738388/3001761
jonrsharpe

1
@SomethingSomethingそれも同じです。構文の解釈方法です。2つのオペランドが何であるかは関係ありません。
jonrsharpe 2015年

回答:


229

を使用disして、2つのバージョン用に生成されたバイトコードを確認します。

not ==

  4           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               2 (==)
              9 UNARY_NOT           
             10 RETURN_VALUE   

!=

  4           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 RETURN_VALUE   

後者は操作が少ないため、わずかに効率がよくなる可能性があります。


それは、指摘されたcommmentsで(おかげで、@Quincunxあなたが持っているところという)if foo != barif not foo == bar操作の数がまったく同じで、それだけということだCOMPARE_OP変化とPOP_JUMP_IF_TRUEに切り替わりPOP_JUMP_IF_FALSE

not ==

  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_TRUE        16

!=

  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 POP_JUMP_IF_FALSE       16

この場合、各比較に必要な作業量に違いがない限り、パフォーマンスの違いはまったくありません。


しかし、注目すべきは、2つのバージョンがあること、常に論理的に同じではありません、それはの実装に依存して、__eq__そして__ne__問題のオブジェクトのため。データモデルのドキュメントごと:

比較演算子間に暗黙の関係はありません。の真実は、x==yそれx!=yが偽であることを意味しません。

例えば:

>>> class Dummy(object):
    def __eq__(self, other):
        return True
    def __ne__(self, other):
        return True


>>> not Dummy() == Dummy()
False
>>> Dummy() != Dummy()
True

最後に、そしておそらく最も重要なことは、一般的に、2つ論理的に同一である場合x != yは、よりもはるかに読みやすくなりnot x == yます。


29
実際には、__eq__一貫性のないクラスはすべて完全に__ne__壊れています。
ケビン

8
そうではないことに注意してください、常にその真のnot x == y1つの以上の命令を持っています。私がコードをに入れたifところ、どちらも同じ数の命令を持っPOP_JUMP_IF_TRUEているPOP_JUMP_IF_FALSEことがわかりましたCOMPARE_OPif私がs なしでコードをコンパイルしたとき、私はあなたが得たものを得ました。
ジャスティン

1
もう一つの例==!=相互排他的ではないが関与するSQLのような実装であるnull値を。SQLにnull戻らないtrue!=SQLインタフェースのPythonの実装も同じ問題を有することができるので、他の値に比べ。
Joe

私は間の可能な違いに言及していなかった希望し始めているnot ==!=、私の答えの中で最も興味深い部分のようです!if、なぜ、いつそれが理にかなっているのかをここで__ne____eq__
jonrsharpe

29

@jonrsharpeは何が起こっているのかについての優れた説明があります。3つのオプションのそれぞれを10,000,000回実行したときの時間の違いを表示するだけだと思いました(わずかな違いを示すのに十分です)。

使用されるコード:

def a(x):
    if x != 'val':
        pass


def b(x):
    if not x == 'val':
        pass


def c(x):
    if x == 'val':
        pass
    else:
        pass


x = 1
for i in range(10000000):
    a(x)
    b(x)
    c(x)

そして、cProfileプロファイラの結果:

ここに画像の説明を入力してください

したがって、if not x == 'val':との間には〜0.7%の非常に小さな違いがあることがわかりif x != 'val':ます。これらのうちif x != 'val':、最速です。

しかし、最も驚くべきことには、

if x == 'val':
        pass
    else:

実は最速で、if x != 'val':0.3%も上回っています。これはあまり読みやすいものではありませんが、ごくわずかなパフォーマンス改善が必要な場合は、このルートをたどることができると思います。


31
皆さんがこの情報に基づいて行動しないことを知っていることを願っています!0.3%の改善、または10%の改善のために判読できない変更を加えることはめったに良い考えではありません。この種の改善はエバネッセントになる可能性が非常に高くなります(そして、良い方法ではありません:Pythonランタイムのごくわずかな変更)ゲインを排除または逆転させることもできます
Malvolio

1
@Malvolioさらに、Python にはさまざまな実装があります。
Cees Timmerman

6

最初の1つでは、Pythonは必要以上に1つ以上の操作を実行する必要があります(等しくないことを確認するだけでなく、等しいかどうかを確認する必要があるため、もう1つの操作)。1回の実行との違いを見分けることは不可能ですが、何度も実行する場合は、2回目の実行の方が効率的です。全体的に2番目のものを使用しますが、数学的には同じです


5
>>> from dis import dis
>>> dis(compile('not 10 == 20', '', 'exec'))
  1           0 LOAD_CONST               0 (10)
              3 LOAD_CONST               1 (20)
              6 COMPARE_OP               2 (==)
              9 UNARY_NOT
             10 POP_TOP
             11 LOAD_CONST               2 (None)
             14 RETURN_VALUE
>>> dis(compile('10 != 20', '', 'exec'))
  1           0 LOAD_CONST               0 (10)
              3 LOAD_CONST               1 (20)
              6 COMPARE_OP               3 (!=)
              9 POP_TOP
             10 LOAD_CONST               2 (None)
             13 RETURN_VALUE

ここでnot x == yは、の指示が1つだけ多いことがわかりますx != y。そのため、何百万もの比較を行わない限り、ほとんどの場合、パフォーマンスの差は非常に小さく、それでもボトルネックの原因にはなりません。


5

他の回答のほとんどが正しくあなたの質問に答えので、追加のノートでは、クラスが定義されている場合のみ、ということで__eq__()はなく__ne__()、その後、あなたのCOMPARE_OP (!=)実行する__eq__()と、それを否定します。現時点では、3番目のオプションの方が少し効率的かもしれませんが、迅速に理解することが難しいため、速度が必要な場合にのみ検討する必要があります。


3

それはあなたがそれを読む方法についてです。not演算子は動的であるため、それを適用することができます

if not x == 'val':

しかし!=、何をするかと==は逆の演算子として、より良い文脈で読むことができます。


3
not演算子は動的」とはどういう意味ですか?
jonrsharpe 2015年

1
@jonrsharpe彼は、「not x」がx .__ bool __()[python 3-python 2はゼロ以外を使用する]を呼び出して結果を元に戻すことを意味すると思います(docs.python.org/3/reference/datamodel.html#object。 __bool__
jdferreira

1

上記の読みやすさに関するコメントを詳しく説明します。

繰り返しになりますが、私は他の(パフォーマンスに重要ではない)懸念を無効にする可読性に完全に同意します。

私が指摘したいのは、脳が「ポジティブ」を「ネガティブ」よりも速く解釈することです。たとえば、「停止」対「行かない」(単語数の違いによるかなりお粗末な例)。

したがって、選択肢が与えられます:

if a == b
    (do this)
else
    (do that)

機能的に同等のものよりも好ましい:

if a != b
    (do that)
else
    (do this)

読みやすさ/理解しやすさが低いほど、バグが多くなります。おそらく最初のコーディングではなく、(あなたほどスマートではない!)メンテナンスの変更...


1
脳は「ポジティブ」を「ネガティブ」よりも速く解釈しますこれは経験からですか、またはこれに関する研究を読んでいますか?(これを実行する)または(それを実行する)のコードに応じて、!= bの方が理解しやすいので、私はただ尋ねています。
lafferc 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.