¿Cómo anotar tipos de múltiples valores devueltos?

107

¿Cómo utilizo sugerencias de tipo para anotar una función que devuelve an Iterableque siempre produce dos valores: ay boola str? La sugerencia Tuple[bool, str]es cercana, excepto que limita el tipo de valor de retorno a una tupla, no a un generador u otro tipo de iterable.

Tengo más curiosidad porque me gustaría anotar una función foo()que se usa para devolver múltiples valores como este:

always_a_bool, always_a_str = foo()

Por lo general, funciona como foo()hacer algo como return a, b(que devuelve una tupla), pero me gustaría que la sugerencia de tipo sea lo suficientemente flexible como para reemplazar la tupla devuelta con un generador o una lista o algo más.

Richard Hansen
fuente
3
@ StevenM.Vascellaro Esto no es un duplicado de esa pregunta
TWR Cole

Respuestas:

144

Siempre estás devolviendo un objeto; el uso return one, twosimplemente devuelve una tupla.

Entonces sí, -> Tuple[bool, str]es completamente correcto.

Solo el Tupletipo le permite especificar un número fijo de elementos, cada uno con un tipo distinto. Realmente debería devolver una tupla, siempre, si su función produce un número fijo de valores de retorno, especialmente cuando esos valores son tipos específicos y distintos.

Se espera que otros tipos de secuencia tengan una especificación de tipo para un número variable de elementos, por typing.Sequencelo que no es adecuado aquí. Consulte también ¿Cuál es la diferencia entre listas y tuplas?

Las tuplas son estructuras de datos heterogéneas (es decir, sus entradas tienen significados diferentes), mientras que las listas son secuencias homogéneas. Las tuplas tienen estructura, las listas tienen orden.

El sistema de sugerencias de tipos de Python se adhiere a esa filosofía, actualmente no existe una sintaxis para especificar un iterable de longitud fija y que contenga tipos específicos en posiciones específicas.

Si debe especificar que cualquier iterable servirá, lo mejor que puede hacer es:

-> Iterable[Union[bool, str]]

momento en el que la persona que llama puede esperar valores booleanos y cadenas en cualquier orden y de longitud desconocida (entre 0 e infinito).

Martijn Pieters
fuente
2
La especificación del lenguaje permite devolver otros iterables; foo()podría hacer yield True; yield "blah"y a, b = foo()seguiría funcionando. O foo()podría devolver una lista. Reformulé mi pregunta para dejar en claro que estoy interesado en insinuar un iterable arbitrario, no una tupla.
Richard Hansen
2
@RichardHansen: He vuelto a comprobar los PEP y la documentación de typingy mypyotras 2 veces desde la publicación; Estoy bastante seguro de que no me perdí nada. Dicho esto, hay varios clientes habituales aquí en SO con mucha experiencia de sugerencias de tipo Python que no dudarán en corregirme si resultan estar equivocados, o publicarán una mejor respuesta.
Martijn Pieters
19
Tuve que agregar from typing import Tuplepara que la anotación Tuple funcionara.
PHPirate
3
@PHPirate: sí, y tendrías que hacer lo mismo para Iterabley Union. Dado que estamos discutiendo su uso específico aquí, la importación está implícita.
Martijn Pieters
4
@MartijnPieters, gracias por una gran respuesta, pero creo que vale la pena editar el comentario de PHPirate en su respuesta original.
Tim Mironov