Was ist der Unterschied zwischen diesen beiden Codezeilen:
if not x == 'val':
und
if x != 'val':
Ist einer effizienter als der andere?
Wäre es besser zu benutzen
if x == 'val':
pass
else:
Was ist der Unterschied zwischen diesen beiden Codezeilen:
if not x == 'val':
und
if x != 'val':
Ist einer effizienter als der andere?
Wäre es besser zu benutzen
if x == 'val':
pass
else:
Antworten:
Verwenden Sie dis
, um den für die beiden Versionen generierten Bytecode anzuzeigen:
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
Letzteres hat weniger Operationen und ist daher wahrscheinlich etwas effizienter.
Es wurde darauf hingewiesen , in den commments (danke, @Quincunx ) , dass , wo man if foo != bar
gegen if not foo == bar
die Anzahl der Operationen ist genau das gleiche, es ist nur , dass die COMPARE_OP
Änderungen und POP_JUMP_IF_TRUE
schaltet auf 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
In diesem Fall ist es unwahrscheinlich, dass Sie überhaupt einen Leistungsunterschied feststellen, es sei denn, es gab einen Unterschied im Arbeitsaufwand für jeden Vergleich.
Beachten Sie jedoch, dass die beiden Versionen nicht immer logisch identisch sind , da dies von den Implementierungen __eq__
und __ne__
für die betreffenden Objekte abhängt . Gemäß der Datenmodelldokumentation :
Es gibt keine impliziten Beziehungen zwischen den Vergleichsoperatoren. Die Wahrheit von
x==y
bedeutet nicht, dass diesx!=y
falsch ist.
Beispielsweise:
>>> class Dummy(object):
def __eq__(self, other):
return True
def __ne__(self, other):
return True
>>> not Dummy() == Dummy()
False
>>> Dummy() != Dummy()
True
Schließlich, und vielleicht am wichtigsten ist : in der Regel, wo die beiden sind logisch identisch, x != y
ist viel besser lesbar alsnot x == y
.
__eq__
nicht mit übereinstimmt __ne__
, pleite.
not x == y
eine weitere Anweisung vorhanden ist. Als ich den Code in eine einfügte if
, stellte sich heraus, dass beide die gleiche Anzahl von Anweisungen haben, nur eine POP_JUMP_IF_TRUE
und die andere POP_JUMP_IF_FALSE
(das war der einzige Unterschied zwischen ihnen, abgesehen von der Verwendung einer anderen COMPARE_OP
). Als ich den Code ohne das if
s kompiliert habe , habe ich bekommen, was Sie haben.
==
und schließen !=
sich nicht aus ist eine SQL-ähnliche Umsetzung beteiligtnull
Werte. In SQL null
kehrt nicht true
zu im !=
Vergleich zu jedem anderen Wert, so Python - Implementierungen von SQL - Schnittstellen auch das gleiche Problem haben.
not ==
und hingewiesen !=
, es scheint der interessanteste Teil meiner Antwort zu sein! Ich denke nicht, dass dies der Ort ist, an dem man darüber nachdenken kann, ob, warum und wann dies sinnvoll ist - siehe z Warum hat Python eine __ne__
Operatormethode anstelle von nur __eq__
?
@jonrsharpe hat eine ausgezeichnete Erklärung, was los ist. Ich dachte, ich würde nur den Zeitunterschied zeigen, wenn ich jede der 3 Optionen 10.000.000 Mal ausführe (genug, um einen kleinen Unterschied zu zeigen).
Verwendeter Code:
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)
Und der cProfile-Profiler ergibt:
Wir können also sehen, dass zwischen if not x == 'val':
und ein sehr kleiner Unterschied von ~ 0,7% besteht if x != 'val':
. Von diesen if x != 'val':
ist die schnellste.
Am überraschendsten ist jedoch, dass wir das sehen können
if x == 'val':
pass
else:
ist in der Tat die schnellste und schlägt if x != 'val':
um ~ 0,3%. Dies ist nicht sehr gut lesbar, aber ich denke, wenn Sie eine vernachlässigbare Leistungsverbesserung wünschen, könnte man diesen Weg gehen.
In der ersten muss Python eine Operation mehr ausführen als nötig (anstatt nur zu prüfen, ob sie nicht gleich ist, muss geprüft werden, ob sie nicht wahr ist, also eine weitere Operation). Es wäre unmöglich, den Unterschied zu einer Ausführung zu erkennen, aber wenn sie mehrmals ausgeführt würde, wäre die zweite effizienter. Insgesamt würde ich die zweite verwenden, aber mathematisch sind sie gleich
>>> 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
Hier können Sie sehen, dass not x == y
eine Anweisung mehr als hat x != y
. Daher ist der Leistungsunterschied in den meisten Fällen sehr gering, es sei denn, Sie führen Millionen von Vergleichen durch, und selbst dann ist dies wahrscheinlich nicht die Ursache für einen Engpass.
Ein zusätzlicher Hinweis, da die anderen Antworten Ihre Frage größtenteils richtig beantwortet haben, ist, dass wenn eine Klasse nur definiert __eq__()
und nicht definiert __ne__()
, Sie COMPARE_OP (!=)
sie ausführen __eq__()
und negieren. Zu diesem Zeitpunkt ist Ihre dritte Option wahrscheinlich ein kleines bisschen effizienter, sollte aber nur in Betracht gezogen werden, wenn Sie die Geschwindigkeit benötigen, da es schwierig ist, sie schnell zu verstehen.
Es geht um deine Art, es zu lesen. not
Der Operator ist dynamisch, deshalb können Sie ihn in anwenden
if not x == 'val':
Könnte !=
aber in einem besseren Kontext als Operator gelesen werden, der das Gegenteil von dem ==
tut, was er tut.
not
Operator ist dynamisch" ?
Ich möchte meinen obigen Lesbarkeitskommentar erweitern.
Auch hier stimme ich der Lesbarkeit voll und ganz zu, die andere (leistungsschwache) Bedenken außer Kraft setzt.
Ich möchte darauf hinweisen, dass das Gehirn "positiv" schneller interpretiert als "negativ". ZB "Stop" vs. "Nicht gehen" (ein ziemlich mieses Beispiel aufgrund der unterschiedlichen Anzahl von Wörtern).
Also eine Wahl gegeben:
if a == b
(do this)
else
(do that)
ist dem funktional äquivalenten vorzuziehen:
if a != b
(do that)
else
(do this)
Weniger Lesbarkeit / Verständlichkeit führt zu mehr Fehlern. Vielleicht nicht in der Erstcodierung, aber die (nicht so kluge wie Sie!) Wartungsänderungen ...