web-dev-qa-db-ja.com

Pythonでない場合== vs if!=

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

if not x == 'val':

そして

if x != 'val':

一方が他方より効率的ですか?

使うほうがいいですか

if x == 'val':
    pass
else:
170
lafferc

2つのバージョン用に生成されたバイトコードを調べるには、 dis を使用します。

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   

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


if foo != barif not foo == barの操作数が全く同じであることがCOMPARE_OPが変更されPOP_JUMP_IF_TRUEPOP_JUMP_IF_FALSEに切り替わるだけであることが、コミットメント= /( @Quincunx )で @Quincunx )で指摘されました。

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__の実装に依存するため、常に論理的に同一であるとは限りません 。 Per データモデルドキュメント

比較演算子の間に暗黙の関係はありません。 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つのareが論理的に同一の場合、x != ynot x == yよりもはるかに読みやすくなります。

213
jonrsharpe

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

使用コード

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プロファイラーの結果:

enter image description here

そのため、if not x == 'val':if x != 'val':の間には、0.7%程度のごくわずかな違いがあることがわかります。これらのうち、if x != 'val':が最速です。

しかし、最も驚くべきことに、我々はそれを見ることができます

if x == 'val':
        pass
    else:

実際には最速で、if x != 'val':を最大0.3%上回ります。これはあまり読みやすいものではありませんが、ごくわずかなパフォーマンスの向上を望んでいるのであれば、この道をたどることができるでしょう。

29
Red Shift

最初に、Pythonは必要以上にもう1つの操作を実行しなければなりません(それが等しくないことを単にチェックする代わりに、それが等しいことが真実でないかどうか、したがってもう1つの操作をチェックしなければなりません)。 1回の実行との違いを見分けることは不可能ですが、何度も実行すると、2回目の実行がより効率的になります。全体的には2番目のものを使用しますが、数学的には同じです。

6
JediPythonClone
>>> 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 == yx != yよりももう1つ命令が多いことがわかります。そのため、何百万もの比較を行っていない限り、ほとんどの場合、パフォーマンスの違いはごくわずかになります。それでも、これがボトルネックの原因になることはおそらくありません。

5
kylie.a

追加の注意点は、他の答えはあなたの質問にほとんど正しく答えたので、クラスが__eq__()だけを定義し、__ne__()を定義しない場合、あなたのCOMPARE_OP (!=)__eq__()を実行しそれを否定するということです。その時点では、3番目の選択肢は少し効率的になる可能性がありますが、速さが必要な場合にのみ考慮する必要があります。すぐに理解するのは難しいからです。

5
Jacob Zimmerman

それはあなたの読み方です。 not演算子は動的です、それであなたがそれを適用することができる理由

if not x == 'val':

しかし、!=は、==が行うこととは反対のことを行う演算子として、より良いコンテキストで読むことができます。

3
Himanshu Mishra

私は上記の私の読みやすさのコメントを拡大したいです。

繰り返しになりますが、読みやすさが他の(パフォーマンスに重要ではない)懸念を上書きすることに完全に同意します。

私が指摘したいのは、脳が「否定的」よりも速く「肯定的」を解釈することです。たとえば、「停止する」と「行かない」(単語数の違いによるかなりお粗末な例)。

だから選択を与えられた:

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

機能的に等価なものよりも好ましいです。

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

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

1
Alan Jay Weiner