python python-3.x annotations type-hinting python-3.6

¿Qué son las anotaciones variables en Python 3.6?



python-3.x annotations (2)

¿Qué son las anotaciones variables?

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

Entonces, en lugar de insinuar el tipo con:

primes = [] # type: List[int]

Se introdujo una nueva sintaxis para permitir la anotación directa del tipo con una asignación del formulario:

primes: List[int] = []

que, como señaló @Martijn, denota una lista de enteros utilizando los tipos disponibles al typing e inicializándolos 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 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 las clases ahora tienen un atributo __annotations__ (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]}

captain no se mostrará actualmente a través de get_type_hints porque get_type_hints solo 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''>}

El uso de print(__annotations__) mostrará ''captain'': <class ''str''> pero realmente no deberías acceder a __annotations__ directamente.

Del mismo modo, para las clases:

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

Donde se utiliza un ChainMap para capturar las anotaciones para una clase dada (ubicada en la primera asignación) y todas las anotaciones definidas en las clases base encontradas en su mro (asignaciones consecuentes, {} para el objeto).

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

¿Me veré obligado a usarlo?

Al igual que con las sugerencias de tipo de PEP 484 , estas son completamente opcionales y son de uso principal para las herramientas de verificación de tipos (y cualquier otra cosa que pueda crear en base a esta información). Será provisional cuando se lance la versión estable de Python 3.6 para que se puedan agregar pequeños ajustes en el futuro.

Python 3.6 está a punto de ser lanzado. PEP 494 - El programa de lanzamiento de Python 3.6 menciona el final de diciembre, así que revisé What''s New in Python 3.6 para ver que mencionan las anotaciones variables :

PEP 484 introdujo el estándar para anotaciones de tipo de parámetros de función, también conocidos 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 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 tipados estáticamente, 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 atributo __annotations__ .

Entonces, por lo que leí, son parte de las sugerencias de tipo que provienen de Python 3.5, que se describen en Qué son las sugerencias de tipo en Python 3.5 .

Sigo al captain: str y class Starship Ejemplo de class Starship , pero no estoy seguro sobre el último: ¿Cómo explica primes: List[int] = [] ? ¿Está definiendo una lista vacía que solo permitirá enteros?


Todo entre : y = es una sugerencia de tipo, por lo que los primes se definen como List[int] , y se establecen inicialmente en una lista vacía (y stats es un diccionario vacío inicialmente, definido como Dict[str, int] ).

List[int] y Dict[str, int] no son parte de la siguiente sintaxis, sin embargo, estos ya se definieron en las sugerencias de escritura de Python 3.5 PEP. La propuesta 3.6 PEP 526 - Sintaxis para anotaciones variables solo define la sintaxis para adjuntar las mismas sugerencias a las variables; antes solo podía adjuntar sugerencias de tipo a variables con comentarios (por ejemplo, primes = [] # List[int] ).

Tanto List como Dict son tipos genéricos , lo que indica que tiene una lista o una asignación de diccionario con contenidos específicos (concretos).

Para 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 en la lista de primes son enteros, y todos los pares clave-valor en el diccionario de stats son pares (str, int) , asignando cadenas a enteros.

Vea la lista de typing.List y typing.Dict definiciones, la sección sobre Genéricos , así como PEP 483 - La teoría de las sugerencias de tipo .

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

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 introspectarlas y cómo declarar algo como un atributo de clase frente a un atributo de instancia, por ejemplo.