python Warum ist 'x' in ('x',) schneller als 'x' == 'x'?




1 Answers

Hier spielen drei Faktoren eine Rolle, die zusammen dieses überraschende Verhalten erzeugen.

Erstens: Der Operator in nimmt eine Abkürzung und prüft die Identität ( x is y ), bevor er die Gleichheit überprüft ( x == y ):

>>> n = float('nan')
>>> n in (n, )
True
>>> n == n
False
>>> n is n
True

Zweitens: Wegen Pythons String-Interning sind beide "x" s in "x" in ("x", ) identisch:

>>> "x" is "x"
True

(große Warnung: dies ist ein implementierungsspezifisches Verhalten!) sollte niemals zum Vergleichen von Strings verwendet werden, da es manchmal überraschende Antworten gibt; zum Beispiel "x" * 100 is "x" * 100 ==> False )

Drittens: tuple.__contains__ (wie in Veedracs fantastischer Antwort beschrieben) , tuple.__contains__ ( x in (y, ) ist ungefähr äquivalent zu (y, ).__contains__(x) ) erreicht den Punkt der Identitätsprüfung schneller als str.__eq__ x == y ist ungefähr äquivalent zu x.__eq__(y) ).

Sie können Beweise dafür sehen, weil x in (y, ) signifikant langsamer ist als das logisch äquivalente, x == y :

In [18]: %timeit 'x' in ('x', )
10000000 loops, best of 3: 65.2 ns per loop

In [19]: %timeit 'x' == 'x'    
10000000 loops, best of 3: 68 ns per loop

In [20]: %timeit 'x' in ('y', ) 
10000000 loops, best of 3: 73.4 ns per loop

In [21]: %timeit 'x' == 'y'    
10000000 loops, best of 3: 56.2 ns per loop

Der Fall x in (y, ) ist langsamer, da nach dem Fehlschlagen des Vergleichs der in Operator auf die normale Gleichheitsüberprüfung zurückfällt (dh mit == ), so dass der Vergleich ungefähr die gleiche Zeit wie == , Rendern benötigt die gesamte Operation langsamer wegen des Aufwands beim Erstellen des Tupels, Gehen seiner Mitglieder usw.

Beachten Sie auch, dass a in (b, ) nur schneller ist, wenn a a is b :

In [48]: a = 1             

In [49]: b = 2

In [50]: %timeit a is a or a == a
10000000 loops, best of 3: 95.1 ns per loop

In [51]: %timeit a in (a, )      
10000000 loops, best of 3: 140 ns per loop

In [52]: %timeit a is b or a == b
10000000 loops, best of 3: 177 ns per loop

In [53]: %timeit a in (b, )      
10000000 loops, best of 3: 169 ns per loop

(Warum ist a in (b, ) schneller als a is b or a == b ? Meine Annahme wäre weniger virtuelle Maschinenanweisungen - a in (b, ) ist nur ~ 3 Anweisungen, wobei a is b or a == b wird ein paar mehr VM-Anweisungen sein)

Veedrac's Antwort - https://stackoverflow.com/a/28889838/71522 - geht sehr viel detaillierter auf das was passiert während jedes == und in und ist das Lesen wert.

python performance python-3.x python-internals
>>> timeit.timeit("'x' in ('x',)")
0.04869917374131205
>>> timeit.timeit("'x' == 'x'")
0.06144205736110564

Funktioniert auch für Tupel mit mehreren Elementen, beide Versionen scheinen linear zu wachsen:

>>> timeit.timeit("'x' in ('x', 'y')")
0.04866674801541748
>>> timeit.timeit("'x' == 'x' or 'x' == 'y'")
0.06565782838087131
>>> timeit.timeit("'x' in ('y', 'x')")
0.08975995576448526
>>> timeit.timeit("'x' == 'y' or 'x' == 'y'")
0.12992391047427532

Darauf aufbauend sollte ich anfangen, überall statt == !




Related