Funciones en Python - De lo Básico a lo Avanzado

🎯 ¿Qué son las funciones?
Imaginate que estás en la cocina preparando tu comida favorita. Para hacer la salsa, siempre seguís los mismos pasos: picar cebolla, sofreír, agregar tomate, condimentar. Las funciones son exactamente eso: recetas de código que podés usar una y otra vez.
Definición formal
Una función es un bloque de código reutilizable que realiza una tarea específica. Tiene:
- Nombre: Para identificarla
- Parámetros (opcional): Datos que recibe
- Cuerpo: El código que ejecuta
- Retorno (opcional): El resultado que devuelve
Analogía del mundo real
Función: Hacer mate
Entrada (parámetros): Yerba, agua caliente
Proceso: Llenar mate, poner bombilla, cebar
Salida (retorno): Mate listo para tomar
🚀 ¿Por qué usar funciones?
1. Evitar repetir código (DRY - Don’t Repeat Yourself)
❌ Sin funciones:
# Calcular área de rectángulo 1
base1 = 10
altura1 = 5
area1 = base1 * altura1
print(f"Área 1: {area1}")
# Calcular área de rectángulo 2
base2 = 8
altura2 = 3
area2 = base2 * altura2
print(f"Área 2: {area2}")
# Calcular área de rectángulo 3
base3 = 15
altura3 = 7
area3 = base3 * altura3
print(f"Área 3: {area3}")
✅ Con funciones:
def calcular_area_rectangulo(base, altura):
return base * altura
area1 = calcular_area_rectangulo(10, 5)
area2 = calcular_area_rectangulo(8, 3)
area3 = calcular_area_rectangulo(15, 7)
print(f"Área 1: {area1}")
print(f"Área 2: {area2}")
print(f"Área 3: {area3}")
2. Organizar el código
Las funciones dividen tu programa en partes manejables, como capítulos de un libro.
3. Reutilización
Escribís una vez, usás mil veces.
4. Facilitar el trabajo en equipo
Cada persona puede trabajar en funciones diferentes.
📝 Crear tu primera función
Estructura básica
def nombre_funcion(parametro1, parametro2):
"""
Docstring: Descripción de qué hace la función
"""
# Código de la función
resultado = parametro1 + parametro2
return resultado
Componentes:
def: Palabra clave para definir una funciónnombre_funcion: Nombre descriptivo (usa snake_case)(parametros): Datos que recibe (opcional)""" docstring """: Documentación (opcional pero recomendado)- Cuerpo: El código indentado
return: Valor que devuelve (opcional)
Ejemplo simple
def saludar(nombre):
"""
Saluda a una persona por su nombre
"""
mensaje = f"¡Hola, {nombre}! ¿Cómo estás?"
return mensaje
# Usar la función
saludo1 = saludar("Juan")
saludo2 = saludar("María")
print(saludo1) # ¡Hola, Juan! ¿Cómo estás?
print(saludo2) # ¡Hola, María! ¿Cómo estás?
🔧 Parámetros y argumentos
Parámetros vs Argumentos
- Parámetros: Variables en la definición de la función
- Argumentos: Valores que pasás cuando llamás la función
def sumar(a, b): # a y b son PARÁMETROS
return a + b
resultado = sumar(5, 3) # 5 y 3 son ARGUMENTOS
Tipos de parámetros
1. Parámetros posicionales
def presentar_persona(nombre, edad, ciudad):
return f"{nombre} tiene {edad} años y vive en {ciudad}"
# El orden importa
print(presentar_persona("Ana", 25, "El Calafate"))
# Ana tiene 25 años y vive en El Calafate
2. Parámetros con nombre (keyword arguments)
# Podés especificar el nombre del parámetro
print(presentar_persona(ciudad="El Calafate", nombre="Ana", edad=25))
# El orden no importa cuando usás nombres
3. Parámetros con valores por defecto
def configurar_sensor(id_sensor, temp_min=0, temp_max=100):
"""
Configura un sensor con valores por defecto
"""
return {
'id': id_sensor,
'temp_min': temp_min,
'temp_max': temp_max
}
# Usar valores por defecto
sensor1 = configurar_sensor("TEMP-001")
print(sensor1) # {'id': 'TEMP-001', 'temp_min': 0, 'temp_max': 100}
# Sobrescribir valores por defecto
sensor2 = configurar_sensor("TEMP-002", temp_min=15, temp_max=85)
print(sensor2) # {'id': 'TEMP-002', 'temp_min': 15, 'temp_max': 85}
4. Número variable de argumentos (*args)
def calcular_promedio(*numeros):
"""
Calcula el promedio de cualquier cantidad de números
"""
if len(numeros) == 0:
return 0
return sum(numeros) / len(numeros)
# Podés pasar cualquier cantidad de argumentos
print(calcular_promedio(8, 7, 9)) # 8.0
print(calcular_promedio(10, 9, 8, 7, 6)) # 8.0
print(calcular_promedio(5)) # 5.0
5. Argumentos con nombre variables (**kwargs)
def crear_reporte(**datos):
"""
Crea un reporte con datos variables
"""
print("📊 REPORTE")
print("=" * 40)
for clave, valor in datos.items():
print(f"{clave}: {valor}")
# Podés pasar cualquier cantidad de pares clave-valor
crear_reporte(
temperatura=85.5,
presion=7.2,
nivel=3.8,
estado="NORMAL"
)
🔄 Return: Devolver valores
Función sin return
def imprimir_mensaje(texto):
"""
Solo imprime, no devuelve nada
"""
print(f"Mensaje: {texto}")
resultado = imprimir_mensaje("Hola")
print(resultado) # None
Función con return
def multiplicar(a, b):
"""
Devuelve el producto de dos números
"""
return a * b
resultado = multiplicar(5, 3)
print(resultado) # 15
Return múltiple (tupla)
def calcular_estadisticas(numeros):
"""
Devuelve mínimo, máximo y promedio
"""
minimo = min(numeros)
maximo = max(numeros)
promedio = sum(numeros) / len(numeros)
return minimo, maximo, promedio
# Desempaquetar los valores
min_val, max_val, prom = calcular_estadisticas([10, 20, 30, 40, 50])
print(f"Mín: {min_val}, Máx: {max_val}, Prom: {prom}")
Return temprano
def verificar_temperatura(temp):
"""
Verifica si la temperatura está en rango
"""
if temp < 0:
return "❌ Temperatura muy baja"
if temp > 100:
return "❌ Temperatura muy alta"
return "✅ Temperatura normal"
print(verificar_temperatura(-5)) # ❌ Temperatura muy baja
print(verificar_temperatura(50)) # ✅ Temperatura normal
print(verificar_temperatura(150)) # ❌ Temperatura muy alta
🌍 Alcance de variables (Scope)
Variables locales
def calcular_area(base, altura):
area = base * altura # 'area' es LOCAL a esta función
return area
resultado = calcular_area(10, 5)
# print(area) # ❌ Error: 'area' no existe fuera de la función
Variables globales
temperatura_maxima = 100 # Variable GLOBAL
def verificar_temperatura(temp):
# Podemos LEER variables globales
if temp > temperatura_maxima:
return "Temperatura alta"
return "Temperatura normal"
print(verificar_temperatura(85)) # Temperatura normal
Modificar variables globales
contador = 0 # Variable global
def incrementar_contador():
global contador # Declarar que vamos a modificar la global
contador += 1
incrementar_contador()
incrementar_contador()
print(contador) # 2
⚠️ Consejo: Evitá usar global cuando sea posible. Es mejor pasar y retornar valores.
🏭 Ejemplos industriales prácticos
Ejemplo 1: Control de temperatura
def controlar_temperatura(temp_actual, temp_objetivo, tolerancia=2):
"""
Determina la acción a tomar según la temperatura
Args:
temp_actual: Temperatura medida
temp_objetivo: Temperatura deseada
tolerancia: Margen de error permitido
Returns:
str: Acción a realizar
"""
diferencia = temp_actual - temp_objetivo
if abs(diferencia) <= tolerancia:
return "✅ MANTENER - Temperatura óptima"
elif diferencia > 0:
return f"🔽 ENFRIAR - {diferencia}°C por encima"
else:
return f"🔼 CALENTAR - {abs(diferencia)}°C por debajo"
# Uso
print(controlar_temperatura(75, 75)) # MANTENER
print(controlar_temperatura(80, 75)) # ENFRIAR
print(controlar_temperatura(70, 75)) # CALENTAR
Ejemplo 2: Validación de sensores
def validar_lectura_sensor(valor, min_valido, max_valido):
"""
Valida si una lectura de sensor está en rango
Returns:
tuple: (es_valido, mensaje)
"""
if valor < min_valido:
return False, f"Valor muy bajo: {valor} < {min_valido}"
if valor > max_valido:
return False, f"Valor muy alto: {valor} > {max_valido}"
return True, "Lectura válida"
# Uso
valido, mensaje = validar_lectura_sensor(85, 0, 100)
print(f"{mensaje} - Válido: {valido}")
Ejemplo 3: Cálculo de consumo energético
def calcular_consumo_energia(potencia_watts, horas_uso, precio_kwh=0.15):
"""
Calcula el consumo y costo de energía
Args:
potencia_watts: Potencia del dispositivo en watts
horas_uso: Horas de uso
precio_kwh: Precio por kWh (default: $0.15)
Returns:
dict: Consumo en kWh y costo
"""
consumo_kwh = (potencia_watts * horas_uso) / 1000
costo = consumo_kwh * precio_kwh
return {
'consumo_kwh': round(consumo_kwh, 2),
'costo': round(costo, 2),
'horas': horas_uso
}
# Motor de 1500W funcionando 8 horas
resultado = calcular_consumo_energia(1500, 8)
print(f"Consumo: {resultado['consumo_kwh']} kWh")
print(f"Costo: ${resultado['costo']}")
🎨 Funciones lambda (avanzado - 4to año)
Las funciones lambda son funciones anónimas de una sola línea.
Sintaxis
# Función normal
def cuadrado(x):
return x ** 2
# Función lambda equivalente
cuadrado_lambda = lambda x: x ** 2
print(cuadrado(5)) # 25
print(cuadrado_lambda(5)) # 25
Uso con map, filter, sorted
# map: Aplicar función a cada elemento
numeros = [1, 2, 3, 4, 5]
cuadrados = list(map(lambda x: x**2, numeros))
print(cuadrados) # [1, 4, 9, 16, 25]
# filter: Filtrar elementos
pares = list(filter(lambda x: x % 2 == 0, numeros))
print(pares) # [2, 4]
# sorted: Ordenar con clave personalizada
sensores = [
{'id': 'TEMP-001', 'valor': 85},
{'id': 'TEMP-002', 'valor': 72},
{'id': 'TEMP-003', 'valor': 91}
]
ordenados = sorted(sensores, key=lambda s: s['valor'])
for sensor in ordenados:
print(f"{sensor['id']}: {sensor['valor']}")
📚 Funciones predefinidas útiles
Funciones matemáticas y numéricas
# abs: Valor absoluto
print(abs(-10)) # 10
# round: Redondear
print(round(3.14159, 2)) # 3.14
# pow: Potencia
print(pow(2, 3)) # 8
# sum: Suma de elementos
print(sum([1, 2, 3, 4, 5])) # 15
# min, max
print(min([5, 2, 8, 1])) # 1
print(max([5, 2, 8, 1])) # 8
Funciones de conversión
# int, float, str
print(int("42")) # 42
print(float("3.14")) # 3.14
print(str(100)) # "100"
# list, tuple, set
print(list("abc")) # ['a', 'b', 'c']
print(tuple([1, 2])) # (1, 2)
print(set([1, 1, 2])) # {1, 2}
Funciones para strings
texto = "Hola Mundo"
print(texto.upper()) # HOLA MUNDO
print(texto.lower()) # hola mundo
print(texto.title()) # Hola Mundo
print(texto.replace("Hola", "Chau")) # Chau Mundo
print(texto.split()) # ['Hola', 'Mundo']
print("-".join(['a', 'b', 'c'])) # a-b-c
Funciones para listas
lista = [3, 1, 4, 1, 5]
lista.append(9) # Agregar al final
lista.remove(1) # Eliminar primera ocurrencia
lista.sort() # Ordenar
lista.reverse() # Invertir
print(lista.count(1)) # Contar ocurrencias
print(lista.index(4)) # Índice de elemento
🎯 Ejercicios prácticos
🟢 Nivel Básico (3er año)
Ejercicio 1: Creá una función que calcule el área de un círculo dado su radio.
# Fórmula: área = π * radio²
# Usá 3.14159 para π
Ejercicio 2: Creá una función que determine si un número es par o impar.
Ejercicio 3: Creá una función que convierta temperatura de Celsius a Fahrenheit.
# Fórmula: F = (C × 9/5) + 32
🟡 Nivel Medio (3er y 4to año)
Ejercicio 4: Creá una función que reciba una lista de números y devuelva solo los números pares.
Ejercicio 5: Creá una función que calcule el factorial de un número.
Ejercicio 6: Creá una función que valide si una contraseña es segura (mínimo 8 caracteres, al menos una mayúscula, un número).
🔴 Nivel Avanzado (4to año)
Ejercicio 7: Creá una función que reciba una lista de sensores (diccionarios) y devuelva los que tienen lecturas fuera de rango.
Ejercicio 8: Creá una función que use *args y **kwargs para crear un reporte flexible.
Ejercicio 9: Implementá una función recursiva que calcule la secuencia de Fibonacci.
Ejercicio 10: Creá una función que use lambda para ordenar una lista de diccionarios por múltiples criterios.
💡 Buenas prácticas
✅ Hacé esto:
- Nombres descriptivos:
calcular_promedio()es mejor quecalc() - Una tarea por función: Cada función debe hacer una cosa bien
- Documentá con docstrings: Explicá qué hace, qué recibe, qué devuelve
- Usa type hints (Python 3.5+):
def sumar(a: int, b: int) -> int: return a + b - Validá los parámetros: Verificá que los datos sean correctos
- Retorná valores: Mejor que modificar variables globales
❌ Evitá esto:
- Funciones muy largas: Si tiene más de 50 líneas, dividila
- Muchos parámetros: Más de 5 parámetros es confuso
- Efectos secundarios ocultos: La función no debería modificar cosas inesperadas
- Nombres genéricos:
hacer_cosas(),procesar()no dicen nada
🐛 Errores comunes
Error 1: Olvidar el return
# ❌ Mal
def sumar(a, b):
resultado = a + b
# Falta return!
print(sumar(5, 3)) # None
# ✅ Bien
def sumar(a, b):
return a + b
print(sumar(5, 3)) # 8
Error 2: Modificar parámetros mutables
# ❌ Mal
def agregar_elemento(elemento, lista=[]):
lista.append(elemento)
return lista
print(agregar_elemento(1)) # [1]
print(agregar_elemento(2)) # [1, 2] ¡Sorpresa!
# ✅ Bien
def agregar_elemento(elemento, lista=None):
if lista is None:
lista = []
lista.append(elemento)
return lista
Error 3: Confundir parámetros posicionales
def dividir(dividendo, divisor):
return dividendo / divisor
# ❌ Mal (orden incorrecto)
print(dividir(2, 10)) # 0.2
# ✅ Bien
print(dividir(10, 2)) # 5.0
# O usar nombres
print(dividir(divisor=2, dividendo=10)) # 5.0
🎓 Resumen
✅ Funciones: Bloques de código reutilizables
✅ Parámetros: Datos que recibe la función
✅ Return: Valor que devuelve la función
✅ Scope: Alcance de las variables (local vs global)
✅ Lambda: Funciones anónimas de una línea (4to año)
✅ Buenas prácticas: Nombres claros, una tarea por función, documentación
🚀 Próximos pasos
Para 3er año:
- Practicá creando funciones simples
- Resolvé los ejercicios básicos y medios
- Experimentá con parámetros y return
Para 4to año:
- Dominá funciones lambda
- Practicá con *args y **kwargs
- Aprendé sobre decoradores
- Resolvé los ejercicios avanzados
¿Tenés dudas? ¡Preguntá en clase! 🙋♂️
¡Ahora a crear funciones increíbles! 💪🐍