Módulo BASICOLección 10 de 12

Funciones

Empaqueta lógica reutilizable: parámetros, return, *args y lambda.

01

Teoría y Fundamentos

Lee y asimila los conceptos clave antes de evaluar

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
  • def define 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)
  • *args agrupa argumentos posicionales extra en una tupla
  • **kwargs agrupa 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) llama
  • return entrega el valor; sin él, la función devuelve None
  • Valores por defecto y argumentos nombrados hacen APIs flexibles
  • *args tupla, **kwargs dict
  • Variables locales mueren con la función; no toques globales
  • lambda para expresiones de una línea (especialmente como key)

¿Terminaste de leer la teoría?

Marca este paso para registrar tu avance y saltar a las preguntas

02

Quiz de Comprobación

3 preguntas de comprensión rápida (requiere 70% para aprobar)

  1. 1

    ¿Qué devuelve una función que termina sin ejecutar ningún return?

  2. 2

    Dentro de una función, ¿qué tipo de dato recibe el parámetro *args?

  3. 3

    ¿Cuál es la forma correcta de una función con parámetro por defecto?

03

Laboratorio de Código Python

2 ejercicios interactivos ejecutados en tu navegador

EJERCICIO 01Python 3.12

Números primos

Completa la función para que devuelva True si n es primo y False si no. Un primo solo es divisible por 1 y por sí mismo.

ejercicio_1.py
Tab: 4 spaces

Iniciando editor de código…

Ctrl/Cmd + Enter para ejecutar
EJERCICIO 02Python 3.12

Fibonacci

Completa la función para que devuelva una lista con los primeros n números de Fibonacci: fibonacci(5) → [0, 1, 1, 2, 3]

ejercicio_2.py
Tab: 4 spaces

Iniciando editor de código…

Ctrl/Cmd + Enter para ejecutar