¿Qué son las anotaciones de variables en Python 3.6?

83

Python 3.6 está a punto de ser lanzado. PEP 494 - Python 3.6 Release Schedule menciona finales de diciembre, así que revisé las novedades de Python 3.6 para ver que mencionan las anotaciones de variables :

PEP 484 introdujo el estándar para anotaciones de tipo de parámetros de función, también conocido como sugerencias de tipo. Este PEP agrega sintaxis a Python para anotar los tipos de variables, incluidas las variables de clase y las variables de instancia:

primes: List[int] = []

captain: str  # Note: no initial value!

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

Al igual que para las anotaciones de funciones, el intérprete de Python no asigna ningún significado particular a las anotaciones de variables y solo las almacena en un atributo especial __annotations__de una clase o módulo. A diferencia de las declaraciones de variables en lenguajes de tipado estático, el objetivo de la sintaxis de anotación es proporcionar una manera fácil de especificar metadatos de tipo estructurado para herramientas y bibliotecas de terceros a través del árbol de sintaxis abstracta y el __annotations__atributo.

Entonces, por lo que leí, son parte de las sugerencias de tipo que provienen de Python 3.5, descritas en ¿Qué son las sugerencias de tipo en Python 3.5 ?

Sigo el ejemplo de captain: stry class Starship, pero no estoy seguro del último: ¿Cómo se primes: List[int] = []explica? ¿Está definiendo una lista vacía que solo permitirá números enteros?

fedorqui 'ASÍ que deja de hacer daño'
fuente
9
Las sugerencias de tipo no realizan ninguna verificación de tipo. primes: List[int] = []es solo una lista vacía como primes = []. La diferencia es que usted está afirmando que primes está destinado a contener solo intmensajes de correo electrónico y las aplicaciones de terceros pueden escribir verificar su programa para verificar esta afirmación, pero cuando ejecuta el código en cualquier intérprete de Python, eso es lo mismo que escribir primes = [], y por lo tanto primes: List[int] = []; primes.append("string")sigue siendo válido.
Bakuriu
2
@Bakuriu sí, buen punto. Como Jim Fasarakis-Hilliard describe en su respuesta a ¿Qué son las sugerencias de tipo en Python 3.5 , por qué las sugerencias de tipoAyuda a los verificadores de tipo, ayuda con la documentación y ayuda a los IDE a desarrollar herramientas más precisas y sólidas ? Tomado de PEP 526 - Sintaxis para anotaciones variables , Python seguirá siendo un lenguaje tipado dinámicamente, y los autores no tienen ningún deseo de hacer que las sugerencias de tipo sean obligatorias, ni siquiera por convención .
fedorqui 'SO deja de dañar'
1
¿Responde esto a tu pregunta? ¿Qué son las sugerencias de tipo en Python 3.5?
AMC

Respuestas:

46

Todo entre :y =es una sugerencia de tipo, por primeslo que de hecho se define como List[int], e inicialmente se establece en una lista vacía (y statses un diccionario vacío inicialmente, definido como Dict[str, int]).

List[int]y Dict[str, int]no forman parte de la siguiente sintaxis, sin embargo, estos ya estaban definidos en Python 3.5 typing hints PEP. El 3,6 PEP 526 - Sintaxis de las variables Anotaciones propuesta sólo se define la sintaxis para fijar los mismos consejos a variables; antes, solo podía adjuntar sugerencias de tipo a las variables con comentarios (por ejemplo primes = [] # List[int]).

Ambos Listy Dictson tipos genéricos , lo que indica que tiene una lista o mapeo de diccionario con contenido específico (concreto).

Porque List, solo hay un 'argumento' (los elementos en la [...]sintaxis), el tipo de cada elemento en la lista. Para Dict, el primer argumento es el tipo de clave y el segundo el tipo de valor. Por lo tanto, todos los valores de la primeslista son números enteros y todos los pares clave-valor del statsdiccionario son (str, int)pares, asignando cadenas a números enteros.

Vea las definiciones typing.Listy typing.Dict, la sección sobre Genéricos , así como PEP 483 - The Theory of Type Hints .

Al igual que las sugerencias de tipo en funciones, su uso es opcional y también se consideran anotaciones (siempre que haya un objeto al que adjuntarlas, por lo tanto, globales en módulos y atributos en clases, pero no locales en funciones) que puede introspectar a través del __annotations__atributo. Puede adjuntar información arbitraria a estas anotaciones, no está estrictamente limitado a escribir información de sugerencia.

Es posible que desee leer la propuesta completa ; contiene algunas funciones adicionales más allá de la nueva sintaxis; especifica cuándo se evalúan tales anotaciones, cómo hacer una introspección y cómo declarar algo como un atributo de clase frente a un atributo de instancia, por ejemplo.

Martijn Pieters
fuente
¿Puedo considerar las sugerencias de tipo como una especie de comentarios "legibles por máquina", ya que no afectan la forma en que se ejecuta el código (excepto por un obj.__annotations__atributo)?
iBug
1
@iBug: las anotaciones son comentarios legibles por máquina, en la medida en que los comentarios son anotaciones legibles por humanos de todos modos. :-)
Martijn Pieters
56

¿Qué son las anotaciones variables?

Las anotaciones variables son solo el siguiente paso de los # typecomentarios, tal como se definieron en PEP 484; el fundamento de este cambio se destaca en la sección respectiva del PEP 526 .

Entonces, en lugar de insinuar el tipo con:

primes = []  # type: List[int]

Se introdujo una nueva sintaxis para permitir anotar directamente el tipo con una asignación del formulario:

primes: List[int] = []

que, como señaló @Martijn, denota una lista de enteros mediante el uso de tipos disponibles typinge inicializándola en una lista vacía.

¿Qué cambios trae?

El primer cambio introducido fue una nueva sintaxis que le permite anotar un nombre con un tipo, ya sea de forma independiente después del :carácter u opcionalmente anotar al mismo tiempo que le asigna un valor:

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

Entonces el ejemplo en cuestión:

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

También se introdujeron cambios adicionales junto con la nueva sintaxis; Los módulos y clases ahora tienen un __annotations__atributo (como las funciones han tenido desde PEP 3107 - Anotaciones de funciones ) en el que se adjunta el tipo de metadatos:

from typing import get_type_hints  # grabs __annotations__

Ahora __main__.__annotations__contiene los tipos declarados:

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

captainactualmente no se mostrará get_type_hintsporque get_type_hintssolo devuelve tipos a los que también se puede acceder en un módulo; es decir, primero necesita un valor:

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

Se print(__annotations__)mostrará el uso , 'captain': <class 'str'>pero en realidad no debería acceder __annotations__directamente.

Del mismo modo, para las clases:

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

Donde ChainMapse usa a para tomar las anotaciones para una clase dada (ubicadas en el primer mapeo) y todas las anotaciones definidas en las clases base encontradas en su mro(mapeos consecuentes, {}para objeto).

Junto con la nueva sintaxis, ClassVarse ha agregado un nuevo tipo para denotar variables de clase. Sí, statsen su ejemplo es en realidad una variable de instancia , no un ClassVar.

¿Me veré obligado a usarlo?

Al igual que con las sugerencias de tipo de PEP 484, estos son completamente opcionales y son de uso principal para las herramientas de verificación de tipos (y cualquier otra cosa que pueda construir basándose en esta información). Será provisional cuando se lance la versión estable de Python 3.6, por lo que podrían agregarse pequeños ajustes en el futuro.

Dimitris Fasarakis Hilliard
fuente