Quelles sont les annotations variables en Python 3.6?

Python 3.6 est sur le point de sortir. PEP 494 -- Python 3.6 Release Schedule mentionne la fin du mois de décembre, donc je suis passé par Quoi de neuf en Python 3.6 pour voir qu'ils mentionnent les annotations variables :

PEP 484 introduction d'une norme pour les annotations de type des paramètres de fonction, a. K. A. tapez des indices. Ce PEP ajoute de la syntaxe à Python pour annoter les types de variables, y compris les variables de classe et les variables d'instance:

  primes: List[int] = []

  captain: str  # Note: no initial value!

  class Starship:
     stats: Dict[str, int] = {}

tout comme pour les annotations de fonctions, L'interpréteur Python n'attache aucune signification particulière aux annotations de variables et ne les stocke que dans un attribut spécial __annotations__ d'une classe ou d'un module. Contrairement aux déclarations variables dans les langues statiquement typées, le but de la syntaxe d'annotation est de fournir un moyen facile de spécifier des métadonnées de type structuré pour les tiers outils et bibliothèques via l'arborescence de syntaxe abstraite et l'attribut __annotations__ .

donc d'après ce que j'ai lu, ils font partie des indices de type provenant de Python 3.5, décrits dans Quels sont les indices de Type en Python 3.5 .

je suis l'exemple captain: str et class Starship , mais pas sûr de la dernière: Comment primes: List[int] = [] expliquer? Est-ce qu'il définit une liste vide qui permettra juste des entiers?

43
demandé sur Community 2016-10-11 10:00:15

2 réponses

tout entre : et le = est un indice de type, donc primes est en effet défini comme List[int] , et initialement défini à une liste vide (et stats est un dictionnaire vide initialement, défini comme Dict[str, int] ).

List[int] et Dict[str, int] ne font pas partie de la syntaxe suivante cependant, ils ont déjà été définis dans les conseils de Dactylographie pep Python 3.5. La syntaxe 3.6 PEP 526 - pour les Annotations variables proposition seulement définit la syntaxe d'accorder les mêmes conseils à des variables; avant que vous ne pouviez vous joindre type allusions à des variables avec des commentaires (par exemple, primes = [] # List[int] ).

les deux List et Dict sont des génériques types, indiquant que vous avez une liste ou Dictionnaire cartographie avec le contenu (concret) spécifique.

pour List , il n'y a qu'un seul "argument" (les éléments de la syntaxe [...] ), le type de chaque élément de la liste. Pour Dict , le premier argument est le type de clé, et le second le type de valeur. Donc toutes les valeurs dans la liste primes sont des entiers, et toutes les valeurs dans le dictionnaire stats sont des paires (str, int) , des chaînes de mappage à des entiers.

voir les typing.List et typing.Dict , les définitions, les section Génériques , ainsi que PEP 483 – La Théorie de préconisations .

comme type conseils sur les fonctions, leur utilisation est facultative et sont également considérés comme annotations (à condition qu'il y ait un objet pour les attacher, donc globals dans les modules et attributs sur les classes, mais pas locaux dans les fonctions) que vous pouvez introduire via l'attribut __annotations__ . Vous pouvez attacher des informations arbitraires à ces annotations, vous n'êtes pas strictement limité aux informations d'indication de type.

vous pouvez vouloir lire la proposition complète ; il contient quelques fonctionnalités supplémentaires au-dessus et au-delà de la nouvelle syntaxe; il spécifie quand de telles annotations sont évaluées, comment les introspecter et comment déclarer quelque chose comme un attribut de classe vs. attribut d'instance, pour exemple.

24
répondu Martijn Pieters 2016-10-11 14:54:27

que sont les annotations variables?

Les annotations des variables

ne sont que la prochaine étape des commentaires # type , tels qu'ils ont été définis dans PEP 484 ; la justification de ce changement est mise en évidence dans la section de la norme pep 526 .

donc, au lieu d'indiquer le type avec:

primes = []  # type: List[int]

nouvelle syntaxe a été introduit pour permettre d'annoter directement le type avec une assignation de la forme:

primes: List[int] = []

qui, comme @Martijn l'a fait remarquer, dénote une liste d'entiers en utilisant les types disponibles dans typing et en l'initialisant à une liste vide.

quels changements apporte-t-elle?

le premier changement introduit a été nouvelle syntaxe qui vous permet d'annoter un nom avec un type, soit standalone après le caractère : ou éventuellement annoter tout en lui assignant une valeur:

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

ainsi l'exemple en question:

   primes: List[int] = [ ]
#    ^        ^         ^
#  augtarget  |         |
#         expression    |
#                  expression (optionally initialize to empty list)

d'autres changements ont également été introduits avec la nouvelle syntaxe; les modules et les classes ont maintenant un attribut __annotations__ (comme les fonctions ont eu depuis PEP 3107 -- fonction Annotations ) dans laquelle le type de métadonnées est attaché:

from typing import get_type_hints  # grabs __annotations__

maintenant __main__.__annotations__ contient les types déclarés:

>>> from typing import List, get_type_hints
>>> primes: List[int] = []
>>> captain: str
>>> import __main__
>>> get_type_hints(__main__)
{'primes': typing.List<~T>[int]}

captain n'apparaîtra pas actuellement par get_type_hints parce que get_type_hints ne renvoie que les types qui peuvent aussi être consultés sur un module; i.e., il a besoin d'une valeur en premier:

>>> captain = "Picard"
>>> get_type_hints(__main__)
{'primes': typing.List<~T>[int], 'captain': <class 'str'>}

à l'Aide de print(__annotations__) montrera 'captain': <class 'str'> mais vous ne devriez vraiment pas accéder à __annotations__ directement.

de même, pour les classes:

>>> get_type_hints(Starship)
ChainMap({'stats': typing.Dict<~KT, ~VT>[str, int]}, {})

où un ChainMap est utilisé pour saisir les annotations pour une classe donnée (située dans la première cartographie) et toutes les annotations définies dans les classes de base trouvées dans son mro (correspondances, {} pour l'objet).

avec la nouvelle syntaxe, un nouveau type ClassVar a été ajouté pour désigner les variables de classe. Yup, stats dans votre exemple est en fait un la variable d'instance , pas un ClassVar .

serai-je forcé de l'utiliser?

comme pour les indices de type de PEP 484 , ceux - ci sont complètement optionnel et sont de utilisation principale pour les outils de vérification de type (et tout ce que vous pouvez construire sur la base de ces informations). Il sera provisoire lorsque la version stable de Python 3.6 sera publiée afin que de petits ajustements puissent être ajoutés à l'avenir.

32
répondu Jim Fasarakis Hilliard 2017-06-18 22:14:11