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:

  • Pandas Zeitschriften Plot Einstellung X-Achse großen und kleineren Zecken und Etiketten
  • Django kann nicht auf raw_post_data zugreifen
  • SQLAlchemy Filter Abfrage "Spalte LIKE ANY (Array)"
  • Python - Warum funktionieren die Such- und Indexmethoden anders?
  • Scrapy, kratzen Seiten von zweiten Satz von Links
  • Aufteilung der Datei in kleinere Dateien nach Anzahl der Felder
  •  if number in [1, 2]: 

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

    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.