J'essaie de comprendre le nouveau appariement des modèles structurels Syntaxe à Python 3.10. Je comprends qu'il est possible de faire correspondre des valeurs littérales comme celle-ci:
SUCCESS = 200 NOT_FOUND = 404 def handle(retcode): match retcode: case SUCCESS: print('success') case NOT_FOUND: print('not found') case _: print('unknown') handle(404) # File "<ipython-input-2-fa4ae710e263>", line 6 # case SUCCESS: # ^ # SyntaxError: name capture 'SUCCESS' makes remaining patterns unreachable
Cependant, si je refacteur et déplace ces valeurs vers des variables au niveau du module, il en résulte une erreur car les instructions représentent désormais Structures ou modèles plutôt que valeurs:
def handle(retcode): match retcode: case 200: print('success') case 404: print('not found') case _: print('unknown') handle(404) # not found
Y a-t-il un moyen d'utiliser l'instruction MATCH pour faire correspondre les valeurs qui sont stockées dans les variables?
5 Réponses :
Si la constante contre laquelle vous testez est un nom pointillé, il doit être traité comme une constante plutôt que comme le nom de la variable pour mettre la capture (voir pep 636 # correspondance contre les constantes et enums ):
class Codes: SUCCESS = 200 NOT_FOUND = 404 def handle(retcode): match retcode: case Codes.SUCCESS: print('success') case Codes.NOT_FOUND: print('not found') case _: print('unknown')
Je pense que cela n'est que moins clair car aucun corps n'est utilisé pour si
.
@Chepner étant donné la spécification, il ne peut pas être plus rapide que la tour linéaire si
(et c'est ainsi qu'il est implémenté actuellement). Les cas doivent être évalués en raison des règles de priorité
Pouvez-vous élaborer sur "Étant donné comment Python essaie d'implémenter la correspondance de modèles"? Qu'en est-il de la façon de le rendre moins sûr ou moins clair que si / autre?
En plus d'utiliser des valeurs littérales , les Modèles de valeur La section de PEP 635 mentionne l'utilisation de noms pêchés ou l'utilisation de gardes . Voir ci-dessous pour comparaison:
valeurs littérales
SUCCESS = 200 NOT_FOUND = 404 def handle(code): match code: case status if status == SUCCESS: print('success') case status if status == NOT_FOUND: print('not found') case _: print('unknown')
Références:
Noms pointillés
Tout nom en pointillé (c'est-à-dire l'accès à l'attribut) est interprété comme un modèle de valeur.
class StatusCodes: OK = 200 NOT_FOUND = 404 def handle(code): match code: case StatusCodes.OK: print('success') case StatusCodes.NOT_FOUND: print('not found') case _: print('unknown')
gardiens
[A] Guard est une expression arbitraire attachée à un modèle et qui doit évaluer à une valeur de "vérité" pour que le modèle réussisse.
def handle(code): match code: case 200: print('success') case 404: print('not found') case _: print('unknown')
J'espère que je pourrai aider à éclairer pourquoi les noms nus fonctionnent de cette façon ici.
Tout d'abord, comme d'autres l'ont déjà noté, si vous devez faire correspondre les valeurs dans le cadre de vos modèles, vous peut le faire par:
aucun
si
) Je crains que nous (les auteurs de PEP) avons probablement fait une petite erreur en incluant cet extrait de jouet dans un tutoriel précoce ... il est depuis devenu un peu viral. Notre objectif était de mener avec l'exemple le plus simple possible de l'appariement des modèles, mais nous semblons plutôt avoir créé une première impression déroutante pour beaucoup (en particulier lorsqu'elle est répétée sans contexte).
Le mot le plus négligé Dans le titre de ces PEPS est "structurel". Si vous ne correspondez pas à la structure du sujet, la correspondance de modèle structurelle n'est probablement pas le bon outil pour le travail.
La conception de cette fonctionnalité a été motivée par la destruction (comme le déballage itérable sur le LHS des affectations, mais généralisé pour tous les objets), c'est pourquoi nous avons facilité l'exécution de la fonctionnalité de base de l'extraction de parties d'un objet et de les lier aux noms. Nous avons également décidé qu'il serait également utile de permettre aux programmeurs de correspondre aux valeurs, nous les avons donc ajoutés (avec la condition que lorsque les valeurs sont nommées, elles doivent être qualifiées avec un point, afin de les distinguer des extractions les plus courantes).
La correspondance du motif de Python n'a jamais été vraiment conçue avec l'intention de propulser des instructions de commutateur de style c comme celle-ci; Cela a été proposé pour Python (et rejeté) deux fois auparavant, nous avons donc choisi d'aller dans une direction différente. En outre, il existe déjà un moyen évident d'activer une seule valeur, ce qui est plus simple, plus court et fonctionne sur chaque version de Python: un bon si
/ elif
/ else
échelle!
SUCCESS = 200 NOT_FOUND = 404 def handle(retcode): if retcode == SUCCESS: print('success') elif retcode == NOT_FOUND: print('not found') else: print('unknown') handle(404)
(si vous êtes vraiment préoccupé par les performances ou avez besoin d'une expression, l'envoi d'un dictionnaire est également une belle alternative .)
Cette réponse m'a beaucoup clarifié. Je ne sais pas si les PEP sont modifiables une fois finaux, mais je pense qu'un point plus clair sur "Pourquoi ce n'est pas une déclaration de commutation / cas et ne devrait pas être utilisé comme un" pourrait éviter beaucoup de confusion. Au moins le "What est nouveau à Python à Python "Docs peut être modifié encore à coup sûr :)
Python's Match
est bien plus qu'une instruction Switch simple. Si vous utilisez Bare ce que vous considérez comme des "noms de variables", ils vont en fait être Capture motifs . selon la définition dans pep no. 634
En plus du fait que vous ne devriez probablement pas utiliser correspondant à
pour votre cas d'utilisation, vous devez utiliser des noms qualifiés (pointillés) de l'une des manières suivantes:
import constants match retcode: case constants.SUCCESS: ... ...
SUCCESS = 200 NOT_FOUND = 404
J'ai développé La bibliothèque Match-Ref qui vous permet d'accéder à toute variable locale ou globale en ou en dehors de toute fonction, en utilisant simplement le préfixe réf.
.
import random SUCCESS = 200 NOT_FOUND = 404 def handle(retcode): random_code = random.randint(600, 699) globs = GetAttributeDict(globals()) locs = GetAttributeDict(locals()) match retcode: case globs.SUCCESS: print("Success") case globs.NOT_FOUND: print("Not found") case locs.random_code: print("OK , you win!")
Comme vous pouvez le voir, ref
a automatiquement résolu des variables à partir de vos espaces de noms locaux et globaux (dans cet ordre). Il n'y a pas de configuration supplémentaire nécessaire.
Si vous ne souhaitez pas utiliser les bibliothèques tiertes, vous pouvez voir une version sans bibliothèque légèrement similaire ci-dessous.
globals ( )
sont des fonctions intégrées dans Python qui renvoient un dict
contenant tous vos noms de variable mappés à leurs valeurs respectives. Vous devez être en mesure d'accéder aux valeurs du dict à l'aide de la syntaxe pointillée, car correspond à
ne prend pas non plus en charge la syntaxe d'accès de Dictionary. Vous pouvez donc écrire cette classe d'assistance simple:
class GetAttributeDict(dict): def __getattr__(self, name): return self[name]
et l'utiliser comme:
from matchref import ref import random SUCCESS = 200 NOT_FOUND = 404 def handle(retcode): random_code = random.randint(600,699) match retcode: case ref.SUCCESS: print("Success") case ref.NOT_FOUND: print("Not found") case ref.random_code: print("OK, you win!")
Étant donné que vous semblez avoir l'intention de réutiliser vos codes d'état (car sinon vous pouvez les alimenter dans votre case
), vous pourriez envisager d'utiliser des modules distincts pour cela. p>
Constants.py:
class StatusValues: success = 200 not_found = 404 def handle(retcode): match retcode: case StatusValues.success: print("Success") case StatusValues.not_found: print("Not found")
main.py
statuses = object() statuses.success = 200 status.not_found = 404 def handle(retcode): match retcode: case statuses.success: print("Success") case statuses.not_found: print("Not found")
python> 3.10
vous permet de gérer plus efficacement les modèles de cas.
|
et Si
les instructions peuvent également être utilisées. p>
Utilisation |
def get_product_info(make, in_dollar): match make: case "product_111" if in_dollar: return "10000 $" case "product_222" if not in_dollar: return "10000*73 INR" case _: return "error"
Utilisation Si
Instruction
match name: case "example_111" | "example_222": return f"Hello {name}" case _: return "Bye"
Ma lecture de PEP-635 suggère que vous avez besoin d'un modèle de valeur, qui semble être défini comme un nom pointillé . Je ne sais pas pourquoi vous obtiendrez une erreur de syntaxe ici, car
Success
devrait être interprété comme un modèle de capture."Un nom non qualifié (c'est-à-dire un nom nu sans points) sera toujours interprété comme un modèle de capture"