Qué es una función y por qué te cambia el juego
Una función es un bloque de código con nombre que encapsula una tarea. La idea es simple: en vez de copiar y pegar lógica por todo tu programa, la metes en una función y la llamas cuando la necesites. Esto mejora tres cosas clave: modularidad (separar el problema en piezas), reutilización (usar la misma pieza muchas veces) y pruebas rápidas (verificar una pieza aislada sin ejecutar todo el programa).
Cuándo conviene crear una función
- Cuando repites 3+ líneas de lógica en más de un lugar.
- Cuando una parte del programa se puede describir con un verbo: calcular, validar, formatear, convertir, resumir.
- Cuando quieres probar una parte sin depender de entradas/salidas (por ejemplo, sin pedir datos al usuario ni imprimir).
La regla de oro: funciones “puras” para probar más rápido
Para pruebas rápidas, intenta que tus funciones sean lo más “puras” posible: que reciban datos por parámetros y devuelvan un resultado con return, sin leer input ni imprimir dentro. Así puedes llamarlas con distintos valores y verificar resultados en segundos.
def precio_con_iva(precio, iva=0.21):
return precio * (1 + iva)
print(precio_con_iva(100)) # 121.0
print(precio_con_iva(100, 0.1)) # 110.0Parámetros vs argumentos (en práctica)
- Parámetros: variables que declaras en la función (
precio,iva). - Argumentos: valores reales al llamar (
100,0.1).
Mini-reto 1: extrae lógica repetida a una función
Objetivo: tomar un cálculo que usarías varias veces y convertirlo en función reutilizable.
Paso a paso
- Identifica una operación que se repite (por ejemplo: aplicar descuento).
- Define una función con parámetros claros.
- Devuelve el resultado con
return. - Úsala en 3 casos distintos para comprobar que sirve.
def aplicar_descuento(precio, porcentaje):
return precio * (1 - porcentaje / 100)
# Pruebas rápidas (casos típicos)
print(aplicar_descuento(200, 10)) # 180.0
print(aplicar_descuento(50, 0)) # 50.0
print(aplicar_descuento(80, 25)) # 60.0Mejora opcional: redondeo controlado
def aplicar_descuento(precio, porcentaje, decimales=2):
resultado = precio * (1 - porcentaje / 100)
return round(resultado, decimales)
print(aplicar_descuento(199.99, 15))Diseño de funciones: una responsabilidad, nombre claro
Una función debería hacer una cosa principal. Si tu función empieza a “hacer de todo”, se vuelve difícil de reutilizar y de probar. Un truco: si al describirla usas “y” muchas veces, probablemente debas dividirla.
Ejemplo: separar cálculo de presentación
En vez de mezclar cálculo con texto, crea una función que calcule y otra que formatee.
Continúa en nuestra aplicación.
Podrás escuchar el audiolibro con la pantalla apagada, recibir un certificado gratuito para este curso y además tener acceso a otros 5.000 cursos online gratuitos.
O continúa leyendo más abajo...Descargar la aplicación
def total_con_impuesto(subtotal, impuesto):
return subtotal * (1 + impuesto)
def formatear_moneda(valor, simbolo="$"):
return f"{simbolo}{valor:.2f}"
total = total_con_impuesto(100, 0.21)
print(formatear_moneda(total))Return: cómo devolver uno o varios resultados
return termina la función y devuelve un valor. Si necesitas devolver varios datos, puedes devolver una tupla (varios valores separados por comas).
def estadisticas_basicas(numeros):
minimo = min(numeros)
maximo = max(numeros)
promedio = sum(numeros) / len(numeros)
return minimo, maximo, promedio
mn, mx, prom = estadisticas_basicas([10, 20, 30])
print(mn, mx, prom)Argumentos por defecto y argumentos con nombre
Los valores por defecto te permiten simplificar llamadas comunes. Los argumentos con nombre hacen la llamada más legible y evitan errores de orden.
def enviar_alerta(mensaje, nivel="INFO", canal="email"):
return f"[{nivel}] ({canal}) {mensaje}"
print(enviar_alerta("Todo ok"))
print(enviar_alerta("Algo falló", nivel="ERROR"))
print(enviar_alerta("Revisar", canal="slack", nivel="WARN"))Regla práctica
- Usa posicionales para lo obvio y corto.
- Usa con nombre cuando hay 3+ parámetros o cuando el significado no es evidente.
Funciones y alcance (scope): evita variables “mágicas”
Las variables creadas dentro de una función viven ahí (son locales). Evita depender de variables externas “por comodidad”, porque dificulta pruebas y genera errores sutiles. Pasa lo necesario como parámetro.
tasa = 0.21
def mal_total(precio):
# Depende de una variable externa: difícil de probar y mantener
return precio * (1 + tasa)
def buen_total(precio, tasa):
return precio * (1 + tasa)
print(buen_total(100, 0.21))Mini-reto 2: crea una “caja de herramientas” de funciones
Objetivo: construir un conjunto pequeño de funciones útiles y probables de reutilizar en futuros mini-proyectos.
Paso a paso
- Crea 3 funciones pequeñas: una de conversión, una de formateo y una de cálculo.
- Asegúrate de que ninguna imprima: solo devuelven valores.
- Escribe 2 pruebas rápidas por función (llamadas con
printpara ver el resultado).
def celsius_a_fahrenheit(c):
return (c * 9/5) + 32
def recortar_texto(texto, max_len=10):
if len(texto) <= max_len:
return texto
return texto[:max_len-3] + "..."
def area_rectangulo(ancho, alto):
return ancho * alto
# Pruebas rápidas
print(celsius_a_fahrenheit(0))
print(celsius_a_fahrenheit(30))
print(recortar_texto("hola"))
print(recortar_texto("esto es un texto largo", 12))
print(area_rectangulo(3, 4))
print(area_rectangulo(10, 2))Pruebas rápidas sin librerías: asserts como “alarmas”
Una forma simple de probar es usar assert. Si la condición no se cumple, Python lanza un error y te avisa exactamente qué caso falló. Es ideal para validar tu lógica mientras programas.
def es_par(n):
return n % 2 == 0
assert es_par(2) == True
assert es_par(3) == False
def aplicar_iva(precio, iva=0.21):
return round(precio * (1 + iva), 2)
assert aplicar_iva(100) == 121.00
assert aplicar_iva(10, 0.1) == 11.00Consejo práctico
- Escribe 2–5
assertpor función: un caso típico, un borde (0, vacío, mínimo), y uno “raro” pero posible.
Mini-reto 3: refactor + pruebas en 10 minutos
Objetivo: tomar un bloque de lógica y convertirlo en funciones testeables con assert.
Paso a paso
- Crea una función
normalizar_nombreque reciba un texto y devuelva una versión “limpia”. - Crea una función
generar_usuarioque use la anterior y devuelva un nombre de usuario. - Escribe al menos 4
assertpara cubrir casos.
def normalizar_nombre(nombre):
nombre = nombre.strip().lower()
# Reemplazos simples (sin meternos en temas avanzados)
nombre = nombre.replace(" ", "")
return nombre
def generar_usuario(nombre, anio):
base = normalizar_nombre(nombre)
return f"{base}{anio}"
assert normalizar_nombre(" Ana ") == "ana"
assert normalizar_nombre("Juan Perez") == "juanperez"
assert generar_usuario(" Ana ", 2026) == "ana2026"
assert generar_usuario("Juan Perez", 1999) == "juanperez1999"Checklist de calidad para tus funciones
- Nombre claro: describe acción y resultado (
calcular_total,formatear_moneda). - Entradas explícitas: todo lo que necesita llega por parámetros.
- Salida consistente: siempre devuelve el mismo tipo de dato.
- Sin efectos secundarios (cuando puedas): no imprime, no modifica cosas externas.
- Probada: tiene
asserto llamadas de verificación con casos variados.