Tupel oder Liste bei der Verwendung von 'in' in einer 'if' -Klausel?

Welcher Ansatz ist besser? Mit einem Tupel, wie:

if number in (1, 2): 

Oder eine Liste, wie:

 if number in [1, 2]: 

Welches wird für solche Anwendungen empfohlen und warum (sowohl logisch als auch leistungsstark)?

  • Was ist die pythonische Art, Tupel auszupacken?
  • Wie summiere ich den ersten Wert in jedem Tupel in einer Liste von Tupeln in Python?
  • Ändern aller Tupel in einer Python-Liste
  • Python, Split Tupel Artikel zu einzelnen Sachen
  • Zeitkomplexität von Tupel in Python
  • Wie man Tupel verkettt
  • Tupel mit einem gemeinsamen Element finden
  • Löschen eines vorherigen Tokens in einem Satz, wenn das gleiche wie das aktuelle Token python ist
  • One Solution collect form web for “Tupel oder Liste bei der Verwendung von 'in' in einer 'if' -Klausel?”

    Der CPython-Interpreter ersetzt das zweite Formular mit dem ersten .

    Das ist, weil das Laden des Tupels von einer Konstanten eine Operation ist, aber die Liste wäre 3 Operationen; Laden Sie die beiden Integer-Inhalte und erstellen Sie ein neues Listenobjekt.

    Weil du ein Listenliteral benutzt, das sonst nicht erreichbar ist, ersetzt es ein Tupel:

     >>> import dis >>> dis.dis(compile('number in [1, 2]', '<stdin>', 'eval')) 1 0 LOAD_NAME 0 (number) 3 LOAD_CONST 2 ((1, 2)) 6 COMPARE_OP 6 (in) 9 RETURN_VALUE 

    Hier lädt der zweite Bytecode in einem Schritt ein (1, 2) Tupel als Konstante. Vergleichen Sie dies mit der Erstellung eines Listenobjekts, das in einem Mitgliedschafts-Test nicht verwendet wird:

     >>> dis.dis(compile('[1, 2]', '<stdin>', 'eval')) 1 0 LOAD_CONST 0 (1) 3 LOAD_CONST 1 (2) 6 BUILD_LIST 2 9 RETURN_VALUE 

    Hier sind N + 1 Schritte für ein Listenobjekt der Länge N erforderlich.

    Diese Substitution ist eine CPython-spezifische Peephole-Optimierung; Siehe die Python/peephole.c Quelle . Für andere Python-Implementierungen dann willst du mit unveränderlichen Objekten stattdessen bleiben.

    Das heißt, die beste Option bei der Verwendung von Python 3.2 und höher, ist es, ein Set-Literal zu verwenden :

     if number in {1, 2}: 

    Wie der Guckloch-Optimierer wird ersetzen, dass mit einem frozenset() Objekt und Mitgliedschaft Tests gegen Sets sind O (1) konstante Operationen:

     >>> dis.dis(compile('number in {1, 2}', '<stdin>', 'eval')) 1 0 LOAD_NAME 0 (number) 3 LOAD_CONST 2 (frozenset({1, 2})) 6 COMPARE_OP 6 (in) 9 RETURN_VALUE 

    Diese Optimierung wurde in Python 3.2 hinzugefügt, wurde aber nicht in Python 2 zurückgesetzt.

    Als solches erkennt der Python 2-Optimierer diese Option nicht und die Kosten für den Aufbau eines set oder eines frozenset aus dem Inhalt sind fast garantiert kostspieliger als mit einem Tupel für den Test.

    Set Mitgliedschaft Tests sind O (1) und schnell; Prüfung gegen ein Tupel ist O (n) schlimmsten Fall. Obwohl das Testen wiederholt wird, muss ein Satz den Hash berechnen (höhere konstante Kosten), die Kosten für das Testen gegen ein Tupel außer dem ersten Element wird immer höher sein. Im Durchschnitt sind die Sets einfach schneller:

     >>> import timeit >>> timeit.timeit('1 in (1, 3, 5)', number=10**7) # best-case for tuples 0.21154764899984002 >>> timeit.timeit('8 in (1, 3, 5)', number=10**7) # worst-case for tuples 0.5670104179880582 >>> timeit.timeit('1 in {1, 3, 5}', number=10**7) # average-case for sets 0.2663505630043801 >>> timeit.timeit('8 in {1, 3, 5}', number=10**7) # worst-case for sets 0.25939063701662235 
    Python ist die beste Programmiersprache der Welt.