1717 Stimmen

Ersetzungen für switch-Anweisung in Python?

Ich möchte eine Funktion in Python schreiben, die je nach dem Wert eines Eingabeindexes verschiedene feste Werte zurückgibt.

In anderen Sprachen würde ich ein switch o case Anweisung, aber Python scheint nicht über eine switch Aussage. Was sind die empfohlenen Python-Lösungen in diesem Szenario?

77 Stimmen

PEP zum Thema, verfasst von Guido selbst: PEP 3103

28 Stimmen

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

15 Stimmen

Was bei allen Lösungen fehlt, ist die Erkennung von doppelte Fallwerte . Als Fail-Fast-Prinzip kann dies ein größerer Verlust sein als die Leistung oder die Fallthrough-Funktion.

2197voto

Greg Hewgill Punkte 882617

Die unten stehende Originalantwort wurde 2008 verfasst. Seitdem wurde mit Python 3.10 (2021) die match - case Anweisung, die eine erstklassige Implementierung eines "Schalters" für Python bietet. Zum Beispiel:

def f(x):
    match x:
        case 'a':
            return 1
        case 'b':
            return 2
        case _:        
            return 0   # 0 is the default case if x is not found

El match - case Anweisung ist wesentlich leistungsfähiger als dieses einfache Beispiel.


Sie könnten ein Wörterbuch benutzen:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]

138 Stimmen

Was geschieht, wenn x nicht gefunden wird?

65 Stimmen

@nick: Sie können defaultdict verwenden

458 Stimmen

Ich würde empfehlen, das Diktat außerhalb der Funktion zu platzieren, wenn die Leistung ein Problem ist, damit das Diktat nicht bei jedem Funktionsaufruf neu erstellt wird

1592voto

Nick Punkte 26768

Wenn Sie Standardwerte wünschen, können Sie das Wörterbuch 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

13 Stimmen

Was ist, wenn "a" und "b" mit 1 übereinstimmen und "c" und "d" mit 2?

14 Stimmen

@JM: Offensichtlich unterstützen Dictionary Lookups keine Fall-Throughs. Sie könnten eine doppelte Wörterbuchsuche durchführen. D.h. 'a' & 'b' zeigen auf Antwort1 und 'c' und 'd' zeigen auf Antwort2, die in einem zweiten Wörterbuch enthalten sind.

3 Stimmen

Es ist besser, einen Standardwert zu übergeben

489voto

Mark Biek Punkte 140395

Ich habe es immer gerne so gemacht

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}[value](x)

Von hier aus

7 Stimmen

Er fragt nach festen Werten. Warum sollte man eine Funktion erstellen, um etwas zu berechnen, wenn es sich um eine Nachschlagefunktion handelt? Interessante Lösung für andere Probleme aber.

39 Stimmen

Ist es vielleicht keine gute Idee, Lambda in diesem Fall zu verwenden, weil Lambda tatsächlich jedes Mal aufgerufen wird, wenn das Wörterbuch erstellt wird.

16 Stimmen

Leider ist dies das, was die Menschen am ehesten bekommen werden. Methoden, die .get() (wie die aktuellen höchsten Antworten) müssen eifrig alle Möglichkeiten auswerten, bevor sie versendet werden, und sind daher nicht nur (nicht nur sehr, sondern) extrem ineffizient und können auch keine Nebeneffekte haben; diese Antwort umgeht dieses Problem, ist aber ausführlicher. Ich würde nur if/elif/else verwenden, und selbst die brauchen genauso lange zum Schreiben wie 'case'.

463voto

Matthew Schinckel Punkte 33617

Zusätzlich zu den Wörterbuchmethoden (die ich übrigens sehr mag), können Sie auch if - elif - else um die 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 Schalter/Gehäuse - man kann nicht so einfach durchfallen, wie wenn man die break Anweisung, aber Sie können auch einen komplizierteren Test durchführen. Seine Formatierung ist schöner als eine Reihe von verschachtelten if s, auch wenn es funktionell gesehen eher dem entspricht.

81 Stimmen

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

9 Stimmen

Ich dachte an das Wörterbuch / get aber die Standardform ist einfach besser lesbar.

0 Stimmen

Sie funktioniert nicht genau wie eine Schalteranweisung, aber sehr ähnlich. Meiner Meinung nach kommt es dem am nächsten

387voto

ChaimG Punkte 5736

Python >= 3.10

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

PEP 634 -- Struktureller Musterabgleich

Ausgewählte Merkmale von match/case

1 - Werte abgleichen:

Der Abgleich von Werten ist ähnlich wie eine einfache 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 - Strukturelle Muster anpassen:

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 - Erfassen von Variablen

Parsen eines Objekts; Speichern als Variablen:

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.

Capture-Variablen können beim Parsen von Daten (z. B. JSON oder HTML) nützlich sein, die in einem von vielen verschiedenen Mustern vorliegen können.

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

Weitere Verwendungsbeispiele :

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 bevorzugtes Python-Rezept für Switch/Case war:

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

Kurz und einfach für einfache Szenarien.

Im Vergleich zu 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'))

38 Stimmen

Ich halte dies für eine solidere Antwort als die akzeptierte.

1 Stimmen

Beachten Sie, dass die beiden Codesegmente nicht identisch sind. Die Python-Version gibt "default" zurück, wenn es keine Übereinstimmung gibt, aber die C-Version gibt -1 zurück. Wenn Sie die Zeile als choices.get(key, -1) wird es schwieriger zu lesen, weil man innehalten muss, um zu überlegen, wie get() funktioniert und was -1 bedeuten.

4 Stimmen

@some user: C verlangt, dass der Rückgabewert in allen Fällen vom gleichen Typ ist. Python tut das nicht. Ich wollte diese Flexibilität von Python nur für den Fall hervorheben, dass jemand eine Situation hat, die eine solche Verwendung rechtfertigt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X