- ¿Por qué evitar los bucles?
- Filtrar y obtener nombres de archivos Python
- Funciones como "piezas de Lego"
- Optimización y rendimiento
- Resumen
Las funciones de orden superior nos ayudan a escribir código más flexible y reutilizable. En lugar de repetir algoritmos una y otra vez, podemos definir una función general y luego especificar su comportamiento según la situación.
Esto se aplica a sorted(), map(), filter() y reduce(). Con ellas, podemos descomponer una tarea en pasos más pequeños y aplicar operaciones en cadena, como si los datos pasaran por una serie de transformaciones.
¿Por qué evitar los bucles?
En Python, el uso de cadenas de funciones como map(), filter(), sorted() es más común que los bucles tradicionales for. Esto se debe a que:
✔️ Hace el código más corto y claro.
✔️ Reduce errores, ya que cada función hace solo una tarea específica.
✔️ Permite combinar funciones fácilmente, como si fueran piezas de un Lego.
Filtrar y obtener nombres de archivos Python
Supongamos que tenemos una lista de archivos y queremos extraer los nombres de los que terminan en .py, sin importar si la extensión está en mayúsculas o minúsculas.
Para esto usaremos funciones de pathlib:
- pathlib.Path(filepath) → Crea un objeto de ruta.
- path.is_file() → Verifica si es un archivo.
- path.suffix → Obtiene la extensión del archivo.
- path.stem—→ Obtiene el nombre del archivo sin la extensión.
⏬ Solución usando un bucle:
import pathlib
def get_py_file_names(paths):
result = []
for filepath in paths:
path = pathlib.Path(filepath)
extension = path.suffix.lower()
if path.is_file() and extension == '.py':
result.append(path.stem.lower())
return result
# Ejemplo de uso
names = get_py_file_names(['app.py', 'test_app.py', 'README.md', 'config.json'])
print(names) # => ['app', 'test_app']
Paso a paso:
1️⃣ Recorremos cada archivo en paths.
2️⃣ Revisamos si es un archivo .py (sin importar mayúsculas/minúsculas).
3️⃣ Si cumple la condición, extraemos su nombre sin la extensión y lo agregamos a la lista.
Ahora, reescribamos este código usando funciones de orden superior.
⏬ Solución usando filter() y map()
import pathlib
# Función que verifica si un archivo es un .py
def is_py_file(path):
path_obj = pathlib.Path(path)
return path_obj.is_file() and path_obj.suffix.lower() == '.py'
def get_py_file_names(paths):
py_files = filter(is_py_file, paths) # Filtra solo archivos .py
return list(map(lambda path: pathlib.Path(path).stem.lower(), py_files))
# Extrae los nombres
names = get_py_file_names(['app.py', 'test_app.py', 'README.md', 'config.json'])
print(names) # => ['app', 'test_app']
Diferencias clave:
- En vez de usar for, filtramos con
filter(). - En vez de
append(), usamos map() para transformar los datos. - El código es más corto y más fácil de entender.
Funciones como "piezas de Lego"
🏗️ En programación, es útil tener funciones pequeñas que hagan solo una tarea. Como los bloques de Lego, podemos combinarlas para resolver problemas más grandes.
Las operaciones de filtrado (filter()), transformación (map()) y agregación (reduce()) se pueden encadenar fácilmente. Esto nos permite trabajar con datos de forma clara y estructurada.
⏬ Ejemplo:
Obtener el total de archivos .py en una lista de rutas:
from functools import reduce
import pathlib
paths = ['app.py', 'test_app.py', 'README.md', 'config.json']
# Filtrar archivos .py
py_files = filter(lambda path: pathlib.Path(path).suffix.lower() == '.py', paths)
# Contar la cantidad de archivos .py
total_py_files = reduce(lambda acc, _: acc + 1, py_files, 0)
print(total_py_files) # => 2
Optimización y rendimiento
Un detalle importante es el rendimiento. Cada vez que aplicamos una función a una lista (map(),filter(), sorted()), recorremos todos los elementos.
Pero en la mayoría de los casos, esto no es un problema, ya que la mayoría de los programas no manejan millones de elementos a la vez.
Ejemplo: La diferencia de tiempo al procesar listas de miles de elementos suele ser mínima.
Optimizando con evaluación diferida
En Python, map() y filter() no devuelven listas, sino iteradores. Esto significa que no procesan todos los datos de inmediato, sino que los generan solo cuando se necesitan.
from itertools import islice
users = [
{ 'name': 'Carlos', 'age': 19 },
{ 'name': 'Luis', 'age': 1 },
{ 'name': 'Mariana', 'age': 4 },
{ 'name': 'Sofía', 'age': 16 },
]
# Filtrar usuarios mayores de 10 años (iterador)
filtered_users = filter(lambda user: user['age'] > 10, users)
# Solo obtener los 2 primeros resultados
print(list(islice(filtered_users, 2)))
# => [{'name': 'Carlos', 'age': 19}, {'name': 'Sofía', 'age': 16}]
Ventajas de usar iteradores:
✔️ Menos consumo de memoria, ya que los datos no se almacenan en una lista.
✔️ Mayor velocidad en grandes volúmenes de datos.
Resumen
- Usa
map(),filter()yreduce()para procesar listas de manera más clara y concisa. - Piensa en tu código como una serie de pasos pequeños, como bloques de Lego.
- Aprovecha los iteradores para mejorar el rendimiento en listas grandes.
Practica dividiendo problemas en pasos más pequeños y usando funciones de orden superior para resolverlos.
Materiales adicionales
Para acceder completo a curso necesitas un plan básico
El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.