Fundamentos
return en Python: devolver uno o varios valores
Entiende el return en Python: devolver un valor, la diferencia con print, salir antes de la función, el None y varios valores con tuplas.
Por Prof. Rodrigo Faustino · Actualizado el · 14 min de lectura
Métricas de este artículo
- Palabras
- 2669
- Caracteres
- 14.838
- Tiempo de lectura
- ~14 min
El return termina la función y entrega un valor a quien la llamó. Ese valor puede guardarse en una variable, usarse en una cuenta, probarse en un if o pasarse a otra función, y es lo que distingue una función que solo hace algo de una función que calcula una respuesta. Una función puede devolver un solo valor, varios valores de una vez, en forma de tupla, o nada, caso en que entrega None.
En los dos artículos anteriores las funciones mostraban el resultado con print. Eso resuelve el ejercicio del momento, pero deja el resultado atrapado en la pantalla: nadie puede sumarlo, compararlo ni reaprovecharlo. Aquí veremos cómo devolver, dónde termina la función, qué ocurre cuando no hay return, cómo devolver dos o tres valores de una vez y cómo aparece esto en los programas de ESP32.
Ya recibes valores devueltos
Desde el segundo artículo de la serie usas funciones que devuelven. El int("12") entrega el número 12, el len(texto) entrega el tamaño, y el input() entrega lo que se escribió. En todos, lo que aparece después de la llamada es un valor que guardas o usas:
idade = int(input("edad: "))
total = len("python") + 1En la ESP32 también: botao.value() entrega 0 o 1 y adc.read() entrega la lectura. Escribir tu propia función que devuelve es hacer lo mismo en el otro sentido: tú decides qué sale.
La IA que recuerda tu vida y vive en tu ordenador
- Memoria a largo plazo con la fuente de cada respuesta
- Funciona sin conexión: tus datos se quedan en tu PC
- Lee PDF, diapositivas, fotos y grabaciones de reuniones
Plan Esencial gratis para siempre
return: entregar el resultado
La palabra return va seguida de la expresión cuyo valor se entregará:
def dobro(n):
return n * 2
print(dobro(4))
x = dobro(5)
print(x)
print(dobro(3) + dobro(4))
print(dobro(dobro(2)))
print("fin")La salida es 8, 10, 14, 8 y fin. La llamada dobro(4) se sustituye por el valor 8 en el lugar donde se escribió, y por eso puede imprimirse, guardarse en x, sumarse a otra llamada o usarse como argumento de una tercera. En la última línea, dobro(dobro(2)) primero calcula dobro(2), que da 4, y después dobro(4), que da 8. Quien lee de adentro hacia afuera acierta el orden.
return no es print
La confusión más común del módulo es creer que return y print hacen lo mismo porque, en la prueba del alumno, los dos "muestran el número". El print escribe en la pantalla y se acabó: lo que entrega a la función es None. El return no escribe nada, y el valor queda disponible para quien llamó.
def dobro_print(n):
print(n * 2)
def dobro_return(n):
return n * 2
a = dobro_print(4)
print("a vale", a)
b = dobro_return(4)
print("b vale", b)
print(dobro_return(4) + 1)
dobro_return(4)
print("fin")La salida es 8, a vale None, b vale 8, 9 y fin. El primer 8 vino de dentro de dobro_print, cuando fue llamada. La variable a quedó con None. La dobro_return no mostró nada, y b quedó con 8. La cuenta dobro_return(4) + 1 dio 9. La última llamada, dobro_return(4) sola, no imprime nada: el valor fue entregado y nadie lo guardó, así que se perdió. Por eso las funciones que devuelven casi siempre aparecen dentro de un print, de una asignación o de otra expresión.
Cuando una función solo imprime, no puede usarse en una cuenta:
def dobro(n):
print(n * 2)
print(dobro(3) + dobro(4))6
8
Traceback (most recent call last):
File "main.py", line 4, in <module>
TypeError: unsupported types for __add__: 'NoneType', 'NoneType'Los dos números 6 y 8 aparecen porque las llamadas corrieron e imprimieron. Después Python intenta sumar lo que devolvieron, que es None en las dos, y falla. El Python del computador escribe el mensaje como unsupported operand type(s) for +: 'NoneType' and 'NoneType'. Siempre que aparezca NoneType en un mensaje, busca una función que debía tener un return.
Una regla práctica: si el resultado se usará después, devuelve. Si el objetivo es mostrar, imprime, y de preferencia fuera de la función, en el programa principal, que decide cómo mostrar.
El return termina la función
Cuando Python llega a un return, la función acaba ahí. Las líneas siguientes del cuerpo no corren, y el valor vuelve a la llamada.
def f():
print("antes")
return 1
print("después")
print(f())
def g(n):
if n > 0:
return "positivo"
print("no positivo")
print(g(3))
print(g(-1))La salida es antes, 1, positivo, no positivo y None. En la función f, el print("después") nunca corre, como ya ocurría con el break y el continue. En la g, el return está dentro del if: con 3 la función devuelve en el acto, y con -1 pasa de largo, imprime el aviso y termina sin devolver nada, lo que entrega None.
Este comportamiento permite un estilo muy útil, el de probar los casos uno por uno y devolver en cuanto uno sirva. La figura muestra la función classificar en tres llamadas, y cada una termina en el primer return que alcanza:
def classificar(n):
if n < 0:
return "negativo"
if n == 0:
return "cero"
return "positivo"
print(classificar(-5))
print(classificar(0))
print(classificar(7))La salida es negativo, cero y positivo. Fíjate en que no hay else ni elif: después de un return, lo que viene abajo solo corre si el anterior no sirvió, así que el else sería redundante. Es el mismo razonamiento de la escalera del elif, con el flujo cortado por el return. La función queda más plana, con menos niveles de sangría.
Lo mismo vale para la función que elige entre dos valores, como la del desafío Mayor de Dos:
def maior(a, b):
if a > b:
return a
return b
print(maior(10, 20))
print(maior(45, 12))
print(maior(7, 7))La salida es 20, 45 y 7. Con los dos iguales, el a > b es falso y la función devuelve b, que vale lo mismo.
Devolver un booleano
Una función que responde sí o no devuelve True o False. La expresión del return puede ser la propia comparación, sin if:
def eh_par(n):
return n % 2 == 0
print(eh_par(4))
print(eh_par(7))
if eh_par(10):
print("10 es par")
for n in range(1, 6):
if eh_par(n):
print(n, "par")La salida es True, False, 10 es par, 2 par y 4 par. Escribir if n % 2 == 0: return True y después else: return False funciona, pero da más líneas para el mismo efecto. Como la llamada eh_par(n) ya es un booleano, cabe directo en un if, como las condiciones de los artículos sobre tablas de verdad. Este patrón aparece en el desafío Función eh_par. Las funciones que responden sí o no suelen tener nombres de pregunta, como eh_par, esta_ligado o apertado.
Del programa al semestre planificado
- Plan de enseñanza y calendario montados solos
- Diario de clases listo para pegar en el SIGA
- Diapositivas y listas de ejercicios con solucionario
Versión Community gratis · Windows
return dentro de un bucle
Un return dentro de un for sale de la función entera, no solo del bucle. Esto vuelve la búsqueda más corta que la del break con else, del artículo sobre break, continue y else:
def primeiro_par(grupo):
for n in grupo:
if n % 2 == 0:
return n
return None
print(primeiro_par((3, 8, 12, 7)))
print(primeiro_par((3, 5, 7)))
r = primeiro_par((3, 5, 7))
if r is None:
print("ningún par")La salida es 8, None y ningún par. Si el bucle encuentra un par, la función devuelve en el acto. Si el bucle acaba sin encontrar, el programa llega al return None final, que avisa "no encontré". Quien llama prueba con is None. En lugar de una variable achou, el propio valor devuelto dice qué ocurrió.
La sangría del return lo decide todo. Dentro del bucle, termina en la primera vuelta:
def soma_ate(n):
total = 0
for i in range(1, n + 1):
total = total + i
return total
print(soma_ate(4))
def soma_ate2(n):
total = 0
for i in range(1, n + 1):
total = total + i
return total
print(soma_ate2(4))La salida es 1 y 10. La primera versión tiene el return con sangría dentro del for, y la función termina en la primera vuelta, con total valiendo 1. La segunda, con el return en la columna del for, solo devuelve después de que el bucle acaba, y la suma de 1 a 4 sale correcta, 10. Cuando una función con bucle entrega el primer elemento en lugar del total, mira la sangría del return.
Sin return, la función devuelve None
Cuando la función termina sin pasar por un return con valor, Python entrega None, el valor que significa "nada". Es el caso de la función que solo imprime, como la dobro_print. Dos variaciones sutiles del mismo problema:
def soma(a, b):
a + b
def soma2(a, b):
return
a + b
print(soma(2, 3))
print(soma2(2, 3))
x = print("hola")
print(x)La salida es None, None, hola y None. En la soma, la expresión a + b se calcula y se tira: sin return, nadie la recibe, y Python no avisa. En la soma2, el return está solo en una línea, lo que entrega None y termina, y el a + b de abajo es código muerto. Y el propio print también devuelve None, lo que muestra el último print(x).
El olvido más traicionero es el de un solo camino:
def classificar(n):
if n < 0:
return "negativo"
elif n > 0:
return "positivo"
print(classificar(5))
print(classificar(0))La salida es positivo y None. Para el 0, ninguna condición sirvió, y la función terminó sin devolver. La pregunta de comprobación es la misma del if: ¿todos los caminos de la función terminan en un return? Un return final, fuera del if, cubre el resto.
Devolver varios valores
Una función puede devolver más de un valor, separándolos con coma. Lo que llega a quien llamó es una tupla:
def dividir(a, b):
q = a // b
r = a % b
return q, r
resultado = dividir(7, 2)
print(resultado, type(resultado))
print(resultado[0], resultado[1])
q, r = dividir(7, 2)
print("cociente", q, "resto", r)
q2, r2 = dividir(17, 5)
print(q2, r2)
print(divmod(17, 5))La salida es (3, 1) <class 'tuple'>, 3 1, cociente 3 resto 1, 3 2 y (3, 2). El return q, r devuelve un solo objeto, la tupla (3, 1), que puede guardarse entera y leerse por posición, resultado[0] y resultado[1], o abrirse en dos nombres de una vez, q, r = dividir(7, 2). Esa apertura se llama desempaquetado. La función incorporada divmod hace exactamente eso: devuelve el cociente y el resto en una tupla.
El desempaquetado exige que los nombres y los valores tengan la misma cantidad. Con demasiados nombres, Python se queja:
def dividir(a, b):
return a // b, a % b
q, r, s = dividir(7, 2)Traceback (most recent call last):
File "main.py", line 4, in <module>
ValueError: need more than 2 values to unpackEl Python del computador dice ValueError: not enough values to unpack (expected 3, got 2), que trae las dos cantidades. El sentido es el mismo: tres nombres para dos valores. Si sobran valores, el error es too many values to unpack.
Otro error es tratar la tupla como si fuera un número:
def dividir(a, b):
return a // b, a % b
q = dividir(7, 2)
print(q + 1)Traceback (most recent call last):
File "main.py", line 5, in <module>
TypeError: unsupported types for __add__: 'tuple', 'int'La variable q guarda (3, 1), y sumar 1 a una tupla no tiene sentido. Cuando una función devuelve más de un valor, la pregunta es siempre la misma: ¿guardé la tupla entera o la abrí en nombres?
Una función que calcula más de una estadística es un buen uso. Las funciones listas min, max y sum, y el *valores del artículo anterior, ayudan:
def resumo(*valores):
menor = min(valores)
maior = max(valores)
media = sum(valores) / len(valores)
return menor, maior, media
mn, mx, md = resumo(7, 3, 9, 5)
print("menor", mn, "mayor", mx, "media", md)
print(resumo(4, 8))La salida es menor 3 mayor 9 media 6.0 y (4, 8, 6.0). La función devuelve tres valores, y quien llama elige cómo recibirlos. Los nombres mn y mx evitan sobrescribir min y max, las funciones listas.
En la ESP32
En hardware, el return sirve para transformar lecturas en decisiones. El botón con pull-up, por ejemplo, devuelve 0 cuando está presionado, y una función puede traducir eso en una pregunta directa:
from machine import Pin
botao = Pin(4, Pin.IN, Pin.PULL_UP)
estado = botao.value()
print("estado", estado)
def apertado(pino):
return pino.value() == 0
print(apertado(botao))
if apertado(botao):
print("presionado")
else:
print("suelto")La salida es estado 1, False y suelto. El botao.value() es una llamada que devuelve, y la función apertado esconde el detalle de que presionar es el valor 0 (el motivo está en el artículo sobre pull-up y pin flotante). En el simulador sin circuito, el pull-up mantiene el pin en 1 y el botón aparece suelto. El programa principal pasa a leer if apertado(botao):, y si el botón se cambia por un sensor activo en nivel alto, solo cambia la función.
Las conversiones entre rangos son otro uso clásico. El ADC lee de 0 a 4095, el PWM acepta de 0 a 1023, y una función mapear con un limitar al lado resuelve los dos:
def mapear(x, de_min, de_max, para_min, para_max):
return (x - de_min) * (para_max - para_min) // (de_max - de_min) + para_min
print(mapear(2048, 0, 4095, 0, 100))
print(mapear(2048, 0, 4095, 0, 1023))
print(mapear(0, 0, 4095, 0, 1023))
print(mapear(4095, 0, 4095, 0, 1023))
def limitar(v, minimo, maximo):
if v < minimo:
return minimo
if v > maximo:
return maximo
return v
print(limitar(-20, 0, 1023))
print(limitar(500, 0, 1023))
print(limitar(2000, 0, 1023))La salida es 50, 511, 0, 1023, 0, 500 y 1023. La división // mantiene todo en enteros, lo que evita el float de 32 bits de la ESP32 en cuentas simples (el artículo sobre ADC muestra los rangos y la atenuación). La limitar usa la escalera de return de la sección anterior, sin else.
La lectura que puede fallar combina bien con el None. La función intenta y devuelve el primer valor bueno, o None cuando nada sirvió, y quien llama decide qué hacer:
def tentar(leituras):
for v in leituras:
if v is not None:
return v
return None
print(tentar((None, None, 23.5)))
print(tentar((None, None)))La salida es 23.5 y None. Aquí la tupla hace el papel del sensor, como en el artículo sobre break y continue. En un programa real, el bucle llamaría al sensor en cada vuelta, y el None sería la señal de "inténtalo de nuevo" o "desiste".
Probar una función
Una función que devuelve es fácil de probar: llámala con un valor conocido y compara con el resultado esperado.
def dobro(n):
return n * 2
assert dobro(2) == 4
print("pasó")
print(dobro(2) == 4)
print(dobro(3) == 7)La salida es pasó, True y False. El assert no imprime nada cuando la condición es verdadera, e interrumpe el programa cuando es falsa:
def dobro(n):
return n * 2
assert dobro(3) == 7, "el doble de 3 debería ser 6"Traceback (most recent call last):
File "main.py", line 4, in <module>
AssertionError: el doble de 3 debería ser 6El texto después de la coma es el mensaje del error. Escribir dos o tres assert justo debajo de la función, antes de usarla en el programa, es un hábito que atrapa errores temprano. Con funciones que solo imprimen, este tipo de prueba no es posible, porque no hay valor que comparar.
return fuera de una función
El return solo tiene sentido dentro de una función. Escrito suelto, en el programa principal, Python lo rechaza:
return 5Traceback (most recent call last):
File "main.py", line 1
SyntaxError: 'return' outside functionEl motivo suele ser una sangría perdida: el return quedó en el margen, fuera del def.
En el aula: dónde suele tropezar el return
Estos casos se repiten en los grupos.
print en lugar de return
Es el más frecuente. El ejercicio pide "una función que devuelva el doble", y el alumno entrega una que imprime. En la pantalla, el resultado parece correcto. Cuando el enunciado manda "mostrar el valor devuelto", la función sigue imprimiendo dos veces o entrega None al print de afuera. La comprobación: ¿la función tiene la palabra return?
Llamar a la función y no usar el resultado
El alumno escribe dobro(5) en una línea suelta y espera ver 10. El valor fue devuelto y nadie lo recibió. En una pantalla de terminal interactivo, puede aparecer sin querer, pero en un programa guardado, no. La solución es print(dobro(5)) o x = dobro(5).
Dos return seguidos
def f(a, b):
return a
return bEl alumno cree que la función devuelve los dos. El segundo return nunca corre. Para devolver dos valores, es un solo return, con coma.
return en la sangría equivocada del bucle
El caso de la soma_ate que devuelve 1. El síntoma es el resultado del primer elemento solamente. Mira si el return está en la columna del for o del cuerpo.
Olvidar un camino
La función con if y elif sin else y sin return final. Ningún error, solo un None que aparece en algún lugar lejano. Prueba con los valores de frontera, como el 0.
Desempaquetar con la cuenta equivocada
q, r, s = dividir(7, 2). El alumno ve el ValueError y no entiende por qué "el computador pidió tres". La cantidad de nombres a la izquierda tiene que ser igual a la de valores devueltos.
Darle a una variable el nombre de una función incorporada
El min, max = resumo(...) funciona, pero borra las funciones min y max por el resto del programa. El error aparece lejos de ahí, cuando la próxima llamada a max(...) reclama que un número "no es invocable".
Ejercicio: resumen de lecturas
Reescribe el resumen para una lista de lecturas de sensor: la función recibe las lecturas que lleguen, descarta las que sean None y devuelve la menor, la mayor y el promedio. Si no sobra ninguna lectura, devuelve None. Empieza con la versión sin None, que ya está arriba, y agrega el filtro.
Una pista para el filtro: recorre valores con un for, acumula las válidas en una suma y cuenta cuántas fueron, como en el ejemplo del promedio de ADC del artículo sobre break y continue. Un return None justo después del bucle cubre el caso sin lecturas. Para mejorarlo, devuelve también cuántas lecturas se descartaron, lo que da una tupla de cuatro valores.
Preguntas frecuentes
¿Cuál es la diferencia entre print y return?
El print escribe en la pantalla, y el valor que la función entrega a quien llamó sigue siendo None. El return no escribe nada, y entrega el valor, que quien llamó puede guardar, sumar o imprimir.
¿Una función puede tener más de un return?
Puede, y es común. Cada camino del if puede tener el suyo. Solo corre el primero que se alcance, porque el return termina la función.
¿Qué devuelve la función si no tiene return?
None. Lo mismo ocurre cuando el return no tiene valor, o cuando el flujo llega al final del cuerpo sin pasar por ninguno.
¿Puedo devolver una lista, un texto o un booleano?
Puedes devolver cualquier valor. Textos, números, booleanos, tuplas y listas funcionan de la misma manera.
¿Necesito escribir return(x) con paréntesis?
No. El return es un comando, y no una función. return x y return (x) hacen lo mismo, pero la primera forma es la habitual.
¿return a, b devuelve una lista?
No, devuelve una tupla. La diferencia es que la tupla no puede alterarse después, y para el desempaquetado eso no hace diferencia.
Para continuar
Ahora los desafíos de funciones quedan al alcance, todos con return: Función Doble y Función Triple con un parámetro, Área del Rectángulo con dos, Función eh_par con booleano, Calculadora con Funciones con dos funciones y Mayor de Dos con if. Si quieres repasar la base, vuelve a los artículos sobre definir funciones y sobre parámetros y argumentos. La ruta Lógica con Python los reúne todos.
El próximo artículo trata del alcance de las variables: dónde existe cada nombre, por qué el n de dentro de la función no es el n de afuera, cuándo se usa global y qué hace el nonlocal.