web-dev-qa-db-fra.com

Quelles sont les annotations variables dans Python 3.6?

Python 3.6 est sur le point d'être publié. PEP 494 - Python 3.6 Calendrier de versions mentionne la fin décembre, donc j'ai traversé Quoi de neuf dans Python = 3.6 voir qu'ils mentionnent les annotations variables :

PEP 484 norme introduite pour les annotations de type des paramètres de fonction, a.k.a. astuces de type. Ce PEP ajoute 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 ne donne 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 de variable dans les langages statiques, l'objectif de la syntaxe d'annotation est de fournir un moyen simple de spécifier des métadonnées de type structuré pour des outils et des bibliothèques tiers via l'arbre de syntaxe abstraite et le script __annotations__ attribut.

Donc, d'après ce que j'ai lu, ils font partie des indications de type provenant de Python 3.5, décrit dans Que sont les indications de type dans Python 3.5 =.

Je suis le captain: str et class Starship exemple, mais je ne suis pas sûr du dernier: Comment fonctionne primes: List[int] = [] Explique? Définit-il une liste vide qui permettra uniquement les entiers?

58
fedorqui

Tout ce qui se situe entre : Et le = Est un indice de type, donc primes est en effet défini comme List[int] Et est initialement défini sur 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. Toutefois, ils étaient déjà définis dans les astuces de frappe Python 3.5 PEP. La proposition 3.6 PEP 526 - Syntaxe pour les annotations de variables proposition niquement ​​définit la syntaxe pour associer les mêmes astuces aux variables; Avant de pouvoir uniquement associer des indicateurs de type aux variables avec des commentaires (par exemple, primes = [] # List[int]).

Les types List et Dict sont génériques, ce qui indique que vous disposez d'un mappage de liste ou de dictionnaire avec un contenu spécifique (concret).

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. Ainsi, les valeurs all de la liste primes sont des entiers et les paires all du dictionnaire stats sont (str, int) paires, mappant des chaînes à des entiers.

Voir les définitions typing.List et typing.Dict , la section sur Génériques , ainsi que PEP 483 - La théorie des indications de type .

Comme les indications de type sur les fonctions, leur utilisation est optionnelle et est également considérée annotations (à condition de pouvoir les associer, donc globales dans les modules et attributs sur les classes, mais pas les locales dans les fonctions) auxquels vous pourrait introspecter via l'attribut __annotations__. Vous pouvez attacher des informations arbitraires à ces annotations, vous n'êtes pas strictement limité aux informations de type.

Vous voudrez peut-être lire la proposition complète ; il contient des fonctionnalités supplémentaires au-delà de la nouvelle syntaxe; il spécifie quand de telles annotations sont évaluées, comment les examiner et comment déclarer quelque chose en tant qu'attribut de classe ou attribut d'instance, par exemple.

34
Martijn Pieters

Que sont les annotations variables?

Les annotations variables ne sont que l'étape suivante des commentaires # type, Tels qu'ils ont été définis dans PEP 484; la justification de ce changement est soulignée dans le section respective du PEP 526 .

Donc, au lieu d'insinuer le type avec:

primes = []  # type: List[int]

Une nouvelle syntaxe a été introduite pour permettre d'annoter directement le type avec une affectation de la forme:

primes: List[int] = []

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

Quels changements apporte-t-il?

La première modification introduite était nouvelle syntaxe , qui vous permet d'annoter un nom avec un type, soit de manière autonome après le caractère :, Soit éventuellement d'annoter, tout en lui attribuant une valeur:

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

Donc, l'exemple en question:

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

Des modifications supplémentaires ont également été introduites avec la nouvelle syntaxe; les modules et les classes ont maintenant un attribut __annotations__ (comme les fonctions en ont depuis PEP 3107 - Annotations de fonctions) dans laquelle les métadonnées de type sont attachées:

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 le biais de get_type_hints car get_type_hints ne renvoie que les types pouvant également être consultés sur un module; c'est-à-dire qu'il faut d'abord une valeur:

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

Utiliser print(__annotations__) affichera 'captain': <class 'str'> Mais vous ne devriez vraiment pas accéder à __annotations__ Directement.

De même, pour les cours:

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

ChainMap est utilisé pour récupérer les annotations d'une classe donnée (située dans le premier mappage) et toutes les annotations définies dans les classes de base trouvées dans ses mro (mappages consécutifs, {} pour objet).

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

Serai-je obligé de l'utiliser?

Comme pour les conseils de type de PEP 484, Il s’agit de complètement facultatif et sont d’une utilisation principale pour le type outils de vérification (et tout ce que vous pouvez construire à partir de ces informations). Il doit être provisoire lorsque la version stable de Python 3.6 est publiée, de sorte que de petites modifications puissent être ajoutées ultérieurement.

41