Escritura gradual en Python

La escritura gradual es un sistema de tipeo desarrollado por Jeremy Siek y Walid Taha en 2006 que permite escribir dinámicamente partes de un programa y escribir estáticamente otras partes. Eso significa que el programador puede elegir qué parte del programa desea verificar.

El verificador de tipo gradual es un verificador de tipo estático que busca errores de tipo en la parte tipificada estáticamente de un programa tipificado gradualmente. El verificador de tipo se ocupa de la parte tipeada dinámicamente de un programa tipificado gradualmente mediante la asignación de variables y parámetros de función a un tipo especial llamado Any. Un verificador de tipos estáticos tratará todos los tipos como compatibles con Any y Any como compatibles con todos los tipos. Esto significa que es posible realizar cualquier operación o llamada de método en un valor de tipo en Cualquiera y asignarlo a cualquier variable, el verificador de tipo estático no se quejará.

¿Por qué necesitamos un verificador de tipo estático?

  • Para encontrar errores antes en la parte del programa tipificada estáticamente
  • Cuanto mayor sea el proyecto, se vuelve más difícil depurar un error de tipo de tiempo de ejecución
  • Ayuda a comprender el programa para un nuevo ingeniero en el equipo, ya que el flujo de objetos es difícil de seguir en Python.

Antecedentes:
en 2014, Guido van Rossum junto con Jukka Lehtosalo y Lukasz Langa hicieron una propuesta PEP 484 para Type Hints. El objetivo era proporcionar una sintaxis estándar para las anotaciones de tipo, abriendo el código de Python para un análisis estático más sencillo. En 2006, PEP 3107 ya había introducido la sintaxis para las anotaciones de funciones, pero la semántica se dejó deliberadamente sin definir ya que no había una idea clara de cómo la utilizaría una herramienta de terceros.

Esquema de la propuesta:

  • El desarrollador elige si usar o no un programa separado llamado Comprobador de tipo estático
  • Las anotaciones de función son provisionales, solo pueden ser utilizadas por verificadores de tipo estático
  • Bibliotecas de terceros, bibliotecas estándar, extensiones de C, código donde el propietario elige no anotar, para la compatibilidad con PY2, lleva tiempo anotar, en los casos en que no es factible usar la anotación de tipo, los desarrolladores pueden hacer declaraciones ficticias de clases y funciones en un archivo separado llamado archivo Stub que solo es visto por Static Type Checker
  • Fuertemente inspirado en Mypy , un verificador de tipo estático desarrollado por Jukka Lehtosalo

¿Por qué necesitamos sugerencias de tipos?

  • Para ayudar a escribir damas
  • Para servir como documentación adicional
  • Para ayudar a los IDE a mejorar las sugerencias y las verificaciones de código

Algunos ejemplos básicos para anotaciones de funciones:

Ejemplo 1:

# Python program to demonstrate
# function annotations
  
# Setting the arguments type and 
# return type to int
def sum(num1: int, num2: int) -> int:
    return num1 + num2
      
# will not throw an error
print(sum(2, 3))
  
# will raise a TypeError
print(sum(1, 'Geeks'))

Producción:

5
Traceback (most recent call last):
  File "/home/1c75a5171763b2dd0ca35c567f855c61.py", line 13, in 
    print(sum(1, 'Geeks'))
  File "/home/1c75a5171763b2dd0ca35c567f855c61.py", line 7, in sum
    return num1 + num2
TypeError: unsupported operand type(s) for +: 'int' and 'str'

El ejemplo 1 es una función simple cuyo argumento y tipo de devolución se declaran en las anotaciones. Esto indica que el tipo esperado de los argumentos num1y num2es int y el tipo de retorno esperado es int. Las expresiones cuyo tipo es un subtipo de un tipo de argumento específico también se aceptan para ese argumento.

Ejemplo 2:

# Python program to demonstrate
# function annotations
   
# Setting the arguments type and 
# return type to str
def say_hello(name: str) -> str:
    return 'Hello ' + name
      
# will not throw an error
print(say_hello("Geeks"))
  
# will raise a TypeError
print(say_hello(1))

Producción:

Hello Geeks
Traceback (most recent call last):
  File "/home/1ff73389e9ad8a9adb854b65716e6ab6.py", line 13, in 
    print(say_hello(1))
  File "/home/1ff73389e9ad8a9adb854b65716e6ab6.py", line 7, in say_hello
    return 'Hello ' + name
TypeError: Can't convert 'int' object to str implicitly

En el Ejemplo 2, el tipo esperado del nameargumento es str. Análogamente, el tipo de retorno esperado es str.

Algunos ejemplos básicos de anotaciones de variables:
PEP 484 introdujo sugerencias de tipo, también conocidas como anotaciones de tipo. Si bien su enfoque principal eran las anotaciones de funciones, también introdujo la noción de comentarios de tipo para anotar variables:

Ejemplo 1:

# Python program to demonstrate
# variable annotations
  
# declaring the list to be
# of int type
  
l = []  # type: List[int]
  
# declaring the variable to
# be str type
  
name = None # type: str

Los tipos de variables son inferidos por el inicializador, aunque hay casos ambiguos. Por ejemplo, en el Ejemplo 1, si no anotamos la variable lque es una lista vacía, un verificador de tipo estático arrojará un error. De manera similar, para una variable no inicializada name, es necesario asignarle el tipo none junto con la anotación de tipo, de lo contrario, un verificador de tipo estático generará un error.

PEP 526 introdujo una sintaxis estándar para anotar los tipos de variables (incluidas las variables de clase y las variables de instancia), en lugar de expresarlas mediante comentarios:
Ejemplo 2:

# Python program to demonstrate
# variable annotations
  
l: List[int] = []
  
name: str

El ejemplo 2 es igual que el ejemplo 1 pero con la sintaxis estándar introducida en PEP 526 en lugar del estilo de comentario de anotación de tipo para las variables. Tenga en cuenta que, en esta sintaxis, no es necesario asignar una variable name para escribir ninguna.

Ejemplo de un verificador de tipo estático:

Mypy es un verificador de tipos estáticos para Python 3 y Python 2.7. Usando la sintaxis de anotación de funciones de Python 3 (usando la notación PEP 484) o una sintaxis de anotación basada en comentarios para el código de Python 2, podrá anotar eficientemente su código y usarlomypypara verificar errores comunes en el código.

Mypy requiere Python 3.5 o posterior para ejecutarse. Una vez que haya instalado Python 3, instálelo mypy usando pip:

$ python3 -m pip install mypy

Una vez que mypy esté instalado, ejecútelo usando la herramienta mypy:

$ mypy program.py

Este comando hace que mypy type verifique su archivo program.py e imprima cualquier error que encuentre. Mypy verificará su código de forma estática: esto significa que buscará errores sin siquiera ejecutar su código, como un linter.

Aunque debe instalar Python 3 para ejecutar mypy, mypy también es totalmente capaz de verificar el tipo de código de Python 2: simplemente pase el indicador –py2.

$ mypy --py2 program.py

Ejemplos de errores de tipo lanzados por Mypy:

# Python program to demonstrate
# mypy 
  
  
def sum(a: int, b: int) -> int:
    return a + b
  
sum( 1, '2') # Argument 2 to "sum" has incompatible type "str"; expected "int"
sum(1, b '2') # Argument 2 to "sum" has incompatible type "bytes"; expected "int"

Escritura gradual en aplicaciones de producción:
Lukasz Langa dio una charla sobre escritura gradual en aplicaciones de producción en PyCascade-2018. Dio sugerencias de flujo de trabajo de la siguiente manera:

  • Sugerencia de flujo de trabajo n.º 1: encuentre las funciones más críticas y comience a escribirlas primero. Por ejemplo, escribir primero las funciones ampliamente utilizadas y los módulos ampliamente importados, ya que esto permite que el código que usa estos módulos y funciones se verifique con mayor eficacia.
  • Sugerencia de flujo de trabajo n.° 2: habilite la verificación de tipo de borrado a nivel de archivo antes de tiempo. Por ejemplo, flake8-mypy solo presenta errores de tipo relacionados con el archivo actual y la biblioteca estándar.
  • Sugerencia de flujo de trabajo n.° 3: habilite la verificación completa del tipo de programa en la integración continua para combatir las regresiones. Por ejemplo, realice comprobaciones completas de la base de código con mypy como parte de la integración continua para evitar errores de tipo en el código existente debido a un código nuevo.
  • Sugerencia de flujo de trabajo n.º 4: mida la cobertura de la función y la cantidad de excepciones TypeError/AttributeError en producción. Esto da una idea clara de cómo proceder con la escritura gradual para el código base restante.

Conclusión:

  • Solo las funciones anotadas son verificadas y las funciones no anotadas son ignoradas por un verificador de tipo estático.
  • Una ejecución limpia del verificador de tipos no prueba que no haya errores. A medida que anota gradualmente la base de código restante, pueden aparecer nuevos errores de tipo.
  • Las nuevas anotaciones pueden descubrir errores en otras funciones para las cuales el verificador de tipos no arrojó ningún error anteriormente.

Publicación traducida automáticamente

Artículo escrito por tarachetana y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *