¿Cómo / por qué funciona la syntax de sugerencias de tipo Python?

Acabo de ver el siguiente ejemplo en PEP 484 :

def greeting(name: str) -> str: return 'Hello ' + name print(greeting('Martin')) print(greeting(1)) 

Como se esperaba, esto no funciona en Python 2:

  File "test.py", line 1 def greeting(name: str) -> str: ^ SyntaxError: invalid syntax 

Sin embargo, funciona para Python 3:

 Hello Martin Traceback (most recent call last): File "test.py", line 5, in  print(greeting(1)) File "test.py", line 2, in greeting return 'Hello ' + name TypeError: Can't convert 'int' object to str implicitly 

Esto fue inesperado. Todavía no verifica los tipos realmente, como puede ver con el siguiente ejemplo (se ejecuta, pero no lanza una excepción):

 def greeting(name: str) -> int: return 'Hello ' + name print(greeting('Martin')) 

Parece como si después de : tiene que ser el nombre de una función, pero la función parece ignorarse:

 def aha(something): print("aha") return something+"!" def greeting(name: aha, foo) -> int: return 'Hello ' + name + foo print(greeting('Martin', 'ad')) 

Lo mismo parece ser cierto para el nombre después de -> .

¿Este tipo de syntax de sugerencia utiliza otra cosa (como el lenguaje de modelado Java hace uso de los comentarios)? ¿Cuándo se introdujo esta syntax en Python? ¿Hay alguna forma de realizar una comprobación de tipos estática con esta syntax? ¿Siempre rompe la compatibilidad con Python 2?

No hay ningún tipo de insinuación aquí. Todo lo que hiciste fue proporcionar anotaciones ; estos se introdujeron con PEP 3107 (solo en Python 3, no hay soporte para esto en Python 2); Le permiten anotar argumentos y devolver valores con información arbitraria para su posterior inspección:

 >>> greeting.__annotations__ {'name': , 'return': } 

De lo contrario, no se consultan en absoluto aquí. En su lugar, el mensaje de error que obtuviste es al intentar concatenar valores de cadena y enteros en el cuerpo de la función :

 >>> 'Hello ' + 1 Traceback (most recent call last): File "", line 1, in  TypeError: Can't convert 'int' object to str implicitly 

Es un error de tipo personalizado destinado a proporcionar información adicional sobre por qué falló la concatenación de str + int ; es lanzado por el método str.__add__ para cualquier tipo que no sea str :

 >>> ''.__add__(1) Traceback (most recent call last): File "", line 1, in  TypeError: Can't convert 'int' object to str implicitly >>> ''.__add__(True) Traceback (most recent call last): File "", line 1, in  TypeError: Can't convert 'bool' object to str implicitly 

PEP 484 luego propone hacer uso de esas anotaciones para hacer una verificación de tipo estática real con herramientas adicionales , pero como la introducción del PEP dice:

Si bien estas anotaciones están disponibles en tiempo de ejecución a través del atributo __annotations__ habitual, no se realiza ninguna comprobación de tipo en tiempo de ejecución . En su lugar, la propuesta asume la existencia de un verificador de tipo independiente fuera de línea que los usuarios pueden ejecutar voluntariamente sobre su código fuente. Esencialmente, este tipo de verificador actúa como una barrera muy poderosa.

Énfasis en el original.

El PEP se inspiró en las herramientas existentes que usan anotaciones PEP 3107; específicamente el proyecto mypy (que está retrocediendo adoptando PEP 484), pero también el soporte de sugerencias de tipo en el IDE de PyCharm y el proyecto pytypedecl . Consulte el correo electrónico original de Guido van Rossum para iniciar este esfuerzo , así como un correo electrónico de seguimiento .

al parecer, mypy admite Python 2 preprocesando las anotaciones, eliminándolas antes de comstackr el código fuente por usted, pero de lo contrario, normalmente no puede usar la syntax del código de Python destinado a funcionar en Python 2.

PEP 484 también describe el uso de archivos de código auxiliar , que se encuentran junto a los archivos de Python normales; estos utilizan la extensión .pyi y solo contienen las firmas (con sugerencias de tipo), dejando la anotación de los archivos .py principales y, por lo tanto, utilizables en Python 2 (siempre que haya escrito el código Polyglot Python de lo contrario).