Ersatz für switch-Anweisung in Python?

Lesezeit: 7 Minuten

Benutzer-Avatar
Michael Schneider

Ich möchte eine Funktion in Python schreiben, die basierend auf dem Wert eines Eingabeindex verschiedene feste Werte zurückgibt.

In anderen Sprachen würde ich a verwenden switch oder case -Anweisung, aber Python scheint keine zu haben switch Aussage. Was sind die empfohlenen Python-Lösungen in diesem Szenario?

  • Zugehöriger PEP, verfasst von Guido selbst: PEP 3103

    – chb

    16. Juni 2012 um 17:22 Uhr

  • @chb In diesem PEP erwähnt Guido nicht, dass if/elif-Ketten auch eine klassische Fehlerquelle sind. Es ist ein sehr fragiles Konstrukt.

    – es ist Bruce

    9. Januar 2014 um 13:46 Uhr

  • Bei allen Lösungen fehlt hier die Erkennung von Doppelte Fallwerte. Als Fail-Fast-Prinzip kann dies ein wichtigerer Verlust sein als die Leistung oder die Fallthrough-Funktion.

    – Bob Stein

    17. Oktober 2014 um 19:04 Uhr

  • switch ist tatsächlich “vielseitiger” als etwas, das basierend auf dem Wert eines Eingabeindex unterschiedliche feste Werte zurückgibt. Es ermöglicht die Ausführung verschiedener Codeteile. Es muss eigentlich nicht einmal ein Wert zurückgegeben werden. Ich frage mich, ob einige der Antworten hier ein guter Ersatz für einen General sind switch -Anweisung oder nur für den Fall, dass Werte zurückgegeben werden, ohne dass allgemeine Codeteile ausgeführt werden können.

    – sancho.s ReinstateMonicaCellio

    14. Mai 2017 um 21:29 Uhr


  • Auf die gleiche Weise treffen Syntaxen wie Rubys Fall … wenn … (oder Scalas Übereinstimmung, Haskells Fall, Perls gegebenes/wann) auf einen gemeinsamen Anwendungsfall und bieten eine starke Abstraktion. if…elif… ist ein schlechter Ersatz.

    – es ist Bruce

    1. Oktober 2017 um 7:14 Uhr

Benutzer-Avatar
Nick

Wenn Sie Standardeinstellungen möchten, können Sie das Wörterbuch verwenden get(key[, default]) Funktion:

def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 will be returned default if x is not found

  • Was ist, wenn ‘a’ und ‘b’ mit 1 übereinstimmen und ‘c’ und ‘d’ mit 2 übereinstimmen?

    – John Mei

    9. April 2010 um 7:57 Uhr

  • @JM: Nun, offensichtlich unterstützen Wörterbuchsuchen keine Fall-Throughs. Sie könnten eine doppelte Wörterbuchsuche durchführen. Dh ‘a’ & ‘b’ zeigen auf Antwort1 und ‘c’ und ‘d’ zeigen auf Antwort2, die in einem zweiten Wörterbuch enthalten sind.

    – Nik

    9. April 2010 um 9:54 Uhr

  • es ist besser, einen Standardwert zu übergeben

    – HaTiMSum

    13. Oktober 2016 um 11:01 Uhr

  • Es gibt ein Problem mit diesem Ansatz, erstens jedes Mal, wenn Sie f aufrufen, um das Diktat erneut zu erstellen, zweitens, wenn Sie einen komplexeren Wert haben, können Sie Ausnahmen erhalten, z. wenn x ein Tupel ist und wir so etwas tun wollen x = (‘a’) def f(x): return { ‘a’: x[0]’b’: x[1] }.get(x[0]9) Dadurch wird IndexError ausgelöst

    – Idan Haim Shalom

    30. August 2017 um 8:01 Uhr


  • @Idan: Die Frage war, den Schalter zu replizieren. Ich bin mir sicher, dass ich diesen Code auch knacken könnte, wenn ich versuchen würde, ungerade Werte einzugeben. Ja, es wird neu erstellt, aber es ist einfach zu beheben.

    – Nick

    19. September 2017 um 21:59 Uhr

  • Er fragt nach festen Werten. Warum eine Funktion generieren, um etwas zu berechnen, wenn es sich um eine Suche handelt? Interessante Lösung für andere Probleme.

    – Nick

    21. Januar 2010 um 17:06 Uhr

  • Es ist vielleicht keine gute Idee, in diesem Fall Lambda zu verwenden, da Lambda tatsächlich jedes Mal aufgerufen wird, wenn das Wörterbuch erstellt wird.

    – Ascher

    22. April 2012 um 21:48 Uhr

  • Leider ist dies das nächste, was die Leute bekommen werden. Methoden, die verwenden .get() (wie die aktuell höchsten Antworten) vor dem Versand alle Möglichkeiten eifrig evaluieren müssen und daher nicht nur (nicht nur sehr, sondern) extrem ineffizient sind und auch keine Nebenwirkungen haben können; Diese Antwort umgeht dieses Problem, ist aber ausführlicher. Ich würde nur if/elif/else verwenden, und selbst diese brauchen genauso lange zum Schreiben wie ‘case’.

    – Ninjagecko

    17. März 2014 um 13:48 Uhr


  • Würde dies nicht jedes Mal in allen Fällen alle Funktionen/Lambdas auswerten, auch wenn nur eines der Ergebnisse zurückgegeben wird?

    – slf

    6. August 2014 um 19:04 Uhr

  • @slf Nein, wenn der Kontrollfluss diesen Codeabschnitt erreicht, erstellt er 3 Funktionen (durch die Verwendung der 3 Lambdas) und erstellt dann ein Wörterbuch mit diesen 3 Funktionen als Werte, aber sie bleiben unaufgerufen (auswerten ist in diesem Zusammenhang zunächst etwas zweideutig). Dann wird das Wörterbuch über indiziert [value]die nur eine der 3 Funktionen zurückgibt (vorausgesetzt value ist einer der 3 Schlüssel). Die Funktion wurde zu diesem Zeitpunkt noch nicht aufgerufen. Dann (x) ruft die gerade zurückgegebene Funktion mit auf x als Argument (und das Ergebnis geht an result). Die anderen 2 Funktionen werden nicht aufgerufen.

    – blubberdiblub

    18. September 2015 um 6:11 Uhr


Zusätzlich zu den Wörterbuchmethoden (die ich übrigens sehr mag) können Sie auch verwenden ifelifelse um die zu erhalten switch/case/default Funktionalität:

if x == 'a':
    # Do the thing
elif x == 'b':
    # Do the other thing
if x in 'bc':
    # Fall-through by not using elif, but now the default case includes case 'a'!
elif x in 'xyz':
    # Do yet another thing
else:
    # Do the default

Dies ist natürlich nicht identisch mit Switch/Case – Sie können nicht so leicht durchfallen wie das weglassen break Aussage, aber Sie können einen komplizierteren Test haben. Seine Formatierung ist schöner als eine Reihe von verschachtelten ifs, obwohl es funktionell näher dran ist.

  • Ich würde das wirklich bevorzugen, es verwendet ein Standard-Sprachkonstrukt und wirft keinen KeyError, wenn kein passender Fall gefunden wird

    – martyglaubitz

    18. Mai 2013 um 10:30 Uhr

  • Ich dachte an das Wörterbuch / get Weg, aber der Standardweg ist einfach besser lesbar.

    – Martin Thoma

    25. Juni 2015 um 6:33 Uhr


  • @someuser, aber die Tatsache, dass sie sich “überschneiden” können, ist eine Funktion. Sie stellen nur sicher, dass die Reihenfolge die Priorität ist, in der Übereinstimmungen auftreten sollten. Wie für wiederholtes x: mach einfach ein x = the.other.thing Vor. Normalerweise haben Sie ein einzelnes if, mehrere elif und ein einzelnes else, da dies einfacher zu verstehen ist.

    – Matthäus Schinckel

    3. März 2016 um 6:55 Uhr


  • Schön, das “Fall-through by not using elif ” ist allerdings etwas verwirrend. Was ist damit: vergiss “durchfallen” und akzeptiere es einfach als zwei if/elif/else‘s?

    – Alois Mahdal

    30. Mai 2016 um 11:40 Uhr

  • Erwähnenswert auch, wenn Dinge wie verwendet werden x in 'bc'Denk daran, dass "" in "bc" ist True.

    – Lohmar ASCHAR

    28. August 2018 um 11:46 Uhr

Python >= 3.10

Wow, Python 3.10+ hat jetzt eine match/case Syntax, die wie ist switch/case und mehr!

PEP 634 – Struktureller Musterabgleich

Ausgewählte Funktionen von match/case

1 – Spielwerte:

Das Abgleichen von Werten ähnelt einem einfachen switch/case in einer anderen Sprache:

match something:
    case 1 | 2 | 3:
        # Match 1-3.
    case _:
        # Anything else.
        # 
        # Match will throw an error if this is omitted 
        # and it doesn't match any of the other patterns.

2 – Übereinstimmungsstrukturmuster:

match something:
    case str() | bytes():  
        # Match a string like object.
    case [str(), int()]:
        # Match a `str` and an `int` sequence 
        # (`list` or a `tuple` but not a `set` or an iterator). 
    case [_, _]:
        # Match a sequence of 2 variables.
        # To prevent a common mistake, sequence patterns don’t match strings.
    case {"bandwidth": 100, "latency": 300}:
        # Match this dict. Extra keys are ignored.

3 – Variablen erfassen

Analysieren Sie ein Objekt; als Variablen speichern:

match something:
    case [name, count]
        # Match a sequence of any two objects and parse them into the two variables.
    case [x, y, *rest]:
        # Match a sequence of two or more objects, 
        # binding object #3 and on into the rest variable.
    case bytes() | str() as text:
        # Match any string like object and save it to the text variable.

Erfassungsvariablen können beim Analysieren von Daten (z. B. JSON oder HTML) nützlich sein, die in einem von mehreren verschiedenen Mustern vorliegen können.

Capture-Variablen ist eine Funktion. Aber es bedeutet auch, dass Sie gepunktete Konstanten verwenden müssen (z. B.: COLOR.RED) nur. Andernfalls wird die Konstante als Capture-Variable behandelt und überschrieben.

Mehr Beispielnutzung:

match something:
    case 0 | 1 | 2:
        # Matches 0, 1 or 2 (value).
        print("Small number")
    case [] | [_]:
        # Matches an empty or single value sequence (structure).
        # Matches lists and tuples but not sets.
        print("A short sequence")
    case str() | bytes():
        # Something of `str` or `bytes` type (data type).
        print("Something string-like")
    case _:
        # Anything not matched by the above.
        print("Something else")

Python <= 3.9

Mein Lieblings-Python-Rezept für Switch/Case war:

choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')

Kurz und einfach für einfache Szenarien.

Vergleichen Sie mit mehr als 11 Zeilen C-Code:

// C Language version of a simple 'switch/case'.
switch( key ) 
{
    case 'a' :
        result = 1;
        break;
    case 'b' :
        result = 2;
        break;
    default :
        result = -1;
}

Sie können sogar mehrere Variablen zuweisen, indem Sie Tupel verwenden:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))

  • Ich würde das wirklich bevorzugen, es verwendet ein Standard-Sprachkonstrukt und wirft keinen KeyError, wenn kein passender Fall gefunden wird

    – martyglaubitz

    18. Mai 2013 um 10:30 Uhr

  • Ich dachte an das Wörterbuch / get Weg, aber der Standardweg ist einfach besser lesbar.

    – Martin Thoma

    25. Juni 2015 um 6:33 Uhr


  • @someuser, aber die Tatsache, dass sie sich “überschneiden” können, ist eine Funktion. Sie stellen nur sicher, dass die Reihenfolge die Priorität ist, in der Übereinstimmungen auftreten sollten. Wie für wiederholtes x: mach einfach ein x = the.other.thing Vor. Normalerweise haben Sie ein einzelnes if, mehrere elif und ein einzelnes else, da dies einfacher zu verstehen ist.

    – Matthäus Schinckel

    3. März 2016 um 6:55 Uhr


  • Schön, das “Fall-through by not using elif ” ist allerdings etwas verwirrend. Was ist damit: vergiss “durchfallen” und akzeptiere es einfach als zwei if/elif/else‘s?

    – Alois Mahdal

    30. Mai 2016 um 11:40 Uhr

  • Erwähnenswert auch, wenn Dinge wie verwendet werden x in 'bc'Denk daran, dass "" in "bc" ist True.

    – Lohmar ASCHAR

    28. August 2018 um 11:46 Uhr

Benutzer-Avatar
KurzedMetal

class switch(object):
    value = None
    def __new__(class_, value):
        class_.value = value
        return True

def case(*args):
    return any((arg == switch.value for arg in args))

Verwendungszweck:

while switch(n):
    if case(0):
        print "You typed zero."
        break
    if case(1, 4, 9):
        print "n is a perfect square."
        break
    if case(2):
        print "n is an even number."
    if case(2, 3, 5, 7):
        print "n is a prime number."
        break
    if case(6, 8):
        print "n is an even number."
        break
    print "Only single-digit numbers are allowed."
    break

Tests:

n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.

  • Dies ist nicht gefahrlos. Wenn mehrere Schalter gleichzeitig gedrückt werden, nehmen alle Schalter den Wert des letzten Schalters an.

    – Francescortiz

    26. Juni 2013 um 16:35 Uhr


  • Während @francescortiz wahrscheinlich threadsicher bedeutet, ist es auch nicht bedrohungssicher. Es bedroht die Werte der Variablen!

    – Zizouz212

    16. Juni 2015 um 16:29 Uhr

  • Das Thread-Sicherheitsproblem könnte wahrscheinlich mit umgangen werden Thread-lokaler Speicher. Oder es könnte ganz vermieden werden, indem eine Instanz zurückgegeben und diese Instanz für die Fallvergleiche verwendet wird.

    – blubberdiblub

    18. September 2015 um 6:24 Uhr

  • @blubberdiblub Aber ist es dann nicht einfach effizienter, einen Standard zu verwenden? if Aussage?

    – wizzwizz4

    23. Mai 2016 um 17:32 Uhr

  • Dies ist auch nicht sicher, wenn es in mehreren Funktionen verwendet wird. In dem angegebenen Beispiel, wenn die case(2) Block rief eine andere Funktion auf, die switch() verwendet, und dann beim Ausführen case(2, 3, 5, 7) usw., um nach dem nächsten auszuführenden Fall zu suchen, wird der von der anderen Funktion festgelegte Schalterwert verwendet, nicht der von der aktuellen Schalteranweisung festgelegte.

    – Benutzer9876

    17. August 2017 um 8:58 Uhr


1159030cookie-checkErsatz für switch-Anweisung in Python?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy