Saltar al contenido
🐍 Curso de Python
/

Módulo 1 · Lección 34 de 59

El valor de retorno

Por qué imprimir y devolver no son lo mismo, cómo funciona return y qué pasa cuando una función no lo tiene.

⏱ 13 min de lectura

Las funciones que has escrito hasta ahora imprimen cosas. Está bien para una cabecera o un menú, pero la mayoría de las funciones útiles no sirven para enseñar algo en pantalla, sino para calcular un resultado que el resto del programa va a usar.

Esa diferencia, entre mostrar un valor y entregarlo, es el malentendido número uno de quien empieza con funciones. Si lo dejas claro hoy, te ahorras semanas de confusión.

Imprimir no es devolver#

Esta función parece que calcula el IVA:

python
def mostrar_iva(precio):
        print(precio * 0.21)


mostrar_iva(100)
Salida en pantalla
21.0

Sale el 21. Parece que funciona. Pero prueba a guardar ese resultado en una variable:

python
total = mostrar_iva(100)
print(total)
Salida en pantalla
21.0
None

El 21 lo imprime la función. Después imprimimos total y sale None, que es la forma que tiene Python de decir "nada". La función ha escrito el número en la pantalla y lo ha tirado. No te lo ha dado.

Y en cuanto intentas usarlo, el programa se rompe:

python
iva = mostrar_iva(100)
print(iva + 100)
Salida en pantalla
21.0
Traceback (most recent call last):
  File "/Users/erwin/curso-python/factura.py", line 6, in <module>
    print(iva + 100)
          ~~~~^~~~~
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

return#

Cambiar print por return lo arregla todo:

python
def calcular_iva(precio):
        return precio * 0.21


iva = calcular_iva(100)
print(iva)
print(100 + calcular_iva(100))
print(f"IVA de la cesta: {calcular_iva(37.5):.2f} euros")
Salida en pantalla
21.0
121.0
IVA de la cesta: 7.88 euros

Ahora la llamada calcular_iva(100) es un valor. Se comporta igual que si hubieras escrito 21.0 en ese sitio: puedes guardarlo, sumarlo, meterlo en una f-string, pasarlo a otra función o ponerlo en una lista.

Fíjate también en el nombre. mostrar_iva empieza por un verbo de mostrar; calcular_iva, por uno de calcular. El nombre ya te dice cuál de las dos devuelve algo.

return termina la función inmediatamente#

En cuanto Python ejecuta un return, sale de la función. Lo que haya debajo no se ejecuta:

python
def calcular_iva(precio):
        print("Calculando el IVA...")
    return precio * 0.21
    print("Esta línea no se ejecuta nunca")


print(calcular_iva(100))
Salida en pantalla
Calculando el IVA...
21.0

El último print está ahí, escrito y bien sangrado, y nunca se ejecutará. Python no da ningún error por ello; simplemente es código muerto. Algunos editores te lo marcan en gris.

Esto no significa que solo pueda haber un return por función. Puede haber varios, en ramas distintas de un if; lo que ocurre es que el primero que se ejecute acaba la función.

python
def clasificar_nota(nota):
        if nota < 5:
                return "Suspenso"
    if nota < 7:
                return "Aprobado"
    if nota < 9:
                return "Notable"
    return "Sobresaliente"


print(clasificar_nota(4))
print(clasificar_nota(8.5))
Salida en pantalla
Suspenso
Notable

Una función sin return devuelve None#

Toda función devuelve algo, siempre. Si no escribes return, Python devuelve None por ti:

python
def guardar_nota(nota):
        print(f"Nota guardada: {nota}")


resultado = guardar_nota(8)
print(resultado)
print(type(resultado))
Salida en pantalla
Nota guardada: 8
None
<class 'NoneType'>

None es un valor de pleno derecho, con su propio tipo, NoneType. Significa "ausencia de valor" y lo verás por todas partes en Python.

Hay un caso especialmente traicionero: la función que a veces devuelve algo.

python
def es_mayor_de_edad(edad):
        if edad >= 18:
                return True


print(es_mayor_de_edad(20))
print(es_mayor_de_edad(15))
Salida en pantalla
True
None

Cuando la condición no se cumple, la función llega al final sin encontrar ningún return y devuelve None. En un if eso se comporta como falso y parece que funciona, pero None no es False, y el día que compares con == False o metas el resultado en una lista te llevarás una sorpresa. Escribe siempre el return de todos los caminos:

python
def es_mayor_de_edad(edad):
        return edad >= 18

Devolver varios valores a la vez#

Pon varios valores separados por comas después del return y Python los empaqueta en una tupla:

python
def analizar_notas(notas):
        media = sum(notas) / len(notas)
    return media, min(notas), max(notas)


resultado = analizar_notas([7, 9, 5, 8])
print(resultado)
Salida en pantalla
(7.25, 5, 9)

No hay nada nuevo aquí: es el mismo empaquetado de tuplas que viste en su lección, y por eso lo normal es recogerlo desempaquetando en varias variables de golpe:

python
media, peor, mejor = analizar_notas([7, 9, 5, 8])
print(f"Media: {media:.2f}")
print(f"Peor nota: {peor}")
print(f"Mejor nota: {mejor}")
Salida en pantalla
Media: 7.25
Peor nota: 5
Mejor nota: 9

Es cómodo, pero con moderación. Si tu función devuelve cinco o seis valores, quien la llama tiene que recordar el orden exacto de todos, y eso se equivoca solo. A partir de tres valores, plantéate devolver un diccionario:

python
def analizar_notas(notas):
        return {
        "media": sum(notas) / len(notas),
        "peor": min(notas),
        "mejor": max(notas),
        "aprobadas": len([nota for nota in notas if nota >= 5]),
    }


resumen = analizar_notas([7, 9, 5, 8])
print(resumen["media"])
print(resumen["aprobadas"])
Salida en pantalla
7.25
4

Con el diccionario, quien lo recibe pide lo que necesita por su nombre y no depende de ningún orden.

El retorno temprano#

Como return corta la función en seco, se puede usar para quitarse de encima los casos raros al principio y dejar el caso normal sin anidar. Compara estas dos versiones de lo mismo:

python
def calcular_descuento(importe, socio):
        if importe > 0:
                if socio:
                        if importe >= 100:
                                return importe * 0.20
            else:
                                return importe * 0.10
        else:
                        return 0.0
    else:
                return 0.0
python
def calcular_descuento(importe, socio):
        if importe <= 0:
                return 0.0
    if not socio:
                return 0.0
    if importe >= 100:
                return importe * 0.20
    return importe * 0.10

Las dos dan exactamente el mismo resultado:

python
print(calcular_descuento(150, True))
print(calcular_descuento(40, True))
print(calcular_descuento(150, False))
Salida en pantalla
30.0
4.0
0.0

La segunda versión se lee de arriba abajo como una lista de reglas, nunca pasa de un nivel de sangría y no te obliga a sostener mentalmente tres if abiertos para saber en qué caso estás. Es el patrón llamado retorno temprano o early return, y cuando te acostumbras a él ya no vuelves atrás.