Retorno de Valores (La Entrega)

Fig. 9.5: print es efímero; return es tangible.
La diferencia que más confunde a los principiantes no es la sintaxis ni los tipos de datos. Es esta: El Altavoz (print) vs La Entrega (return). Entenderla cambia cómo diseñas tus funciones.
La Metáfora
-
print()es el Sistema de Altavoces: El robot anuncia por los altavoces: “¡El resultado es 50!”. Tú (el humano) lo escuchas, pero el siguiente robot en la línea no puede agarrar un sonido. El sonido se desvanece en el aire. -
returnes la Cinta Transportadora: El robot pone una caja física con el número 50 en la cinta y se la pasa al siguiente proceso. El siguiente robot puede tomar esa caja, abrirla y usar el 50 para hacer otra cosa.
El Error Clásico
def suma_mala(a, b):
print(a + b) # ANUNCIA el resultado
def suma_buena(a, b):
return a + b # ENTREGA el resultado
# Intento de uso
x = suma_mala(5, 5) # x está VACÍO (None). El número se perdió en el aire.
y = suma_buena(5, 5) # y vale 10. Tengo el número en la mano.
total = y + 20 # Funciona (30)
total = x + 20 # FALLA:
# TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Ese error de None desconcierta a todo el mundo la primera vez. No es un bug del lenguaje: Python cumplió exactamente lo que le pediste. El problema es que pediste la cosa equivocada.
Nota:
- ¿Es para que el usuario lo lea? →
- ¿Es para que el programa siga calculando? →
return
La Cinta Entrega Paquetes Dobles (Retorno de Tuplas)
En el capítulo de tuplas viste un adelanto que prometimos retomar. Este es el momento. Una función puede entregar varios valores de un solo envío: separa con comas en el return (Python arma la tupla) y desempaca al recibir:
def dividir(a: int, b: int) -> tuple[int, int]:
return a // b, a % b # la tupla (cociente, resto) viaja por la cinta
cociente, resto = dividir(17, 5)
print(cociente) # 3
print(resto) # 2
Sin variables globales, sin trucos: dos resultados, un viaje. Lo usarás cada vez que una operación produzca naturalmente más de un dato (el precio y el descuento aplicado, la caja y su pasillo).
Salidas de Emergencia (return Temprano)
Una función puede tener varios return, y el primero que se ejecuta termina el trabajo ahí mismo. Ya viste este patrón con nombre propio en el Capítulo 7: las cláusulas de guarda.
def buscar_producto(inventario: list, id_producto: str) -> dict | None:
for producto in inventario:
if producto["id"] == id_producto:
return producto # encontrado: salida inmediata
return None # recorrido completo sin éxito
Un detalle de la firma antes de seguir: -> dict | None se lee “devuelve un diccionario o None”. En las pistas de tipo, la barra | significa “o”; no es la unión de conjuntos del Capítulo 5.
Y un secreto que explica muchos None misteriosos: si una función llega al final sin return, Python le agrega un return None invisible. Toda función devuelve algo, aunque tú no lo pidas.