Ich möchte eine Funktion in Python schreiben, die verschiedene feste Werte basierend auf dem Wert eines Eingabeindex zurückgibt.
In anderen Sprachen würde ich eine switch
oder case
-Anweisung verwenden, aber Python scheint keine switch
Anweisung zu haben . Was sind die empfohlenen Python-Lösungen in diesem Szenario?
python
switch-statement
Michael Schneider
quelle
quelle
switch
ist tatsächlich "vielseitiger" als etwas, das unterschiedliche feste Werte basierend auf dem Wert eines Eingabeindex zurückgibt. Es ermöglicht die Ausführung verschiedener Codeteile. Es muss nicht einmal einen Wert zurückgeben. Ich frage mich, ob einige der Antworten hier ein guter Ersatz für eine allgemeineswitch
Aussage sind oder nur für den Fall, dass Werte zurückgegeben werden, ohne dass die Möglichkeit besteht, allgemeine Codeteile auszuführen.Antworten:
Sie könnten ein Wörterbuch verwenden:
quelle
get
Methode wärecollections.defaultdict
in diesem Fall wahrscheinlich normaler als die Verwendung von a .}.get(x, default)
stattdessen, wenn es eine Standardeinstellung geben sollte. (Hinweis: Dies ist viel schöner als das, was passiert, wenn Sie die Standardeinstellung für eine switch-AnweisungWenn Sie Standardeinstellungen wünschen, können Sie die Wörterbuchmethode
get(key[, default])
verwenden:quelle
Ich habe es immer so gemacht
Von hier
quelle
.get()
(wie die derzeit höchsten Antworten) verwenden, müssen alle Möglichkeiten vor dem Versand sorgfältig prüfen und sind daher nicht nur (nicht nur sehr, sondern) äußerst ineffizient und können auch keine Nebenwirkungen haben. Diese Antwort umgeht dieses Problem, ist jedoch ausführlicher. Ich würde nur if / elif / else verwenden, und selbst diese brauchen genauso lange zum Schreiben wie 'case'.[value]
, wodurch nur eine der 3 Funktionen zurückgegeben wird (vorausgesetzt, esvalue
handelt sich um eine der 3 Tasten). Die Funktion wurde zu diesem Zeitpunkt noch nicht aufgerufen. Dann(x)
ruft die gerade zurück Funktion mitx
als Argument (und das Ergebnis geht anresult
). Die anderen 2 Funktionen werden nicht aufgerufen.Zusätzlich zu den Wörterbuchmethoden (die mir übrigens sehr gut gefallen) können Sie auch
if
-elif
- verwendenelse
, um dieswitch
/case
/default
-Funktionalität zu erhalten:Dies ist natürlich nicht identisch mit switch / case - Sie können nicht so leicht durchfallen wie das Weglassen der
break
Anweisung, aber Sie können einen komplizierteren Test durchführen. Die Formatierung ist besser als bei einer Reihe verschachtelterif
s, obwohl dies funktional eher der Fall ist.quelle
get
Weg nachgedacht , aber der Standardweg ist einfach besser lesbar.x = the.other.thing
vorher. Normalerweise haben Sie ein einzelnes if, mehrere elif und ein einzelnes else, da dies leichter zu verstehen ist.if/elif/else
?x in 'bc'
, bedenken Sie, dass"" in "bc"
istTrue
.Mein Lieblingsrezept für Python für Schalter / Fall ist:
Kurz und einfach für einfache Szenarien.
Vergleichen Sie mit mehr als 11 Zeilen C-Code:
Sie können sogar mehrere Variablen mithilfe von Tupeln zuweisen:
quelle
default = -1; result = choices.get(key, default)
.result=key=='a'?1:key==b?2:-1
result = 1 if key == 'a' else (2 if key == 'b' else 'default')
. Aber ist der eine Liner lesbar?Verwendungszweck:
Tests:
quelle
if
?case(2)
Block im angegebenen Beispiel eine andere Funktion aufruft, die switch () verwendet, wird beicase(2, 3, 5, 7)
der Suche nach dem nächsten auszuführenden Fall usw. der von der anderen Funktion festgelegte Schalterwert verwendet, nicht der von der aktuellen switch-Anweisung festgelegte .Mein Lieblingsrezept ist ein wirklich schönes Rezept . Du wirst es wirklich mögen. Es ist das, was ich den tatsächlichen Switch-Case-Anweisungen am nächsten gesehen habe, insbesondere in Bezug auf Funktionen.
Hier ist ein Beispiel:
quelle
for case in switch()
mitwith switch() as case
mehr Sinn macht, da es s nur einmal ausgeführt werden .with
jedoch nicht möglich istbreak
, sodass die Fallthrough-Option wegfällt.if c in set(range(0,9)): print "digit" elif c in set(map(chr, range(ord('a'), ord('z')))): print "lowercase"
?quelle
value
, der Switch-Klasse eine (öffentliche) Eigenschaft hinzuzufügen, damit Sie auf die Eigenschaftcase.value
innerhalb der Anweisung verweisen können .Es gibt ein Muster, das ich aus Twisted Python-Code gelernt habe.
Sie können es jederzeit verwenden, wenn Sie ein Token versenden und erweiterten Code ausführen müssen. In einer Zustandsmaschine hätten Sie
state_
Methoden und würden versendenself.state
. Dieser Schalter kann sauber erweitert werden, indem Sie von der Basisklasse erben und Ihre eigenendo_
Methoden definieren. Oft haben Sie nicht einmaldo_
Methoden in der Basisklasse.Bearbeiten: wie genau wird das verwendet
Im Falle von SMTP erhalten Sie
HELO
von der Leitung. Der relevante Code (vontwisted/mail/smtp.py
, geändert für unseren Fall) sieht folgendermaßen ausSie erhalten
' HELO foo.bar.com '
(oder Sie erhalten'QUIT'
oder'RCPT TO: foo'
). Dies wird inparts
as tokenisiert['HELO', 'foo.bar.com']
. Der tatsächliche Name der Methodensuche wird übernommenparts[0]
.(Die ursprüngliche Methode wird auch aufgerufen
state_COMMAND
, da sie dasselbe Muster zum Implementieren einer Zustandsmaschine verwendet, dhgetattr(self, 'state_' + self.mode)
)quelle
Angenommen, Sie möchten nicht nur einen Wert zurückgeben, sondern Methoden verwenden, die etwas an einem Objekt ändern. Die Verwendung des hier angegebenen Ansatzes wäre:
Was hier passiert ist, dass Python alle Methoden im Wörterbuch auswertet. Selbst wenn Ihr Wert 'a' ist, wird das Objekt um x inkrementiert und dekrementiert.
Lösung:
Sie erhalten also eine Liste mit einer Funktion und ihren Argumenten. Auf diese Weise werden nur der Funktionszeiger und die Argumentliste zurückgegeben und nicht ausgewertet. 'result' wertet dann den zurückgegebenen Funktionsaufruf aus.
quelle
Ich werde nur meine zwei Cent hier reinwerfen. Der Grund, warum es in Python keine case / switch-Anweisung gibt, ist, dass Python dem Prinzip "Es gibt nur einen richtigen Weg, etwas zu tun" folgt. Natürlich könnten Sie verschiedene Möglichkeiten finden, um die Switch / Case-Funktionalität wiederherzustellen, aber die pythonische Methode, um dies zu erreichen, ist das if / elif-Konstrukt. dh
Ich hatte gerade das Gefühl, dass PEP 8 hier ein Nicken verdient hat. Eines der schönen Dinge an Python ist seine Einfachheit und Eleganz. Dies ist größtenteils auf die in PEP 8 festgelegten Grundsätze zurückzuführen, darunter "Es gibt nur einen richtigen Weg, etwas zu tun".
quelle
Erweiterung der Idee "Diktieren als Schalter". Wenn Sie einen Standardwert für Ihren Switch verwenden möchten:
quelle
'default'
) von der Regel (erhalten Sie etwas von diesem Diktat). Von Natur aus verwenden Python-Programme Ausnahmen im Handumdrehen. Abgesehen davonget
könnte die Verwendung den Code möglicherweise ein bisschen schöner machen.Wenn Sie einen komplizierten Fallblock haben, können Sie eine Nachschlagetabelle für Funktionswörterbücher verwenden ...
Wenn Sie dies noch nicht getan haben, empfiehlt es sich, in Ihren Debugger einzusteigen und genau anzuzeigen, wie das Wörterbuch die einzelnen Funktionen nachschlägt.
HINWEIS: Verwenden Sie nicht "()" in der Fall- / Wörterbuchsuche, da sonst jede Ihrer Funktionen aufgerufen wird, wenn der Wörterbuch- / Fallblock erstellt wird. Denken Sie daran, da Sie jede Funktion nur einmal mit einer Hash-Suche aufrufen möchten.
quelle
Wenn Sie nach einer zusätzlichen Anweisung als "Schalter" suchen, habe ich ein Python-Modul erstellt, das Python erweitert. Es heißt ESPY als "Enhanced Structure for Python" und ist sowohl für Python 2.x als auch für Python 3.x verfügbar.
In diesem Fall könnte eine switch-Anweisung beispielsweise mit dem folgenden Code ausgeführt werden:
das kann so verwendet werden:
so espy übersetzen Sie es in Python als:
quelle
while True:
der generierte Python-Code oben? Es wird getroffen zwangsläufig diebreak
am unteren Rande des erzeugten Python - Code, so scheint es mir , dass sowohl diewhile True:
undbreak
entfernt werden kann.cont
Ist ESPY außerdem intelligent genug, um den Namen zu ändern, wenn der Benutzer denselben Namen in seinem eigenen Code verwendet? Auf jeden Fall möchte ich Vanille-Python verwenden, damit ich dies nicht verwende, aber es ist trotzdem cool. +1 für pure Coolness.while True:
undbreak
s ist, Fall-Through zuzulassen, aber nicht zu erfordern.Ich fand, dass eine gemeinsame Schalterstruktur:
kann in Python wie folgt ausgedrückt werden:
oder klarer formatiert:
Anstatt eine Anweisung zu sein, ist die Python-Version ein Ausdruck, der einen Wert ergibt.
quelle
parameter
undp1==parameter
f = lambda x: 'a' if x==0 else 'b' if x==1 else 'c'
. Als ich später anrieff(2)
, bekam ich'c'
;f(1)
,'b'
; undf(0)
,'a'
. P1 (x) bezeichnet ein Prädikat; Solange es zurückkehrtTrue
oderFalse
, egal ob es sich um einen Funktionsaufruf oder einen Ausdruck handelt, ist es in Ordnung.Die meisten Antworten hier sind ziemlich alt und besonders die akzeptierten, daher scheint es eine Aktualisierung wert zu sein.
Zunächst wird dies in den offiziellen Python-FAQ behandelt und die
elif
Kette für einfache Fälle und diedict
für größere oder komplexere Fälle empfohlen . Invisit_
einigen Fällen wird auch eine Reihe von Methoden vorgeschlagen (ein Stil, der von vielen Server-Frameworks verwendet wird):In den häufig gestellten Fragen wird auch PEP 275 erwähnt , das geschrieben wurde, um eine endgültige endgültige Entscheidung über das Hinzufügen von Switch-Anweisungen im C-Stil zu erhalten. Dieses PEP wurde jedoch tatsächlich auf Python 3 verschoben und nur als separater Vorschlag, PEP 3103, offiziell abgelehnt . Die Antwort war natürlich nein - aber die beiden PEPs haben Links zu zusätzlichen Informationen, wenn Sie an den Gründen oder der Geschichte interessiert sind.
Eine Sache, die mehrmals auftauchte (und in PEP 275 zu sehen ist, obwohl sie als tatsächliche Empfehlung herausgeschnitten wurde), ist, dass Sie wirklich die Mühe haben, 8 Codezeilen für 4 Fälle zu haben, im Vergleich zu den 6 Zeilen, die Sie in C oder Bash haben würden, können Sie immer schreiben:
Dies wird von PEP 8 nicht gerade unterstützt, ist aber lesbar und nicht zu unidiomatisch.
In den mehr als einem Jahrzehnt seit der Ablehnung von PEP 3103 wurde das Problem der C-artigen Fallaussagen oder sogar der etwas leistungsfähigeren Version in Go als tot angesehen. Immer wenn jemand Python-Ideen oder -dev anspricht, wird er auf die alte Entscheidung verwiesen.
Die Idee eines vollständigen Mustervergleichs im ML-Stil entsteht jedoch alle paar Jahre, zumal Sprachen wie Swift und Rust ihn übernommen haben. Das Problem ist, dass es ohne algebraische Datentypen schwierig ist, den Mustervergleich optimal zu nutzen. Während Guido mit der Idee einverstanden war, hat niemand einen Vorschlag gemacht, der sehr gut in Python passt. (Sie können meinen Strohmann von 2014 als Beispiel lesen .) Dies könnte sich mit
dataclass
in 3.7 und einigen sporadischen Vorschlägen für eine leistungsfähigereenum
Handhabung von Summentypen oder mit verschiedenen Vorschlägen für verschiedene Arten von aussagelokalen Bindungen (wie PEP 3150 oder die Reihe von Vorschlägen, die derzeit auf -ideas diskutiert werden). Aber bisher hat es nicht.Gelegentlich gibt es auch Vorschläge für ein Perl 6-Matching, das im Grunde genommen eine Mischung aus allem ist, von
elif
Regex bis hin zu Single-Dispatch-Typ-Switching.quelle
Lösung zum Ausführen von Funktionen:
Dabei sind foo1 (), foo2 (), foo3 () und default () Funktionen
quelle
foo2()
, diefoo1()
,foo3()
unddefault()
Funktionen sind alle auch laufen gehen, Dinge bedeuten eine lange Zeit in Anspruch nehmen könnteget(option)()
. Problem gelöst.Ich habe die einfache Antwort, nach der ich gesucht habe, in der Google-Suche nicht gefunden. Aber ich habe es trotzdem herausgefunden. Es ist wirklich ganz einfach. Beschlossen, es zu posten und vielleicht ein paar weniger Kratzer auf dem Kopf eines anderen zu verhindern. Der Schlüssel ist einfach "in" und Tupel. Hier ist das Verhalten der switch-Anweisung mit Fall-Through, einschließlich RANDOM-Fall-Through.
Bietet:
quelle
break
am Ende des Codes für a zu schreibencase
. Aber ich denke, wir brauchen keinen solchen "Fallthrough" :)Die Lösungen, die ich benutze:
Eine Kombination aus zwei der hier veröffentlichten Lösungen, die relativ einfach zu lesen ist und Standardeinstellungen unterstützt.
wo
schaut
"lambda x: x - 2"
im Diktat nach und benutzt es mitx=23
findet es nicht im Diktat und verwendet die Standardeinstellung
"lambda x: x - 22"
mitx=44
.quelle
quelle
quelle
Ich mochte Mark Bies 'Antwort
Da die
x
Variable zweimal verwendet werden muss, habe ich die Lambda-Funktionen auf parameterlos geändert.Ich muss mit rennen
results[value](value)
Bearbeiten: Mir ist aufgefallen, dass ich
None
mit Wörterbüchern schreiben kann. Das würde also nachahmenswitch ; case else
quelle
result[None]()
?result = {'a': 100, None:5000}; result[None]
None:
verhältdefault:
.Kurz und einfach zu lesen, hat einen Standardwert und unterstützt Ausdrücke sowohl in Bedingungen als auch in Rückgabewerten.
Es ist jedoch weniger effizient als die Lösung mit einem Wörterbuch. Beispielsweise muss Python alle Bedingungen durchsuchen, bevor der Standardwert zurückgegeben wird.
quelle
Sie können ein versendetes Diktat verwenden:
Ausgabe:
quelle
Einfach, nicht getestet; Jede Bedingung wird unabhängig ausgewertet: Es gibt keinen Durchfall, aber alle Fälle werden ausgewertet (obwohl der einzuschaltende Ausdruck nur einmal ausgewertet wird), es sei denn, es gibt eine break-Anweisung. Zum Beispiel,
Drucke
Was 1. Was 1 or 2. Was something.
(Verdammt! Warum kann ich in Inline-Codeblöcken kein nachfolgendes Leerzeichen haben?), wennexpression
ausgewertet wird1
,Was 2.
wennexpression
ausgewertet2
wird oderWas something.
wennexpression
ausgewertet wird.quelle
Definieren:
ermöglicht es Ihnen, eine ziemlich einfache Syntax zu verwenden, wobei die Fälle in einer Karte gebündelt sind:
Ich versuchte immer wieder, den Schalter so neu zu definieren, dass ich das "Lambda:" loswerden konnte, gab aber auf. Definition optimieren:
Erlaubte mir, mehrere Fälle demselben Code zuzuordnen und eine Standardoption anzugeben:
Jeder replizierte Fall muss sich in einem eigenen Wörterbuch befinden. switch () konsolidiert die Wörterbücher, bevor der Wert nachgeschlagen wird. Es ist immer noch hässlicher als ich es gerne hätte, aber es hat die grundlegende Effizienz, eine Hash-Suche für den Ausdruck zu verwenden, anstatt eine Schleife durch alle Schlüssel.
quelle
Ich denke, der beste Weg ist, die Python-Sprachsprache zu verwenden, um Ihren Code testbar zu halten . Wie in früheren Antworten gezeigt, verwende ich Wörterbücher, um Python-Strukturen und -Sprache zu nutzen und den "Fall" -Code auf verschiedene Arten isoliert zu halten. Unten gibt es eine Klasse, aber Sie können direkt ein Modul, Globals und Funktionen verwenden. Die Klasse verfügt über Methoden, die isoliert getestet werden können . Abhängig von Ihren Anforderungen können Sie auch mit statischen Methoden und Attributen spielen.
Es ist möglich, diese Methode zu nutzen, indem auch Klassen als Schlüssel von "__choice_table" verwendet werden. Auf diese Weise können Sie den Missbrauch von Instanzen vermeiden und alles sauber und testbar halten.
Angenommen, Sie müssen viele Nachrichten oder Pakete aus dem Netz oder Ihrem MQ verarbeiten. Jedes Paket hat seine eigene Struktur und seinen Verwaltungscode (generisch). Mit dem obigen Code ist es möglich, Folgendes zu tun:
Die Komplexität verteilt sich also nicht auf den Codefluss, sondern wird in der Codestruktur gerendert .
quelle
Erweiterung der Antwort von Greg Hewgill - Wir können die Wörterbuchlösung mit einem Dekorateur kapseln:
Dies kann dann mit dem
@case
-decorator verwendet werdenDie gute Nachricht ist, dass dies bereits im NeoPySwitch- Modul geschehen ist . Einfach mit pip installieren:
quelle
Eine Lösung, die ich tendenziell benutze und die auch Wörterbücher verwendet, ist:
Dies hat den Vorteil, dass nicht jedes Mal versucht wird, die Funktionen zu bewerten, und Sie müssen nur sicherstellen, dass die äußere Funktion alle Informationen erhält, die die inneren Funktionen benötigen.
quelle
Bisher gab es viele Antworten, die besagten: "Wir haben keinen Schalter in Python, machen Sie es so." Ich möchte jedoch darauf hinweisen, dass die switch-Anweisung selbst ein leicht zu missbrauchendes Konstrukt ist, das in den meisten Fällen vermieden werden kann und sollte, da sie eine verzögerte Programmierung fördert. Ein typisches Beispiel:
Jetzt könnten Sie dies mit einer switch-Anweisung tun (wenn Python eine anbietet), aber Sie würden Ihre Zeit verschwenden, weil es Methoden gibt, die dies gut tun. Oder vielleicht haben Sie etwas weniger Offensichtliches:
Diese Art von Vorgang kann und sollte jedoch mit einem Wörterbuch ausgeführt werden, da es schneller, weniger komplex, weniger fehleranfällig und kompakter ist.
Und die überwiegende Mehrheit der "Anwendungsfälle" für switch-Anweisungen fällt in einen dieser beiden Fälle. Es gibt nur einen sehr geringen Grund, einen zu verwenden, wenn Sie gründlich über Ihr Problem nachgedacht haben.
Anstatt zu fragen, wie ich in Python wechseln soll, sollten wir uns vielleicht fragen, warum ich in Python wechseln möchte. weil das oft die interessantere Frage ist und oft Fehler in der Gestaltung von allem aufdeckt, was Sie bauen.
Das heißt nicht, dass Schalter auch niemals verwendet werden sollten. Zustandsautomaten, Lexer, Parser und Automaten verwenden sie bis zu einem gewissen Grad. Wenn Sie von einer symmetrischen Eingabe ausgehen und zu einer asymmetrischen Ausgabe wechseln, können sie im Allgemeinen nützlich sein. Sie müssen nur sicherstellen, dass Sie den Schalter nicht als Hammer verwenden, da Sie in Ihrem Code ein paar Nägel sehen.
quelle