Funciones en Python: def, parámetros, return y scope explicados
- Por qué las funciones cambian la forma de programar
- Definir y llamar una función: def y return
- Parámetros: obligatorios, por defecto y con nombre
- *args y **kwargs: número variable de argumentos
- return: qué puede devolver una función
- Scope: dónde viven las variables
- Docstrings: documentar el código que escribes
- Funciones lambda: anónimas de una línea
- Funciones de orden superior: map(), filter() y sorted()
- Programa completo: calculadora con historial
- Errores clásicos con funciones
- Preguntas frecuentes
Hasta ahora cada programa que has escrito ha sido una secuencia lineal de instrucciones. Eso funciona para scripts pequeños, pero en cuanto el programa crece aparece un problema: repites el mismo código en varios sitios, y cuando hay que corregir algo tienes que encontrarlo y cambiarlo en cada uno. Las funciones resuelven exactamente ese problema.
Una función es un bloque de código con nombre que puedes invocar cuantas veces quieras. Le das unos datos (parámetros), hace algo con ellos, y opcionalmente devuelve un resultado. El código queda organizado, reutilizable y mucho más fácil de mantener.
🔧 Definir y llamar una función: def y return
Para definir una función usas la palabra clave def, seguida del nombre, los parámetros entre paréntesis y dos puntos. El cuerpo va indentado. return devuelve el resultado al punto donde se llamó.
# Función sin parámetros
def saludar():
print("¡Hola, mundo!")
saludar() # → ¡Hola, mundo!
saludar() # reutilizable
# Función con parámetro y return
def doblar(numero):
return numero * 2
resultado = doblar(5)
print(resultado) # → 10
# Return directo de expresión booleana
def es_par(n):
return n % 2 == 0
print(es_par(4)) # → True
print(es_par(7)) # → False
⚙️ Parámetros: obligatorios, por defecto y con nombre
# Parámetros con valor por defecto
def saludar(nombre, saludo="Hola"):
return f"{saludo}, {nombre}!"
saludar("Ana") # → "Hola, Ana!"
saludar("Ana", "Buenos días") # → "Buenos días, Ana!"
# Argumentos por nombre (keyword arguments)
def crear_usuario(nombre, edad, ciudad="Madrid"):
return {"nombre": nombre, "edad": edad, "ciudad": ciudad}
crear_usuario("Ana", 28)
crear_usuario(edad=28, nombre="Ana") # orden libre
crear_usuario("Ana", 28, ciudad="Bilbao")
# ❌ La lista se comparte entre llamadas
def añadir(elemento, lista=[]):
lista.append(elemento)
return lista
# ✅ Usar None como centinela
def añadir(elemento, lista=None):
if lista is None:
lista = []
lista.append(elemento)
return lista
📦 *args y **kwargs: número variable de argumentos
# *args: extras posicionales como tupla
def sumar(*numeros):
return sum(numeros)
sumar(1, 2) # → 3
sumar(1, 2, 3, 4, 5) # → 15
# **kwargs: extras con nombre como diccionario
def presentar(**datos):
for clave, valor in datos.items():
print(f" {clave}: {valor}")
presentar(nombre="Ana", edad=28, ciudad="Madrid")
# Desempaquetar al llamar:
args = [2, 10]
potencia(*args) # equivale a potencia(2, 10)
kwargs = {"base": 3, "exp": 3}
potencia(**kwargs) # equivale a potencia(base=3, exp=3)
↩️ return: qué puede devolver una función
# Return múltiple (devuelve una tupla)
def min_max(lista):
return min(lista), max(lista)
minimo, maximo = min_max([3, 1, 7, 2, 9])
print(minimo, maximo) # → 1 9
# Early return para simplificar lógica
def dividir(a, b):
if b == 0:
return None
return a / b
print(dividir(10, 2)) # → 5.0
print(dividir(10, 0)) # → None
🔭 Scope: dónde viven las variables
Python aplica la regla LEGB: Local → Enclosing → Global → Built-in. Las variables definidas dentro de una función son locales y no afectan al exterior.
x = 10 # GLOBAL
def mi_funcion():
x = 99 # LOCAL — no toca la global
print(x) # → 99
mi_funcion()
print(x) # → 10
# Para modificar la global:
contador = 0
def incrementar():
global contador
contador += 1
# Mejor sin global: pasar como parámetro y devolver
def incrementar(c):
return c + 1
contador = incrementar(contador)
📝 Docstrings: documenta lo que escribes
def calcular_imc(peso_kg, altura_m):
"""
Calcula el Índice de Masa Corporal (IMC).
Args:
peso_kg (float): Peso en kilogramos.
altura_m (float): Altura en metros.
Returns:
float: El IMC redondeado a 2 decimales.
Raises:
ValueError: Si la altura es cero o negativa.
"""
if altura_m <= 0:
raise ValueError("La altura debe ser positiva.")
return round(peso_kg / altura_m ** 2, 2)
help(calcular_imc) # muestra la documentación
calcular_imc(70, 1.75) # → 22.86
⚡ Funciones lambda: anónimas de una línea
# Equivalencia lambda / def
doblar = lambda x: x * 2
doblar(5) # → 10
# Uso más habitual: key= en sorted(), min(), max()
personas = [
{"nombre": "Marta", "edad": 22},
{"nombre": "Luis", "edad": 34},
{"nombre": "Ana", "edad": 28},
]
por_edad = sorted(personas, key=lambda p: p["edad"])
mas_joven = min(personas, key=lambda p: p["edad"])
print(mas_joven["nombre"]) # → Marta
🎛️ Funciones de orden superior: map(), filter() y sorted()
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# map(): transformar cada elemento
cuadrados = list(map(lambda x: x**2, numeros))
# equivalente moderno: [x**2 for x in numeros]
# filter(): filtrar por condición
pares = list(filter(lambda x: x % 2 == 0, numeros))
# equivalente: [x for x in numeros if x % 2 == 0]
# Closure: función que devuelve otra función
def multiplicador(factor):
def multiplicar(x):
return x * factor
return multiplicar
triple = multiplicador(3)
print(triple(7)) # → 21
🛠️ Programa completo: calculadora con historial
def operar(a, b, op):
"""Realiza una operación aritmética entre dos números."""
ops = {
"+": lambda x, y: x + y,
"-": lambda x, y: x - y,
"*": lambda x, y: x * y,
"/": lambda x, y: x / y if y != 0 else None,
"**": lambda x, y: x ** y,
"%": lambda x, y: x % y,
}
if op not in ops:
raise ValueError(f"Operación '{op}' no reconocida.")
return ops[op](a, b)
def pedir_numero(mensaje):
"""Pide un número flotante con validación."""
while True:
try:
return float(input(mensaje))
except ValueError:
print(" Introduce un número válido.")
historial = []
print("=== CALCULADORA === (escribe 'salir' o 'historial')\n")
while True:
cmd = input("Comando: ").strip().lower()
if cmd == "salir":
print(f"Sesión terminada. {len(historial)} operaciones.")
break
elif cmd == "historial":
for i, (a, op, b, r) in enumerate(historial, 1):
print(f" {i}. {a} {op} {b} = {r if r is not None else 'ERROR'}")
continue
try:
a = pedir_numero(" Primer número: ")
op = input(" Operador: ").strip()
b = pedir_numero(" Segundo número: ")
r = operar(a, b, op)
print(f" = {r if r is not None else 'División por cero'}")
historial.append((a, op, b, r))
except ValueError as e:
print(f" {e}")
🐛 Errores clásicos con funciones
1. Usar el resultado de una función que devuelve None
lista = [3, 1, 2]
lista_ordenada = lista.sort() # sort() devuelve None
print(lista_ordenada) # → None
lista_ordenada = sorted(lista) # sorted() devuelve lista nueva ✅
2. Confundir print() con return
def doblar(x):
print(x * 2) # imprime pero NO devuelve
resultado = doblar(5) # imprime 10
print(resultado) # → None
def doblar(x):
return x * 2 # ✅
3. Llamar sin paréntesis
print(saludar) # → (objeto función)
print(saludar()) # → "Hola" ✅
✅ Resumen y próximos pasos
Con def defines funciones reutilizables. Los parámetros pueden ser obligatorios, tener valor por defecto, o recoger extras con *args / **kwargs. return devuelve uno o varios valores. Las variables locales no afectan al exterior. Las docstrings documentan la función. Y lambda es para funciones simples de una línea como argumento de sorted() o map().
La siguiente lección: estructuras de datos — listas, tuplas, diccionarios y conjuntos.
❓ Preguntas frecuentes
❓ Preguntas frecuentes sobre Funciones en Python: def, parámetros, return y scope explicados
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre Funciones en Python: def, parámetros, return y scope explicados? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!