Anotaciones de funciones en Python

Terminología básica

PEP: PEP significa Propuesta de mejora de Python. Es un documento de diseño que describe nuevas funciones para Python o sus procesos o entorno. También proporciona información a la comunidad de python.
PEP es un mecanismo principal para proponer nuevas características importantes, por ejemplo, la interfaz de puerta de enlace del servidor web de Python, que recopila los aportes de la comunidad sobre los problemas y documenta las decisiones de diseño que se han implementado en Python.

Anotaciones de funciones: PEP 3107: PEP-3107 introdujo el concepto y la sintaxis para agregar anotaciones de metadatos arbitrarias a Python. Se introdujo en Python3, que anteriormente se hacía usando bibliotecas externas en python 2.x

¿Qué son las anotaciones de función?

Las anotaciones de funciones son expresiones arbitrarias de Python que están asociadas con varias partes de las funciones. Estas expresiones se evalúan en tiempo de compilación y no tienen vida en el entorno de tiempo de ejecución de python. Python no atribuye ningún significado a estas anotaciones. Toman vida cuando son interpretados por bibliotecas de terceros, por ejemplo, mypy.

Propósito de las anotaciones de funciones:
los beneficios de las anotaciones de funciones solo se pueden obtener a través de bibliotecas de terceros. El tipo de beneficios depende del tipo de biblioteca, por ejemplo

  1. Python admite escritura dinámica y, por lo tanto, no se proporciona ningún módulo para la verificación de tipos. Anotaciones como
    [def foo(a:”int”, b:”float”=5.0)  -> ”int”]

    (sintaxis descrita en detalle en la siguiente sección) se puede utilizar para recopilar información sobre el tipo de los parámetros y el tipo de retorno de la función para realizar un seguimiento del cambio de tipo que se produce en la función. ‘mypy’ es una de esas bibliotecas.

  2. Las bibliotecas pueden utilizar anotaciones basadas en strings para proporcionar mejores mensajes de ayuda en tiempo de compilación con respecto a las funcionalidades de varios métodos, clases y módulos.

Sintaxis de las anotaciones de funciones

Son como los parámetros opcionales que siguen al nombre del parámetro.

    Nota: La palabra ‘expresión’ que se menciona a continuación puede ser el tipo de los parámetros que se deben pasar o comentar o cualquier string arbitraria que las bibliotecas externas puedan usar de manera significativa.

  1. Anotaciones para parámetros simples: el nombre del argumento va seguido de ‘:’, que luego va seguido de la expresión. La sintaxis de las anotaciones se muestra a continuación.
    def foobar(a: expression, b: expression = 5):
    
  2. Anotaciones para parámetros en exceso: los parámetros en exceso, por ejemplo, *args y **kwargs, permiten pasar un número arbitrario de argumentos en una llamada de función. La sintaxis de anotación de dichos parámetros se muestra a continuación.
    def foobar(*args: expression, *kwargs: expression):
    
  3. Anotaciones para parámetros anidados: los parámetros anidados son una característica útil de python 2x donde se pasa una tupla en una llamada de función y se lleva a cabo el desempaquetado automático. Esta función se elimina en python 3x y se debe realizar un desempaquetado manual. La anotación se realiza después de la variable y no después de la tupla, como se muestra a continuación.
    def foobar((a: expression, b: expression), (c: expression, d: expression)):
    
  4. Anotaciones para el tipo de devolución: anotar el tipo de devolución es ligeramente diferente de anotar los argumentos de la función. El ‘->’ es seguido por expresión que es seguido por ‘:’. La sintaxis de anotación del tipo de devolución se muestra a continuación.
    def foobar(a: expression)->expression:

Gramática

decorator    :  ‘@’ name_  [‘(’ [arglist] ‘)’] NEWLINE
decorators   :  decorator+
funcdef      :  [decorators] ‘def’ NAME parameters [‘->’] ‘:’ suite
parameters   :  ‘(’ [typedarglist] ‘)’
typedarglist :  (( tfpdef [‘=’ test] ‘, ’)* (‘*’ [tname]
(‘, ’ tname [‘=’ test])* [‘, ’ ‘ **’ tname] | ‘**’ tname)
| tfpdef [‘=’ test (‘, ’ tfpdef [‘=’ test])* [‘, ’]])
tname        :  NAME [‘:’ test]
tfpdef       :  tname | ‘(’ tfplist ‘)’
tfplist      :  tfpdef (‘, ’ tfpdef)* [‘, ’]

Gramática de visualización: el árbol de análisis se forma a partir de la gramática anterior para brindar una mejor visualización de la sintaxis de la función de Python y las anotaciones de función.

Código de muestra

El siguiente código aclarará el hecho de que las anotaciones de la función no se evalúan en tiempo de ejecución. El código imprime series de fibonacci hasta las posiciones ‘n’.

# Python program to print Fibonacci series
def fib(n:'int', output:'list'=[])-> 'list':
    if n == 0:
        return output
    else:
        if len(output)< 2:
            output.append(1)
            fib(n-1, output)
        else:
            last = output[-1]
            second_last = output[-2]
            output.append(last + second_last)
            fib(n-1, output)
        return output
print(fib(5))
Output: [1, 1, 2, 3, 5]

Nota: Las anotaciones de funciones solo se admiten en python 3x.

Acceso a anotaciones de funciones

1. Uso de ‘__anotaciones__’ : se puede acceder a las anotaciones de función en el código anterior mediante un atributo especial ‘__anotaciones__’. Muestra el diccionario con una tecla especial ‘retorno’ y otras teclas con el nombre de los argumentos anotados. El siguiente código imprimirá las anotaciones.

# Python program to illustrate Function Annotations
def fib(n:'int', output:'list'=[])-> 'list':
    if n == 0:
        return output
    else:
        if len(output)< 2:
            output.append(1)
            fib(n-1, output)
        else:
            last = output[-1]
            second_last = output[-2]
            output.append(last + second_last)
            fib(n-1, output)
        return output
print(fib.__annotations__)
Output: {'return': 'list', 'n': 'int', 'output': 'list'}

2. Uso del módulo estándar ‘pydoc’ : el ‘pydoc’ es un módulo estándar de Python que devuelve la documentación dentro de un módulo de Python (si corresponde). Tiene un método especial de ‘ayuda()’ que proporciona un shell interactivo para obtener ayuda sobre cualquier palabra clave, método, clase o módulo. ‘ayuda()’ se puede utilizar para acceder a las anotaciones de la función. La siguiente imagen muestra las anotaciones de funciones en el código de la serie de Fibonacci anterior. El nombre del módulo es ‘fib.py’.

3. Uso del módulo estándar ‘inspeccionar’ : el módulo ‘inspeccionar’ proporciona varias funciones útiles para ayudar a obtener información sobre objetos vivos, como módulos, clases, métodos, funciones, rastreos, objetos de marco y objetos de código. Podemos usar el método ‘getfullargspec’ del módulo para obtener información completa sobre la función que contendrá las anotaciones.

# Python program to illustrate Function Annotations
import inspect
def fib(n:'int', output:'list'=[])-> 'list':
    if n == 0:
        return output
    else:
        if len(output)< 2:
            output.append(1)
            fib(n-1, output)
        else:
            last = output[-1]
            second_last = output[-2]
            output.append(last + second_last)
            fib(n-1, output)
        return output
print(inspect.getfullargspec(fib))
Output: FullArgSpec(args=['n', 'output'], varargs=None,
 varkw=None, defaults=([], ), kwonlyargs=[],
kwonlydefaults=None, annotations=
{'output': 'list', 'return': 'list', 'n': 'int'})

Aplicación de anotaciones de funciones

  • Uso de ‘mypy’: ‘mypy’ es una biblioteca externa que proporciona verificación de tipos estáticos con la ayuda de anotaciones de funciones.
    Descargar mypy para python 2x
    pip install mypy

    python 3x

    pip install git+git://github.com/JukkaL/mypy.git


    Ejemplo 1:

    # String slicing function that returns a string from start index to end index.
    def slice(string:str, start: int, end: int) -> str:
        return string[start:end]
      
    slice([1, 2, 3, 4, 5], 2, 4)

    Guarde el código anterior como ejemplo.py y ejecute el siguiente comando después de la instalación de mypy. Asegúrese de estar en el directorio donde guardó el archivo.

    mypy example.py

    Obtendrá el siguiente resultado.

  • Las cosas son un poco diferentes cuando los decoradores están involucrados.
    Ejemplo 2 (parte a): Comprobación de tipo de los parámetros de la función envuelta ‘gift_func’ y ‘wrapped’

    def wrapping_paper(func):
        def wrapped(gift:int):
            return 'I got a wrapped up {} for you'.format(str(func(gift)))
        return wrapped
      
    @wrapping_paper
    def gift_func(giftname:int):
        return giftname
          
    print(gift_func('gtx 5000'))

    Al principio, puede parecer que pasar una string como argumento devolverá un error ya que el tipo de datos requerido es un ‘int’ como se indica en ‘gift_func’ y ‘wrapped’. mypy no establece la verificación de tipos en los parámetros de la función envuelta, sin embargo, se puede verificar la verificación de tipos del decorador y el tipo de retorno de las funciones envueltas. Por lo tanto, se puede esperar el siguiente resultado del código anterior.

  • Ejemplo 2 (parte b): Comprobación de tipo de los parámetros del decorador ‘wrapping_paper’.

    def wrapping_paper(func:str):    
        def wrapped(gift:int):
            return 'I got a wrapped up {} for you'.format(str(func(gift)))
        return wrapped
      
    @wrapping_paper
    def gift_func(giftname:int):
        return giftname
          
    print(gift_func('gtx 5000'))

    Ahora obtendrá el siguiente resultado.

  • Ejemplo 2 (parte c): Comprobación de tipo del tipo de devolución de ‘gift_func’ y ‘wrapped’

    # Suppose we want the return type to be int
    from typing import Callable
    def wrapping_paper(func):
        def wrapped(gift) -> int:
            return 'I got a wrapped up {} for you'.format(str(func(gift)))
        return wrapped
      
    @wrapping_paper
    def gift_func(giftname) -> int:
        return giftname
          
    print(gift_func('gtx 5000'))

    Obtendrá el siguiente resultado.

  • Ejemplo 2 (parte d) Comprobación de tipo del tipo de retorno de la función contenedora ‘wrapping_paper’

    # Suppose we want the return type to be int
    from typing import Callable
    def wrapping_paper(func) -> int:
        def wrapped(gift):
            return 'I got a wrapped up {} for you'.format(str(func(gift)))
        return wrapped
      
    @wrapping_paper
    def gift_func(giftname):
        return giftname
          
    print(gift_func('gtx 5000'))

    Obtendrás el siguiente resultado

Este artículo es una contribución de Anmol Chachra . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando contribuya.geeksforgeeks.org o envíe su artículo por correo a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 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 *