これらの2行のコードの違いは何ですか?
if not x == 'val':
そして
if x != 'val':
1つは他よりも効率的ですか?
使用した方がいいですか
if x == 'val':
pass
else:
これらの2行のコードの違いは何ですか?
if not x == 'val':
そして
if x != 'val':
1つは他よりも効率的ですか?
使用した方がいいですか
if x == 'val':
pass
else:
回答:
を使用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 != bar
対if 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
ます。
__eq__
一貫性のないクラスはすべて完全に__ne__
壊れています。
not x == y
1つの以上の命令を持っています。私がコードをに入れたif
ところ、どちらも同じ数の命令を持っPOP_JUMP_IF_TRUE
ているPOP_JUMP_IF_FALSE
ことがわかりましたCOMPARE_OP
。if
私がs なしでコードをコンパイルしたとき、私はあなたが得たものを得ました。
==
と!=
相互排他的ではないが関与するSQLのような実装であるnull
値を。SQLにnull
戻らないtrue
と!=
SQLインタフェースのPythonの実装も同じ問題を有することができるので、他の値に比べ。
@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%も上回っています。これはあまり読みやすいものではありませんが、ごくわずかなパフォーマンス改善が必要な場合は、このルートをたどることができると思います。
最初の1つでは、Pythonは必要以上に1つ以上の操作を実行する必要があります(等しくないことを確認するだけでなく、等しいかどうかを確認する必要があるため、もう1つの操作)。1回の実行との違いを見分けることは不可能ですが、何度も実行する場合は、2回目の実行の方が効率的です。全体的に2番目のものを使用しますが、数学的には同じです
>>> 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
。そのため、何百万もの比較を行わない限り、ほとんどの場合、パフォーマンスの差は非常に小さく、それでもボトルネックの原因にはなりません。
他の回答のほとんどが正しくあなたの質問に答えので、追加のノートでは、クラスが定義されている場合のみ、ということで__eq__()
はなく__ne__()
、その後、あなたのCOMPARE_OP (!=)
実行する__eq__()
と、それを否定します。現時点では、3番目のオプションの方が少し効率的かもしれませんが、迅速に理解することが難しいため、速度が必要な場合にのみ検討する必要があります。
それはあなたがそれを読む方法についてです。not
演算子は動的であるため、それを適用することができます
if not x == 'val':
しかし!=
、何をするかと==
は逆の演算子として、より良い文脈で読むことができます。
not
演算子は動的」とはどういう意味ですか?
上記の読みやすさに関するコメントを詳しく説明します。
繰り返しになりますが、私は他の(パフォーマンスに重要ではない)懸念を無効にする可読性に完全に同意します。
私が指摘したいのは、脳が「ポジティブ」を「ネガティブ」よりも速く解釈することです。たとえば、「停止」対「行かない」(単語数の違いによるかなりお粗末な例)。
したがって、選択肢が与えられます:
if a == b
(do this)
else
(do that)
機能的に同等のものよりも好ましい:
if a != b
(do that)
else
(do this)
読みやすさ/理解しやすさが低いほど、バグが多くなります。おそらく最初のコーディングではなく、(あなたほどスマートではない!)メンテナンスの変更...