Que fait ce comportement bizarre du côlon?

104

J'utilise Python 3.6.1 et je suis tombé sur quelque chose de très étrange. J'ai eu une simple faute de frappe dans le dictionnaire qui m'a pris beaucoup de temps à trouver.

context = {}
context["a"]: 2
print(context)

Production

{}

Que fait le code context["a"]: 2? Il ne soulève pas un SyntaxErrorquand il devrait IMO. Au début, je pensais que cela créait une tranche. Cependant, la saisie repr(context["a"]: 2)déclenche un SyntaxError. J'ai également tapé context["a"]: 2dans la console et la console n'a rien imprimé. Je pensais qu'il était peut-être revenu None, mais je n'en suis pas si sûr.

J'ai également pensé que cela pourrait être une instruction if sur une seule ligne, mais cela ne devrait pas non plus être la bonne syntaxe.

De plus, context["a"]devrait augmenter un KeyError.

Je suis perplexe. Que se passe-t-il?

Justengel
la source
2
Déjà cette question a une dupe et il est assez clair que c'est déroutant pour les novices de Python. Je suppose que c'est pire si Python est votre seul langage, où l'indication de type et la définition de variable avant l'initialisation en général peuvent sembler étrangères. J'imagine qu'il est impossible de soulever une erreur car ce comportement est délibéré et parfois utile comme expliqué dans PEP 526, et vous ne voulez pas casser la compatibilité. Cependant, je me demande si les développeurs Python envisageraient d'ajouter un message d'avertissement utile dans certains cas.
Chris_Rands
1
Est-ce que cela répond à votre question? Que sont les annotations de variables dans Python 3.6?
Georgy

Réponses:

98

Vous avez accidentellement écrit une syntaxiquement correcte annotation variable . Cette fonctionnalité a été introduite dans Python 3.6 (voir PEP 526 ).

Bien qu'une annotation de variable soit analysée dans le cadre d'une affectation annotée , l'instruction d'affectation est facultative :

annotated_assignment_stmt ::=  augtarget ":" expression ["=" expression]

Ainsi, dans context["a"]: 2

  • context["a"] est la cible de l'annotation
  • 2 est l'annotation elle-même
  • context["a"] est laissé non initialisé

Le PEP déclare que "la cible de l'annotation peut être n'importe quelle cible d'affectation unique valide, au moins syntaxiquement (il appartient au vérificateur de type quoi faire avec cela)" , ce qui signifie que la clé n'a pas besoin d'exister pour être annoté (donc non KeyError). Voici un exemple du PEP original:

d = {}
d['a']: int = 0  # Annotates d['a'] with int.
d['b']: int      # Annotates d['b'] with int.

Normalement, l'expression d'annotation doit être évaluée à un type Python - après tout, l'utilisation principale des annotations est l'indication de type, mais elle n'est pas appliquée. L'annotation peut être n'importe quelle expression Python valide , quel que soit le type ou la valeur du résultat.

Comme vous pouvez le voir, à l'heure actuelle, les indices de type sont très permissifs et rarement utiles, à moins que vous n'ayez un vérificateur de type statique tel que mypy .

vaultah
la source
12
Cela ne devrait-il pas alors nécessiter un =opérateur d'affectation? La clé n'existe pas. Cela me semble juste mal.
justengel
1
Dans ce cas, : est l'opérateur d'affectation. Nous "assignons" simplement une annotation de type seule, pas une clé. Je doute qu'il y ait une raison de l'autoriser, juste un effet secondaire involontaire de l'ajout de la syntaxe d'annotation.
chepner
1
@chepner Il semble que ce n'est pas un effet secondaire à mon humble avis. C'est exactement ce pour quoi le PEP correspondant a été conçu.
Ma0
6
C'est bizarre que cela vous permette d'annoter une cible qui n'a pas encore été définie. Si ma toute première ligne est x: stret immédiatement suivie de type(x), l'interprète lèvera un NameError. OMI, la syntaxe doit appliquer l'objet est prédéfinie ou définie sur place. Cela ne fait qu'introduire de la confusion.
regardé le
2
@Idlehands Cela va à l'encontre du but. Avoir x = 'i am a string'avant x: strrend ce dernier type de redondance. Cela n'aurait pas dû être ajouté du tout. C'était bien comme commentaire; Je ne le montre jamais utilisé d'une manière ou d'une autre.
Ma0