Remplacements pour instruction switch en Python?
Je veux écrire une fonction Python qui retourne différentes valeurs fixes basés sur la valeur d'une entrée d'index.
Dans d'autres langues, je voudrais utiliser une switch
ou case
déclaration, mais Python ne semble pas avoir un switch
déclaration. Ce sont recommandés en Python solutions dans ce scénario?
- Liés à la PPE, écrit par Guido lui-même: PEP 3103
- Dans ce PEP, Guido ne pas mentionner que si/elif chaînes sont également une source classique de l'erreur. C'est un très fragiles construire.
- Absent de toutes les solutions ici est la détection de dupliquer le cas des valeurs. L'échec rapide de principe, c'est peut être une plus importante perte de rendement ou de la fallthrough fonctionnalité.
- Toutes les solutions apportées sont vraiment laid... switch cas est si propre, lorsque la lecture. Ne peut pas comprendre pourquoi il n'est pas implémenté en Python.
switch
est en fait plus "polyvalent" que quelque chose de retour différentes valeurs fixes basés sur la valeur d'une entrée d'index. Elle permet différents morceaux de code à exécuter. Il ne fait même pas besoin de retourner une valeur. Je me demande si certaines des réponses ici sont de bons remplaçants pour un généralswitch
déclaration, ou seulement pour le cas de renvoi de valeurs, sans aucune possibilité de l'exécution générale des morceaux de code.- d'accord. Si vous n'êtes pas de retour ou de la rupture de votre
switch
case
énoncé de l'ensemble du code dans les autres cas seront exécutées. C'est clairement pas la même que d'une collection de si/elseifs - Fragile construire, comme une boucle while est un fragile de construire si vous essayez de l'utiliser pour faire ce for...in... ne. Allez-vous appeler les programmeurs faible pour l'utilisation des boucles for? Tandis que les boucles sont tout ce qu'ils ont réellement besoin. Mais pour les boucles de montrer l'intention claire de sauver inutile standard et de donner la possibilité de créer des abstractions.
- De la même manière, la syntaxe comme le Rubis est le cas...quand... (ou Scala match, Haskell cas, Perl donné/quand) répondre à une commune de cas d'utilisation et offre un puissant abstraction. if...elif... est un pauvre substitut.
- Je n'ai pas assez sur Haskell ou Ruby, et rien du tout à propos de Perl et de la Scala, de sorte que nous devons arrêter ce débat pour l'instant, mais je ne peux pas aider mais se sentir comme ce est l'opinion plus que de la réalité. Pourrait être amusant et intéressant. Des acclamations.
- Python aphorisme que "explicite est mieux qu'implicite" est ce que l'on fait tomber dans Python non-standard. Je ne sais pas si je dois être triste ou heureux 😐
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser un dictionnaire:
get
méthode serait sans doute plus normal que d'utiliser uncollections.defaultdict
dans ce cas.}.get(x, default)
au lieu de cela, si il devrait y avoir un défaut. (Note: c'est beaucoup plus agréable que ce qui se passe si vous laissez la valeur par défaut off d'une instruction switch!)print
instruction dans le dictionnaire. ideone.com/aL9EUEprint
(parce queprint
a des effets secondaires, et l'ensemble du dictionnaire est évalué lorsqu'il est construit).someDict.getitem(x)
, ou mieux encore,someDict[x]
def f(x, *, _lookup={'a': 1, 'b': 2}): return _lookup.get(x, 3)
. Le*
sans nom signifie que les arguments après ce point ne peut être transmis que par son nom, afin de l'appelantf(1, {})
ne silencieusement en mal. Un utilisateur peut fairef(1, _lookup={})
, mais c'est de leur faute. Souligner les préfixes signifie généralement "usage interne seulement", et nous sommes tous des adultes ici; s'ils veulent ignorer cette règle, c'est leur prérogative.dict
méthodes directement, par exemple, sans défaut,f = {'a': 1, 'b': 2}.__getitem__
, ou avec une valeur par défaut,f = collections.defaultdict(lambda: 3, {'a': 1, 'b': 2}).__getitem__
(même si ce dernier va stocker auto-vivifiée paires clé/valeur, donc une fonction wrapper de sens ici, à éviter).Si vous souhaitez par défaut, vous pouvez utiliser le dictionnaire
get(key [par défaut])
méthode:J'ai toujours aimé cette façon de
À partir d'ici
.get()
(comme la meilleure des réponses) devra avec impatience évaluer toutes les possibilités avant de les envoyer, et, par conséquent, ne sont pas seulement (et pas seulement de très mais extrêmement inefficace et ne peut également avoir des effets secondaires; cette réponse permet de contourner le problème, mais est plus verbeux. Je voudrais juste utiliser if/elif/else, et même ceux de prendre autant de temps pour écrire en tant que "cas".[value]
, qui sera de retour une seule des 3 fonctions (en supposant quevalue
est l'une des 3 touches). La fonction n'a pas été appelée à ce point, encore. Puis(x)
appelle la tout juste de retour de la fonction avecx
comme argument (et le résultat va àresult
). Les 2 autres fonctions ne sera pas appelé.get
forces de n'importe quel dictionnaire pour évaluer toutes les valeurs ne sont pas.get
cherche la clé - qui est un O(1) résultat et puis si la clé n'existe pas sera ensuite de retour à la valeur par défaut - c'est pas pire que : si la clé dans le dict: retour dict[key] else: return par défaut{True:f(), False:g()}[x]
(O(f+g)) au lieu def() if x else g()
(O(max(f,g))). La seule grâce est l'OP demande pour des valeurs fixes, mais cela prouve on ne peut pas remplacer une instruction switch avec un{...}
/.get
sans lambda si l'on se soucie asymptotique. De la cours d'appel de fonction, les frais généraux est mauvais aussi.En plus du dictionnaire des méthodes (que j'aime vraiment, d'ailleurs), vous pouvez également utiliser si-elif-d'autre pour obtenir le commutateur/cas/fonctionnalité par défaut:
Ce n'est évidemment pas identique à switch/case - vous ne pouvez pas avoir de chute à travers aussi facilement qu'en laissant au large de la rupture, la déclaration, mais vous pouvez avoir un plus compliqué de test. Sa mise en forme est plus agréable que d'une série de imbriquée fi, même si fonctionnellement c'est ce qu'elle est plus proche.
get
, mais le standard est simplement plus lisible.switch
a unbreak
et l'utilisation la plus courante pour l'automne-à travers ce que je vois, c'est pour correspondre à de multiples éléments, comme dansif x in 'bc':
.==
etin
, les conditions pourraient se chevauchent et que devient difficile à lire.x = the.other.thing
avant. Généralement, vous auriez un seul cas, plusieurs elif et une seule autre personne, comme c'est plus facile à comprendre.if/elif/else
. Mais la plupart de ceux qui visitent cette rubrique ne le font pas. Nous voulons plus de code structurel. Toute langue qui prend en chargeswitch
prend déjà en chargeif/elif/else
.if/elif/else
's?x in 'bc'
, gardez à l'esprit que"" in "bc"
estTrue
.if/elif
est le plus clair.Mon préféré Python recette pour switch/case est:
Court et simple pour les scénarios simples.
Comparer aux 11+ lignes de code C:
Vous pouvez même affecter plusieurs variables en utilisant des n-uplets:
choices.get(key, -1)
, il devient plus difficile à lire parce que les gens ont à réfléchir comment get() qui fonctionne et ce qui-1
veux dire.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')
. mais qui est l'un liner lisible?Utilisation:
Tests:
if
déclaration?case=switch( foo )
si est plus efficace que le dessus (ou voulez-vous dire moins de frappe)if
va être plus rapide.case(2)
bloc d'appeler une autre fonction qui utilise switch(), puis lorsque vous faitescase(2, 3, 5, 7)
etc regarder pour le cas suivant à exécuter, il va utiliser le commutateur de valeur définie par l'autre fonction n'est pas celle définie par l'actuelle instruction switch.switch
? Leswitch.value
sera écrasé, conduisant à des ruptures de manipulation ultérieure en cas! Il y a une bien meilleure mise en œuvre de cette approche ci-dessous, et les gens devraient downvote cette réponse, et upvote que l'on.Il y a un modèle que j'ai appris à partir d'Tordu de code Python.
Vous pouvez l'utiliser à tout moment vous avez besoin pour l'expédition sur un jeton et exécuter étendu morceau de code. Dans une machine d'état, vous auriez
state_
méthodes, et l'envoi surself.state
. Ce commutateur peut être proprement étendu en héritant de la classe de base et de définir votre propredo_
méthodes. La plupart du temps vous n'aurez même pasdo_
méthodes dans la classe de base.Edit: comment est exactement celui utilisé
En cas de SMTP vous recevrez
HELO
du fil. Le code (à partir detwisted/mail/smtp.py
, modifié pour notre cas) ressemble à ceciVous recevrez
' HELO foo.bar.com '
(ou vous pourriez obtenir'QUIT'
ou'RCPT TO: foo'
). C'est segmenté enparts
comme['HELO', 'foo.bar.com']
. La méthode de recherche de nom est tiré departs[0]
.(L'original de la méthode est également appelée
state_COMMAND
, car il utilise le même schéma de mettre en œuvre une machine d'état, c'est à diregetattr(self, 'state_' + self.mode)
)dict
. Pas besoin pour cela de fantaisiegetattr
non-sens.Mon préféré est un très beau recette. Vous allez vraiment vous l'aimez. C'est le plus proche de celui que j'ai vu de changement réel de cas relevés, en particulier dans les caractéristiques.
Voici un exemple:
for case in switch()
avecwith switch() as case
, plus de sens, car il faut s pour exécuter qu'une seule fois.with
ne permet pas debreak
bien que, de sorte que le fallthrough option est enlevé.if c in set(range(0,9)): print "digit" elif c in set(map(chr, range(ord('a'), ord('z')))): print "lowercase"
?value
propriété de l'Interrupteur de la classe, de sorte que vous pouvez faire référence à lacase.value
dans la déclaration.Disons que vous ne voulez pas de simplement renvoyer une valeur, mais vous voulez utiliser les méthodes qui changent quelque chose sur un objet. L'utilisation de l'approche indiqué ici:
Ce qui se passe ici est que python évalue toutes les méthodes dans le dictionnaire.
Donc, même si votre valeur est 'a', l'objet sera incrémentée et décrémenté par x.
Solution:
De sorte que vous obtenez une liste contenant une fonction et ses arguments. De cette façon, seul le pointeur de fonction et la liste des arguments sont retournées, pas évalué. 'résultat' évalue ensuite le retour de l'appel de fonction.
Je vais laisser tomber mon grain de sel ici. La raison il n'y a pas de cas/instruction switch en Python est parce que Python suit le principe de "il n'existe qu'une seule bonne façon de faire quelque chose". Alors, évidemment, vous pourriez en venir avec différentes façons de recréer switch/case fonctionnalité, mais le Pythonic façon d'accomplir ceci est le if/elif construire. ie
J'ai juste senti la PEP 8 mérité un clin d'œil ici. Une des belles choses au sujet de Python est sa simplicité et son élégance. C'est en grande partie dérivées de principes inscrits dans notre PEP 8, y compris "Il n'y a qu'une seule bonne façon de faire quelque chose"
expansion sur le "dict que de passer" de l'idée. si vous souhaitez utiliser une valeur par défaut pour votre switch:
'default'
) de la règle (obtenir quelque chose à partir de ce dict). De par sa conception, Python programmes de l'utilisation des exceptions à la baisse d'un chapeau. Cela étant dit, à l'aide deget
pourrait potentiellement rendre le code un peu plus agréable.Si vous avez un cas compliqué bloc vous pouvez envisager d'utiliser une fonction de recherche dans le dictionnaire de la table...
Si vous n'avez pas fait cela avant son une bonne idée de faire un pas dans votre débogueur et de voir exactement comment le dictionnaire regarde chaque fonction.
REMARQUE: Ne pas utilisation "()" à l'intérieur du boîtier/recherche dans le dictionnaire ou il va appeler chacun de vos fonctions, dictionnaire de cas et de bloc est créé. Rappelez-vous ce parce que vous voulez l'appeler chaque fonction une fois à l'aide d'un hachage de recherche de style.
Si vous êtes à la recherche extra-déclaration, comme "switch", j'ai construit un module python qui s'étend Python. Il est appelé ESPY que "le renforcement de la Structure pour Python" et il est disponible pour Python 2.x et Python 3.x.
Par exemple, dans ce cas, une instruction de commutation peut être effectuée par le code suivant:
qui peut être utilisée comme ceci:
donc espy traduire en Python comme:
while True:
en haut de l'généré le code Python? Il va inévitablement frappé lebreak
au bas de l'généré le code Python, il me semble donc que les deuxwhile True:
etbreak
pourrait être supprimé. De plus, est ESPY assez intelligent pour changer le nom decont
si l'utilisateur utilise le même nom dans leur propre code? En tout cas, je veux utiliser de la vanille en Python donc je ne vais pas l'utiliser, mais c'est cool aucun-le-moins. +1 pour la fraîcheur pure.while True:
etbreak
s est de permettre, mais nécessitent pas de tomber à travers.Je n'ai pas trouver la réponse la plus simple que je cherchais n'importe où sur la recherche Google. Mais j'ai tout compris de toute façon. C'est vraiment très simple. Décidé de le poster, et peut-être éviter quelques rayures sur quelqu'un d'autre de sa tête. La clé est tout simplement "en" et des n-uplets. Voici l'instruction switch comportement à l'automne-à travers, y compris au HASARD tomber à travers.
Offre:
break
à la fin du code pour uncase
. Mais je pense que nous n'avons pas besoin de tel "fallthrough" 🙂J'ai trouvé qu'une commune de l'interrupteur de la structure:
peut être exprimé en Python comme suit:
ou la mise en forme d'une façon plus claire:
Au lieu d'être une déclaration, la version de python est une expression qui renvoie une valeur.
parameter
etp1==parameter
f = lambda x: 'a' if x==0 else 'b' if x==1 else 'c'
. Quand j'ai appelé plus tardf(2)
, j'ai eu'c'
;f(1)
,'b'
; etf(0)
,'a'
. Comme pour p1(x), il désigne un prédicat; tant qu'il renvoieTrue
ouFalse
, peu importe, il est un appel de fonction ou une expression, c'est la fin.Solutions que j'ai utiliser:
Une combinaison de 2 des solutions posté ici, ce qui est relativement facile à lire et prend en charge les paramètres par défaut.
où
recherche
"lambda x: x - 2"
dans le dict, et qu'il utilise avecx=23
ne le trouve pas dans le dictionnaire et utilise la valeur par défaut
"lambda x: x - 22"
avecx=44
.La plupart des réponses sont assez vieux, et en particulier les acceptée, si elle semble en vaut la mise à jour.
Tout d'abord, l'officiel Python FAQ couvre ce, et recommande la
elif
de la chaîne pour les cas simples et lesdict
pour les plus grands ou plus complexes. Elle propose également un ensemble devisit_
méthodes (un style utilisé par de nombreux serveur cadres) pour certains cas:La FAQ mentionne également PEP 275, qui a été écrite pour obtenir un officiel-fois-pour-toutes les décisions sur l'ajout de style C instructions de commutation. Mais que PEP a effectivement été reportée à Python 3, et il ne fut officiellement rejeté une proposition distincte, PEP 3103. La réponse est, bien sûr, pas—mais les deux PEPs ont des liens vers des informations supplémentaires si vous êtes intéressé par les raisons ou l'histoire.
Une chose qui m'est venue à plusieurs reprises (et peut être vu dans la PPE 275, même si elle a été découpé comme une véritable recommandation), c'est que si vous êtes vraiment gêné par 8 lignes de code pour gérer les 4 cas, contre 6 lignes, vous auriez en C ou en Bash, vous pouvez toujours écrire ceci:
Ce n'est pas exactement encouragé par PEP 8, mais c'est lisible et pas trop unidiomatic.
Sur plus d'une décennie depuis que PEP 3103 a été rejetée, la question du style C le cas de déclarations, ou même un peu plus puissant version en Aller, a été considéré comme mort; chaque fois que quelqu'un met sur python-des idées ou -dev, qu'ils sont visés à l'ancienne décision.
Cependant, l'idée de la pleine ML de style pattern matching se pose toutes les quelques années, surtout depuis que les langues comme Swift et la Rouille ont adopté. Le problème est qu'il est difficile d'obtenir beaucoup de l'utilisation de la correspondance de motif sans des types de données algébriques. Alors que Guido a été sympathique à l'idée, personne n'est venu avec une proposition qui s'inscrit dans Python très bien. (Vous pouvez lire mon 2014 strawman pour un exemple.) Cela pourrait changer avec
dataclass
en 3.7 et sporadique des propositions pour un plus puissantenum
pour gérer les types sommes, ou avec des propositions différentes pour les différents types de déclaration locale de liaisons (comme PEP 3150, ou l'ensemble des propositions actuellement en cours de discussion sur des idées). Mais jusqu'à présent, il n'a pas.Il y a aussi parfois des propositions pour Perl 6-style correspondant, qui est en fait un méli-mélo de tout, de
elif
de regex de répartition unique type de commutation.J'ai aimé Marque Bies réponse
Depuis le
x
variable doit être utilisé deux fois, j'ai modifié les lambda fonctions sans paramètre.Je dois courir avec
results[value](value)
Edit: j'ai remarqué que je peux utiliser
None
type avec avec les dictionnaires. Donc, ce serait imiterswitch ; case else
result[None]()
?result = {'a': 100, None:5000}; result[None]
None:
se comporte commedefault:
.Solution pour exécuter des fonctions:
où foo1(), foo2(), foo3() et par défaut() sont des fonctions
switch
de remplacement ne s'exécute que l'option qui a été nécessaire...foo2()
, lefoo1()
,foo3()
, etdefault()
fonctions sont toutes aussi va courir, de sens, les choses pourraient prendre beaucoup de tempsget(option)()
. le problème est résolu.Court et facile à lire, a une valeur par défaut et prend en charge les expressions dans les deux conditions et les valeurs de retour.
Cependant, il est moins efficace que la solution avec un dictionnaire. Par exemple, Python est le scan de toutes les conditions avant de retourner à la valeur par défaut.
Je pense que la meilleure façon est de utiliser le langage python idiomes de garder votre code testable. Comme l'a montré dans les réponses précédentes, j'utilise les dictionnaires pour prendre avantage de python structures et de la langue et de garder le "cas" code isolés dans différentes méthodes. Ci-dessous il y a une classe, mais vous pouvez l'utiliser directement un module, variables globales et fonctions. La classe possède des méthodes qui peut être testé avec l'isolement.
Dependending à vos besoins, vous pouvez jouer avec des méthodes statiques et les attributs de trop.
Il est possible de prendre avantage de cette méthode aide aussi classes que les clés de "__choix_table". De cette façon, vous pouvez éviter isinstance abus et de garder tout propre et vérifiables.
En supposant que vous avez à traiter un grand nombre de messages ou de paquets sur le net ou votre MQ. Chaque paquet possède sa propre structure et son code de gestion (de manière générique).
Avec le code ci-dessus, il est possible de faire quelque chose comme ceci:
Donc complexité ne se propage pas dans le flux de code, mais il est rendu dans la structure de code.
Expansion sur Greg Hewgill réponse - Nous pouvons encapsuler le dictionnaire de la solution à l'aide d'un décorateur:
Cela peut ensuite être utilisé avec la
@case
-décorateurLes bonnes nouvelles sont que ce qui a déjà été fait dans NeoPySwitch-module. Il suffit de l'installer à l'aide de pip:
Une solution, j'ai tendance à utiliser qui permet également l'utilisation de dictionnaires est :
Ceci a l'avantage qu'il ne tente pas d'évaluer les fonctions de tous les temps, et vous avez juste à vous assurer que la fonction externe reçoit toutes les informations à l'intérieur des fonctions de besoin.
vous pouvez utiliser un envoyé dict:
De sortie:
Simple, pas testé; chaque condition est évaluée de façon indépendante: il n'y a pas de chute, mais tous les cas sont évalués (bien que l'expression de l'interrupteur n'est évaluée qu'une seule fois), sauf s'il existe une instruction break. Par exemple,
imprime
Was 1. Was 1 or 2. Was something.
(nom d'une pipe! Pourquoi ne puis-je pas avoir de fuite des espaces dans des blocs de code en ligne?) siexpression
évalue à1
,Was 2.
siexpression
évalue à2
, ouWas something.
siexpression
évalue à quelque chose d'autre.Définition:
vous permet d'utiliser un assez simple, la syntaxe, avec le cas groupés dans une carte:
J'ai continué à essayer de redéfinir l'interrupteur de manière à permettez-moi de se débarrasser de la "lambda:" mais abandonné. Peaufiner la définition:
M'a permis de carte de plusieurs cas du même code, et de fournir une option par défaut:
Chaque répliqué cas doit être dans son propre dictionnaire; switch() regroupe les dictionnaires avant de trouver la valeur. C'est encore plus laide que je le voudrais, mais c'est la base de l'efficacité de l'aide d'un haché de recherche sur l'expression, plutôt que d'une boucle sur toutes les touches.
Si vous n'avez pas à vous inquiéter de perdre la surbrillance de la syntaxe à l'intérieur du boîtier suites, vous pouvez effectuer les opérations suivantes:
Où
value
est la valeur. En C, ce serait:Nous pouvons également créer une fonction d'aide pour ce faire:
On peut donc l'utiliser comme ça pour l'exemple avec un, deux et trois:
J'ai été assez confus après la lecture de la réponse, mais ce effacé tout:
Ce code est analogue à:
Vérifier la Source pour en savoir plus sur dictionnaire de la cartographie des fonctions.
Il y a eu beaucoup de réponses jusqu'à présent qui ont dit, "nous n'avons pas d'interrupteur en Python, le faire de cette façon". Cependant, je tiens à souligner que l'instruction switch lui-même est un facile d'abuser de construire, qui peut et doit être évité dans la plupart des cas, car ils favorisent la programmation différée. Affaire au point:
Maintenant, vous pourrait le faire avec un interrupteur d'instruction (si Python offert) mais vous ferais perdre votre temps, car il y a des méthodes qui font cela très bien. Ou peut-être, vous avez quelque chose de moins évident:
Cependant, ce genre d'opération peut et doit être manipulé avec un dictionnaire, parce que ça sera plus rapide, moins complexe, moins sujet à erreur et plus compact.
Et la grande majorité des "cas d'utilisation" pour les instructions switch va tomber dans un de ces deux cas; il n'y a que très peu de raison de l'utiliser si vous avez pensé à votre problème de fond.
Donc, plutôt que de demander "comment puis-je passer en Python?", peut-être devrions-nous demander, "pourquoi dois-je passer en Python?" parce que c'est souvent la question la plus intéressante et souvent exposer les défauts dans la conception de ce que vous êtes en train de construire.
Maintenant, cela ne veut pas dire que les interrupteurs ne doivent jamais être utilisés. Les machines d'état, lexers, les analyseurs et des automates de tous les utiliser à un certain degré, et, en général, lorsque vous démarrez à partir d'une entrée symétrique et aller à une sortie asymétrique ils peuvent être utiles; il vous suffit de vous assurer que vous n'utilisez pas l'interrupteur, comme un marteau parce que vous voyez un tas de clous dans votre code.
Juste cartographie de quelques une des clés du code n'est pas vraiment question que la plupart des gens ont montré à l'aide de la dict. Le vrai truc est d'essayer d'émuler l'ensemble de tomber à travers et pause chose. Je ne pense pas que j'ai jamais écrit une instruction de cas où j'ai utilisé cette "fonctionnalité". Voici un aller à tomber à travers.
J'étais vraiment en l'imaginant comme une seule instruction. J'espère que vous me pardonnez l'idiot de mise en forme.
J'espère que c'est python. Il devrait vous donner de tomber à travers. bien sûr, les booléens les contrôles peuvent être des expressions et si vous voulait être évalué paresseusement vous pourriez emballer le tout dans un lambda. Je ne serais pas difficile à faire accepter, après l'exécution de certains éléments dans la liste. Il suffit de faire le n-uplet (bool, bool, fonction) et le deuxième bool indique si ou de ne pas casser ou de tomber à travers.
J'ai fait un Commutateur Cas de mise en œuvre qui ne fait pas l'utiliser tout à fait fi de l'extérieur(il utilise encore une si dans la classe).
L'utiliser comme ceci:-
if value in keys
avec un try-except bloc.Comme une variation mineure sur Marque Biek réponse, pour de rares cas comme ce double où l'utilisateur a un tas d'appels de fonction à retard avec des arguments pour le pack (et ce n'est pas la peine de construire un tas de fonctions hors-ligne), au lieu de cela:
... vous pouvez faire ceci:
C'est certes plus court, mais si c'est plus lisible est une question ouverte...
Je pense qu'il pourrait être plus lisible (bien que pas le plus bref) pour passer de
lambda
àpartial
pour cette utilisation particulière:... ce qui a l'avantage de travailler bien avec mot-clé arguments ainsi:
foo(some_expensive_function(3))
, alors c'est un problème. Soit l'ensemble de la chose pauses ou ils ont séparément test pour cette affaire devant le dictionnaire, qui non seulement semble étrange, mais peut induire en erreur un lecteur qui cherche un coup d'œil en pensant que les seules options sont à considérer dans le dictionnaire.lambda: foo(some_expensive_function(3))
pour qu'un cas. J'ai ajouté ma propre réponse le long de ces lignes.Bien qu'il existe déjà suffisamment de réponses, je tiens à souligner un plus simple et plus puissante solution:
De sortie:
J'ai trouvé la réponse suivante de python docs des plus utiles:
Vous pouvez le faire assez facilement avec une séquence de
if... elif... elif... else
. Quelques propositions ont été formulées pour la mise en marche syntaxe de l'instruction, mais il n'y a pas de consensus (encore) sur l'opportunité et la façon de faire des tests d'autonomie. Voir PEP 275 pour tous les détails et l'état actuel.Pour les cas où vous devez choisir parmi un très grand nombre de possibilités, vous pouvez créer un dictionnaire de cartographie cas, les valeurs pour les fonctions à appeler. Par exemple:
Pour l'appel de méthodes sur des objets, vous pouvez simplifier encore plus loin en utilisant le getattr() pour récupérer des méthodes avec un nom particulier:
Il est suggéré que vous utilisez un préfixe pour les noms de méthode, comme
visit_
dans cet exemple. Sans aucun préfixe, si les valeurs sont à venir à partir d'une source non fiable, un attaquant doit être capable d'appeler une méthode de l'objet.Similaire à cette réponse par abarnert, voici une solution spécifiquement pour le cas d'utilisation de l'appel d'une fonction unique pour chaque " cas " dans le commutateur, tout en évitant les
lambda
oupartial
pour les ultra-concision tout en étant capable de gérer les arguments mots-clefs:Exemple d'utilisation:
Noter que c'est le chaînage des appels, c'est à dire
switch(3)(...)(...)(...)
. Ne mettez pas de virgule entre les deux. Il est également important de mettre tout ça dans une expression, c'est pourquoi j'ai utilisé supplémentaire des parenthèses autour de la principale appel implicite de continuation de ligne.L'exemple ci-dessus va déclencher une erreur si vous passez sur une valeur qui n'est pas traitée, par exemple
switch(5)(1, ...)(2, ...)(3, ...)
. Vous pouvez fournir une valeur par défaut au lieu de cela, par exemple,switch(5, default=-1)...
retourne-1
.Si vous êtes vraiment juste de retour d'une prédéterminé, valeur fixe, vous pouvez créer un dictionnaire avec tous les apports possibles des indices comme les clés, ainsi que leurs valeurs correspondantes. Aussi, vous ne pourriez pas vraiment envie de fonction pour ce faire, sauf si vous êtes le calcul de la valeur de retour d'une certaine manière.
Oh, et si vous avez envie de faire quelque chose de type commutateur, voir ici.
Les ouvrages suivants pour ma situation quand j'ai besoin d'un interrupteur simple-cas d'appel d'un ensemble de méthodes et de ne pas seulement l'impression du texte. Après avoir joué avec les lambda et globals il m'a frappé comme l'option la plus simple pour moi pour l'instant. Peut-être que cela aidera quelqu'un aussi:
Et une autre option:
Facile à retenir:
aussi utiliser la Liste pour stocker les cas ,et appel de fonction correspondante par select-
également expliqué à screwdesk
Instruction Switch est juste sucre syntaxique pour if/elif/else.
Ce que tout contrôle est en train de faire est de déléguer le travail basé sur certaine condition est remplie - la décision de chemin.Pour l'emballage que dans le module et être capable d'appeler un travail basé sur un id unique, on peut utilise sur l'héritage et le fait que n'importe quelle méthode de python est virtuel, de fournir à la classe dérivée de travail spécifique de mise en œuvre, en tant que cas particuliers" gestionnaire