Una función es un bloque de código con nombre que puedes reutilizar. Es la herramienta número uno para no repetirte y para organizar programas grandes.
Definir y llamar
def saludar():
print("¡Hola!")
saludar() # ¡Hola!
saludar() # ¡Hola! → cuantas veces quieras
defdefine la función- Los paréntesis son obligatorios (aquí van los parámetros)
- El cuerpo va indentado
- La función solo se ejecuta cuando la llamas con
()
Parámetros y return
def sumar(a, b):
return a + b
resultado = sumar(3, 5)
print(resultado) # 8
return entrega un valor a quien llamó. Sin return explícito, toda función devuelve None:
def saludar():
print("hola")
x = saludar()
print(x) # None ← print no es return
Diferencia clave: print muestra en pantalla; return entrega el valor para que el programa lo use.
Parámetros con valor por defecto
def saludar(nombre="mundo"):
return f"Hola, {nombre}"
print(saludar()) # Hola, mundo
print(saludar("Ana")) # Hola, Ana
Argumentos por nombre (keyword arguments)
def crear_perfil(nombre, edad, ciudad):
return f"{nombre}, {edad}, {ciudad}"
# por posición:
crear_perfil("Ana", 25, "Bogotá")
# por nombre — el orden da igual:
crear_perfil(edad=25, ciudad="Bogotá", nombre="Ana")
*args y **kwargs
A veces no sabes cuántos argumentos recibirás:
def sumar_todos(*numeros):
# numeros llega como una TUPLA
return sum(numeros)
print(sumar_todos(1, 2)) # 3
print(sumar_todos(1, 2, 3, 4)) # 10
def mostrar_perfil(**datos):
# datos llega como un DICT
for clave, valor in datos.items():
print(f"{clave}: {valor}")
mostrar_perfil(nombre="Ana", edad=25)
*argsagrupa argumentos posicionales extra en una tupla**kwargsagrupa argumentos nombrados extra en un dict
Scope: dónde vive una variable
variable_global = "soy global"
def mi_funcion():
variable_local = "solo existo dentro"
print(variable_global) # sí puede leer globals
mi_funcion()
print(variable_local) # NameError: no existe fuera
Regla de oro: evita modificar globales desde una función. Recibe lo que necesites por parámetros y devuelve resultados con return — funciones así son fáciles de probar y entender.
Lambda: funciones anónimas de una línea
Una función lambda es una función pequeña, anónima (sin nombre obligatorio) definida en una sola expresión con la sintaxis:
lambda parametro1, parametro2: expresion_retornada
No lleva la palabra return; evalúa automáticamente la expresión a la derecha de los dos puntos y la devuelve:
duplicar = lambda x: x * 2
print(duplicar(5)) # 10
sumar = lambda a, b: a + b
print(sumar(2, 3)) # 5
¿Cuándo usar lambdas? El trío de oro: sorted, map y filter
Asignar una lambda a una variable (f = lambda x: ...) se considera mala práctica según PEP 8; para eso es mejor def f(x): .... El verdadero propósito de una función lambda es ser una función desechable (callback) que pasas como argumento a funciones de orden superior.
1. Ordenamiento avanzado con sorted() y key=lambda
sorted() acepta un parámetro clave key que transforma cada elemento antes de compararlo:
# Ordenar diccionarios por un campo específico
usuarios = [
{"nombre": "Carlos", "edad": 30, "puntos": 85},
{"nombre": "Ana", "edad": 22, "puntos": 95},
{"nombre": "Beatriz", "edad": 28, "puntos": 90},
]
# Ordenar por edad ascendente
por_edad = sorted(usuarios, key=lambda u: u["edad"])
print([u["nombre"] for u in por_edad]) # ['Ana', 'Beatriz', 'Carlos']
# Ordenar por puntos descendente (mayor a menor)
por_puntos = sorted(usuarios, key=lambda u: u["puntos"], reverse=True)
print([u["nombre"] for u in por_puntos]) # ['Ana', 'Beatriz', 'Carlos']
# Criterios múltiples con tuplas: primero por longitud, luego alfabético
palabras = ["pera", "manzana", "kiwi", "uva", "higo"]
ordenadas = sorted(palabras, key=lambda p: (len(p), p))
print(ordenadas) # ['uva', 'higo', 'kiwi', 'pera', 'manzana']
2. Transformar elementos con map()
map(funcion, iterable) aplica la función a cada elemento y devuelve un iterador perezoso:
precios_cop = [10000, 25000, 50000]
# Aplicar 19% de IVA
con_iva = list(map(lambda p: round(p * 1.19), precios_cop))
print(con_iva) # [11900, 29750, 59500]
# Mapear sobre múltiples iterables a la vez
bases = [2, 3, 4]
exponentes = [3, 2, 2]
potencias = list(map(lambda b, e: b ** e, bases, exponentes))
print(potencias) # [8, 9, 16]
3. Filtrar colecciones con filter()
filter(predicado, iterable) conserva solo los elementos para los cuales la función devuelve True:
edades = [12, 17, 18, 25, 14, 30]
# Filtrar solo mayores de edad
mayores = list(filter(lambda e: e >= 18, edades))
print(mayores) # [18, 25, 30]
# Filtrar correos válidos simples
correos = ["test@mail.com", "invalido", "admin@empresa.co", "spam@"]
validos = list(filter(lambda c: "@" in c and "." in c.split("@")[-1], correos))
print(validos) # ['test@mail.com', 'admin@empresa.co']
4. Encadenar el pipeline: filter + map + sorted
Podemos encadenar estas operaciones para construir pipelines de procesamiento limpios y declarativos:
estudiantes = [
{"nombre": "Luisa", "nota": 4.5, "activo": True},
{"nombre": "Mario", "nota": 2.8, "activo": True},
{"nombre": "Diana", "nota": 4.8, "activo": False}, # inactiva
{"nombre": "Camilo", "nota": 3.9, "activo": True},
]
# Paso 1: Filtrar solo estudiantes activos aprobados (nota >= 3.0)
activos_aprobados = filter(lambda e: e["activo"] and e["nota"] >= 3.0, estudiantes)
# Paso 2: Transformar a string legible "Nombre: Nota"
etiquetas = map(lambda e: f"{e['nombre']} (Nota: {e['nota']})", activos_aprobados)
# Paso 3: Ordenar por nota descendente directamente con sorted
top = sorted(
filter(lambda e: e["activo"] and e["nota"] >= 3.0, estudiantes),
key=lambda e: e["nota"],
reverse=True
)
print([e["nombre"] for e in top]) # ['Luisa', 'Camilo']
Nota de arquitectura Pythonica: Aunque map y filter son muy populares en lenguajes como JavaScript o Scala, en Python moderno muchas veces se prefiere la sintaxis de list comprehensions por ser más legible:
# Equivalente comprehension: [transformacion for x in iterable if condicion]
aprobados = [f"{e['nombre']} (Nota: {e['nota']})" for e in estudiantes if e["activo"] and e["nota"] >= 3.0]
Sin embargo, sorted(..., key=lambda ...) sigue siendo la forma reina e indiscutible para ordenamiento personalizado en todo el ecosistema de Python.
Resumen
def nombre(parametros):define;nombre(argumentos)llamareturnentrega el valor; sin él, la función devuelveNone- Valores por defecto y argumentos nombrados hacen APIs flexibles
*argstupla,**kwargsdict- Variables locales mueren con la función; no toques globales
lambdapara expresiones de una línea (especialmente comokey)