Objetivos de Aprendizaje
Al finalizar esta clase, serás capaz de:
- Crear y manipular listas (agregar, eliminar, buscar elementos)
- Usar diccionarios para almacenar datos con clave-valor
- Entender tuplas (inmutables) y sets (únicos)
- Elegir la estructura correcta según el caso
- Crear un sistema de gestión de contactos para TaskFlow
Listas [ ] (25 min)
Las listas son colecciones ordenadas y modificables.
Crear y Acceder
# Crear listas
frutas = ["manzana", "banana", "naranja"]
numeros = [10, 20, 30, 40, 50]
mixta = [1, "hola", 3.14, True]
# Acceder por índice (empieza en 0)
print(frutas[0]) # "manzana"
print(frutas[1]) # "banana"
print(frutas[-1]) # "naranja" (último)
# Modificar
frutas[0] = "pera" # ["pera", "banana", "naranja"]
# Slicing [inicio:fin]
print(numeros[1:4]) # [20, 30, 40]
print(numeros[:3]) # [10, 20, 30] (desde inicio)
print(numeros[2:]) # [30, 40, 50] (hasta final)
print(numeros[::2]) # [10, 30, 50] (cada 2)
# Longitud
cantidad = len(frutas) # 3
Métodos Importantes
# Agregar elementos
frutas.append("uva") # Agrega al final
frutas.insert(1, "mango") # Inserta en posición 1
frutas.extend(["kiwi", "limón"]) # Agrega varios
# Eliminar elementos
frutas.remove("banana") # Elimina el primero que encuentra
ultimo = frutas.pop() # Elimina y retorna el último
primero = frutas.pop(0) # Elimina y retorna el primero
del frutas[0] # Elimina por índice
# Buscar
if "manzana" in frutas:
posicion = frutas.index("manzana") # Índice del elemento
cantidad = frutas.count("manzana") # Cuántas veces aparece
# Ordenar
numeros.sort() # Ordena ascendente (modifica la lista)
numeros.sort(reverse=True) # Ordena descendente
nombres = sorted(frutas) # Retorna nueva lista ordenada
Iterar sobre Listas
usuarios = ["ana", "juan", "maria"]
# For simple
for usuario in usuarios:
print(usuario)
# Con índice
for i in range(len(usuarios)):
print(f"{i}: {usuarios[i]}")
# Con enumerate (recomendado)
for i, usuario in enumerate(usuarios, 1):
print(f"{i}. {usuario}")
# Filtrar
mayores = []
for edad in [15, 22, 18, 30, 12]:
if edad >= 18:
mayores.append(edad)
print(mayores) # [22, 18, 30]
Ejercicio Rápido 1: Manipulación de Listas (5 min)
Crea una lista de tus 5 comidas favoritas y practica:
- Agrega una nueva comida al final
- Inserta una comida en la posición 2
- Elimina la última comida
- Ordena la lista alfabéticamente
- Muestra solo las primeras 3 comidas
Diccionarios { } (25 min)
Los diccionarios almacenan pares clave: valor.
Crear y Acceder
# Crear diccionario
usuario = {
"nombre": "Juan",
"email": "juan@email.com",
"edad": 25,
"activo": True
}
# Acceder por clave
print(usuario["nombre"]) # "Juan"
print(usuario["email"]) # "juan@email.com"
# get() - Más seguro (no da error si no existe)
print(usuario.get("nombre")) # "Juan"
print(usuario.get("telefono")) # None (no error)
print(usuario.get("telefono", "N/A")) # "N/A" (valor por defecto)
# Modificar y Agregar
usuario["edad"] = 26 # Modificar
usuario["pais"] = "Colombia" # Agregar nueva clave
# Eliminar
del usuario["pais"] # Eliminar clave
email = usuario.pop("email") # Eliminar y obtener valor
Métodos Útiles
# Obtener claves, valores o ambos
claves = usuario.keys() # dict_keys(['nombre', 'edad', 'activo'])
valores = usuario.values() # dict_values(['Juan', 26, True])
items = usuario.items() # dict_items([('nombre', 'Juan'), ...])
# Iterar
for clave in usuario:
print(f"{clave}: {usuario[clave]}")
# Iterar con items()
for clave, valor in usuario.items():
print(f"{clave}: {valor}")
# Verificar existencia
if "nombre" in usuario:
print("Tiene nombre")
# Actualizar con otro diccionario
usuario.update({"ciudad": "Bogotá", "edad": 27})
# Copiar
usuario_copia = usuario.copy() # O dict(usuario)
Lista de Diccionarios
# Lista de usuarios (cada uno es un diccionario)
usuarios = [
{"nombre": "Ana", "edad": 25, "activo": True},
{"nombre": "Juan", "edad": 30, "activo": False},
{"nombre": "María", "edad": 22, "activo": True}
]
# Filtrar usuarios activos
activos = []
for u in usuarios:
if u["activo"]:
activos.append(u)
# Mostrar solo nombres de activos
print("Usuarios activos:")
for u in activos:
print(f" - {u['nombre']}")
# Calcular edad promedio
total_edades = 0
for u in usuarios:
total_edades += u["edad"]
promedio = total_edades / len(usuarios)
print(f"Edad promedio: {promedio}")
Ejercicio Rápido 2: Agenda Telefónica (5 min)
Crea una agenda telefónica:
- Crea un diccionario vacío
agenda = {}
- Agrega 3 contactos (nombre → teléfono)
- Busca un contacto por nombre
- Actualiza el teléfono de un contacto
- Elimina un contacto
Desafío: Usa .get() para buscar un contacto que no existe y mostrar "No encontrado".
GitHub: Subir Código a la Nube (20 min)
Ahora que tienes commits locales, es momento de subirlos a GitHub.
1. Conectar tu Repo Local con GitHub
# Ver la URL de tu repo en GitHub (botón verde "Code")
# Luego en tu terminal local:
# Agregar remoto (reemplaza con tu URL)
git remote add origin https://github.com/tuusuario/poo2-practicas.git
# Verificar que se agregó
git remote -v
2. Subir Código (Push)
# Subir tus commits a GitHub
git push -u origin main
# En el futuro, solo necesitarás:
git push
3. Clonar un Repositorio
# Descargar un repo existente de GitHub
git clone https://github.com/usuario/repo.git
# Entrar a la carpeta
cd repo
# Ver los commits
git log --oneline
Ejercicio Práctico: Sube tu Código (15 min)
Completa el flujo Git → GitHub:
- Asegúrate de tener commits locales de la clase anterior
- En GitHub, copia la URL HTTPS de tu repo
- En terminal:
git remote add origin TU_URL - Verifica:
git remote -v - Sube código:
git push -u origin main - Ve a GitHub y verifica que tus archivos aparecen
- En GitHub, edita el README.md agregando tu nombre
- En terminal local:
git pullpara descargar el cambio
4. Flujo de Trabajo Completo
# Tu día a día con Git:
# 1. Trabajar en tu código
...
# 2. Ver qué cambió
git status
git diff
# 3. Preparar cambios
git add .
# 4. Guardar versión
git commit -m "feat: nuevo sistema de inventario"
# 5. Subir a GitHub
git push
# 6. Si alguien más modificó el código
git pull
5. README.md Profesional
El archivo README es la carta de presentación de tu proyecto:
# POO2 - Prácticas
Repositorio de prácticas de Programación Orientada a Objetos II.
## 📁 Estructura
```
clase-01/ # Estructuras de control
clase-02/ # Estructuras de datos
clase-03/ # Clases y objetos
```
## 🚀 Cómo ejecutar
```bash
python clase-01/sistema_usuarios.py
```
## 📚 Contenido
- Clase 1: Condicionales y bucles
- Clase 2: Listas, diccionarios, tuplas
- Clase 3: POO con Python
## ✏️ Autor
[Tu Nombre] - 2026
Ejercicio: Mejora tu README (10 min)
Edita tu README.md para que sea profesional:
- Cambia el título y agrega descripción
- Agrega sección de estructura de carpetas
- Agrega instrucciones de ejecución
- Agrega tu nombre al final
- Guarda, commit y push
git remote add origin URL- Conectar con GitHubgit push -u origin main- Subir primera vezgit push- Subir cambiosgit pull- Descargar cambiosgit clone URL- Descargar repo nuevo
Tuplas y Sets (10 min)
Tuplas ( ) - Inmutables
No se pueden modificar después de crearlas. Útiles para datos constantes.
# Crear tupla
coordenadas = (10, 20)
rgb = (255, 128, 0)
# Acceder
print(coordenadas[0]) # 10
x, y = coordenadas # Desempaquetado
# NO se puede modificar
# coordenadas[0] = 5 # ¡Error!
# Usos típicos: retornar múltiples valores, datos fijos
def obtener_min_max(numeros):
return (min(numeros), max(numeros))
minimo, maximo = obtener_min_max([3, 1, 4, 1, 5])
print(f"Mín: {minimo}, Máx: {maximo}")
Sets { } - Elementos Únicos
No permiten duplicados. Útiles para eliminar repetidos.
# Crear set
numeros = {1, 2, 3, 4, 5}
# Desde lista (elimina duplicados)
con_duplicados = [1, 2, 2, 3, 3, 3]
unicos = set(con_duplicados) # {1, 2, 3}
# Operaciones
unicos.add(6) # Agregar
unicos.remove(3) # Eliminar (error si no existe)
unicos.discard(10) # Eliminar (sin error si no existe)
# Operaciones matemáticas
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
union = a | b # {1, 2, 3, 4, 5, 6}
interseccion = a & b # {3, 4}
diferencia = a - b # {1, 2}
# Verificar pertenencia
if 2 in a:
print("2 está en el set")
Ejercicio Rápido 3: Sets y Tuplas (5 min)
Resuelve estos problemas:
- Tuplas: Crea una tupla con las coordenadas (x, y) de un punto. Intenta modificarla y observa el error.
- Sets: Tienes dos listas de estudiantes de dos cursos diferentes. Usa sets para encontrar:
- Estudiantes que están en ambos cursos (intersección)
- Estudiantes que solo están en el primer curso (diferencia)
- Todos los estudiantes únicos (unión)
¿Cuándo usar cada uno?
- Lista [ ]: Colección ordenada y modificable (usuarios, tareas)
- Diccionario { }: Datos con propiedades (usuario con nombre, email, edad)
- Tupla ( ): Datos inmutables (coordenadas, configuraciones)
- Set { }: Eliminar duplicados, operaciones matemáticas
Laboratorio 1: Gestor de Contactos Mejorado (25 min)
Sistema completo usando listas y diccionarios con validaciones y categorías (base para TaskFlow).
# contactos.py
contactos = []
categorias_validas = {"amigo", "familia", "trabajo", "otro"}
def validar_email(email):
"""Valida que el email contenga @ y ."""
return "@" in email and "." in email
def agregar_contacto(nombre, telefono, email, categoria="otro"):
"""Agrega un contacto nuevo con validaciones."""
# Validaciones
if not nombre.strip():
print("❌ El nombre no puede estar vacío")
return False
if not validar_email(email):
print("❌ Email inválido. Debe contener @ y punto")
return False
if categoria.lower() not in categorias_validas:
print(f"❌ Categoría inválida. Opciones: {', '.join(categorias_validas)}")
return False
# Verificar duplicado por email
for c in contactos:
if c["email"].lower() == email.lower():
print("❌ Ya existe un contacto con ese email")
return False
contacto = {
"nombre": nombre,
"telefono": telefono,
"email": email,
"categoria": categoria.lower()
}
contactos.append(contacto)
print(f"✅ Contacto '{nombre}' agregado correctamente.")
return True
def mostrar_contactos(filtrar_categoria=None):
"""Muestra contactos, opcionalmente filtrados por categoría."""
if not contactos:
print("📭 No hay contactos registrados.")
return
contactos_mostrar = contactos
if filtrar_categoria:
contactos_mostrar = [c for c in contactos if c["categoria"] == filtrar_categoria]
if not contactos_mostrar:
print(f"📭 No hay contactos en la categoría '{filtrar_categoria}'")
return
print("\n" + "="*60)
print(f"{'N°':<4} {'NOMBRE':<20} {'TELÉFONO':<15} {'CATEGORÍA'}")
print("="*60)
for i, c in enumerate(contactos_mostrar, 1):
print(f"{i:<4} {c['nombre']:<20} {c['telefono']:<15} {c['categoria']}")
print(f" 📧 {c['email']}")
print("="*60)
print(f"Total: {len(contactos_mostrar)} contacto(s)")
def buscar_contacto(termino):
"""Busca contactos por nombre, teléfono o email."""
if not contactos:
print("📭 No hay contactos registrados")
return
termino = termino.lower()
encontrados = []
for c in contactos:
if (termino in c["nombre"].lower() or
termino in c["telefono"] or
termino in c["email"].lower()):
encontrados.append(c)
if encontrados:
print(f"\n🔍 {len(encontrados)} resultado(s) para '{termino}':")
for c in encontrados:
print(f" • {c['nombre']} ({c['categoria']})")
else:
print(f"❌ No se encontraron resultados para '{termino}'")
def eliminar_contacto(email):
"""Elimina un contacto por email."""
for i, c in enumerate(contactos):
if c["email"].lower() == email.lower():
confirmar = input(f"¿Eliminar a {c['nombre']}? (s/n): ")
if confirmar.lower() == 's':
contactos.pop(i)
print(f"✅ Contacto '{c['nombre']}' eliminado")
return True
else:
print("Cancelado")
return False
print(f"❌ No se encontró contacto con email '{email}'")
return False
def mostrar_estadisticas():
"""Muestra estadísticas de los contactos."""
if not contactos:
print("📭 No hay datos para estadísticas")
return
total = len(contactos)
print("\n" + "="*40)
print("📊 ESTADÍSTICAS")
print("="*40)
print(f"Total de contactos: {total}")
# Contar por categoría
conteo = {}
for c in contactos:
cat = c["categoria"]
conteo[cat] = conteo.get(cat, 0) + 1
print("\nPor categoría:")
for cat, cantidad in sorted(conteo.items()):
porcentaje = (cantidad / total) * 100
print(f" • {cat.capitalize():<12}: {cantidad:>2} ({porcentaje:.1f}%)")
print("="*40)
# Programa principal
while True:
print("\n" + "="*50)
print("📒 GESTOR DE CONTACTOS")
print("="*50)
print("1. Agregar contacto")
print("2. Ver todos los contactos")
print("3. Filtrar por categoría")
print("4. Buscar contacto")
print("5. Eliminar contacto")
print("6. Estadísticas")
print("7. Salir")
opcion = input("\nSelecciona una opción: ")
if opcion == "1":
nombre = input("Nombre: ").strip()
telefono = input("Teléfono: ").strip()
email = input("Email: ").strip()
print(f"Categorías disponibles: {', '.join(categorias_validas)}")
categoria = input("Categoría (Enter para 'otro'): ").strip() or "otro"
agregar_contacto(nombre, telefono, email, categoria)
elif opcion == "2":
mostrar_contactos()
elif opcion == "3":
print(f"Categorías: {', '.join(categorias_validas)}")
cat = input("Filtrar por categoría: ").strip().lower()
mostrar_contactos(filtrar_categoria=cat)
elif opcion == "4":
termino = input("Buscar (nombre, teléfono o email): ").strip()
buscar_contacto(termino)
elif opcion == "5":
email = input("Email del contacto a eliminar: ").strip()
eliminar_contacto(email)
elif opcion == "6":
mostrar_estadisticas()
elif opcion == "7":
print("👋 ¡Hasta luego!")
break
else:
print("❌ Opción no válida")
Conexión con TaskFlow: Este sistema es la base del proyecto. En las siguientes clases agregaremos: clases, validaciones más avanzadas, persistencia en archivos y base de datos.
Retos Adicionales
- Validación avanzada: Verifica que el email tenga formato válido (texto@dominio.com)
- Ordenamiento: Permite ordenar contactos por nombre o categoría
- Exportar: Guarda los contactos en un archivo CSV
- Editar: Permite modificar datos de un contacto existente
Laboratorio 2: Sistema de Inventario (25 min)
Gestiona un inventario de productos usando listas de diccionarios con funcionalidades avanzadas.
Requisitos
- Registrar productos con: nombre, categoría, precio, cantidad, código único
- Calcular valor total del inventario (precio × cantidad)
- Identificar productos con bajo stock (< 5 unidades)
- Buscar productos por nombre o categoría
- Actualizar cantidad de productos (entradas y salidas)
- Generar alertas de stock mínimo
Código Base
# inventario.py
print("📦 SISTEMA DE INVENTARIO 📦\n")
inventario = []
id_contador = 1
def generar_id():
"""Genera un ID único para cada producto."""
global id_contador
id_actual = f"PROD-{id_contador:04d}"
id_contador += 1
return id_actual
def agregar_producto(nombre, categoria, precio, cantidad):
"""Agrega un nuevo producto al inventario."""
if precio <= 0 or cantidad < 0:
print("❌ Precio y cantidad deben ser positivos")
return None
producto = {
"id": generar_id(),
"nombre": nombre,
"categoria": categoria,
"precio": precio,
"cantidad": cantidad
}
inventario.append(producto)
print(f"✅ Producto '{nombre}' agregado con ID: {producto['id']}")
return producto
def calcular_valor_inventario():
"""Calcula el valor total del inventario."""
total = 0
for p in inventario:
total += p["precio"] * p["cantidad"]
return total
def productos_bajo_stock(limite=5):
"""Retorna lista de productos con stock bajo."""
return [p for p in inventario if p["cantidad"] < limite]
def buscar_producto(termino):
"""Busca productos por nombre o categoría."""
termino = termino.lower()
resultados = []
for p in inventario:
if termino in p["nombre"].lower() or termino in p["categoria"].lower():
resultados.append(p)
return resultados
def actualizar_stock(id_producto, cantidad, es_entrada=True):
"""Actualiza el stock de un producto."""
for p in inventario:
if p["id"] == id_producto:
if es_entrada:
p["cantidad"] += cantidad
print(f"✅ Entrada: {cantidad} unidades de {p['nombre']}")
else:
if p["cantidad"] >= cantidad:
p["cantidad"] -= cantidad
print(f"✅ Salida: {cantidad} unidades de {p['nombre']}")
else:
print(f"❌ Stock insuficiente. Disponible: {p['cantidad']}")
return True
print(f"❌ Producto con ID '{id_producto}' no encontrado")
return False
def mostrar_inventario():
"""Muestra todo el inventario en formato tabla."""
if not inventario:
print("📭 Inventario vacío")
return
print("\n" + "="*90)
print(f"{'ID':<12} {'NOMBRE':<20} {'CATEGORÍA':<15} {'PRECIO':<10} {'CANT':<6} {'VALOR'}")
print("="*90)
for p in inventario:
valor = p["precio"] * p["cantidad"]
print(f"{p['id']:<12} {p['nombre']:<20} {p['categoria']:<15} "
f"${p['precio']:<9.2f} {p['cantidad']:<6} ${valor:.2f}")
print("="*90)
print(f"💰 Valor total del inventario: ${calcular_valor_inventario():.2f}")
def mostrar_alertas_stock():
"""Muestra productos con stock bajo."""
bajos = productos_bajo_stock()
if bajos:
print("\n⚠️ ALERTAS DE STOCK BAJO:")
for p in bajos:
print(f" • {p['nombre']} ({p['id']}): {p['cantidad']} unidades")
else:
print("\n✅ Todos los productos tienen stock adecuado")
def resumen_por_categoria():
"""Muestra resumen agrupado por categoría."""
if not inventario:
return
categorias = {}
for p in inventario:
cat = p["categoria"]
if cat not in categorias:
categorias[cat] = {"cantidad": 0, "valor": 0}
categorias[cat]["cantidad"] += p["cantidad"]
categorias[cat]["valor"] += p["precio"] * p["cantidad"]
print("\n📊 RESUMEN POR CATEGORÍA:")
print("="*60)
for cat, datos in sorted(categorias.items()):
print(f"{cat.capitalize():<20}: {datos['cantidad']:>4} unidades - ${datos['valor']:.2f}")
print("="*60)
# Menú principal
while True:
print("\n" + "="*50)
print("📦 MENÚ DE INVENTARIO")
print("="*50)
print("1. Agregar producto")
print("2. Ver inventario completo")
print("3. Buscar producto")
print("4. Registrar entrada de stock")
print("5. Registrar salida de stock")
print("6. Ver alertas de stock bajo")
print("7. Resumen por categoría")
print("8. Salir")
opcion = input("\nSelecciona una opción: ")
if opcion == "1":
nombre = input("Nombre del producto: ").strip()
categoria = input("Categoría: ").strip()
try:
precio = float(input("Precio unitario: $"))
cantidad = int(input("Cantidad inicial: "))
agregar_producto(nombre, categoria, precio, cantidad)
except ValueError:
print("❌ Precio y cantidad deben ser números")
elif opcion == "2":
mostrar_inventario()
elif opcion == "3":
termino = input("Buscar (nombre o categoría): ").strip()
resultados = buscar_producto(termino)
if resultados:
print(f"\n✅ {len(resultados)} resultado(s):")
for p in resultados:
print(f" • {p['nombre']} ({p['id']}) - Stock: {p['cantidad']}")
else:
print(f"❌ No se encontraron productos")
elif opcion == "4":
id_prod = input("ID del producto: ").strip()
try:
cantidad = int(input("Cantidad de entrada: "))
if cantidad > 0:
actualizar_stock(id_prod, cantidad, es_entrada=True)
else:
print("❌ La cantidad debe ser positiva")
except ValueError:
print("❌ Ingresa un número válido")
elif opcion == "5":
id_prod = input("ID del producto: ").strip()
try:
cantidad = int(input("Cantidad de salida: "))
if cantidad > 0:
actualizar_stock(id_prod, cantidad, es_entrada=False)
else:
print("❌ La cantidad debe ser positiva")
except ValueError:
print("❌ Ingresa un número válido")
elif opcion == "6":
mostrar_alertas_stock()
elif opcion == "7":
resumen_por_categoria()
elif opcion == "8":
print("👋 ¡Hasta luego!")
break
else:
print("❌ Opción no válida")
Conexión con TaskFlow: Este sistema de inventario usa las mismas estructuras de datos que necesitarás para gestionar proyectos y tareas: listas de objetos complejos, filtros, cálculos de totales y estadísticas.
Retos Adicionales
- Historial: Registra un historial de movimientos (entradas/salidas) para cada producto
- Descuentos: Permite aplicar descuentos por categoría
- Búsqueda avanzada: Filtra por rango de precios (mínimo y máximo)
- Productos más vendidos: Lleva un contador de salidas y muestra los top 5
Ejercicios Adicionales (5 min)
Crea un analizador de texto que:
- Cuente palabras únicas usando un set
- Cuente frecuencia de cada palabra (diccionario)
- Encuentre la palabra más larga
- Muestre las 5 palabras más frecuentes
Gestiona una biblioteca simple:
- Libros: título, autor, ISBN, disponible (bool)
- Préstamos: fecha, lector, libro
- Funciones: prestar, devolver, buscar
- Lista de libros prestados vs disponibles
Resumen
| Estructura | Sintaxis | Usar cuando... |
|---|---|---|
| Lista | [1, 2, 3] |
Colección ordenada, se modifica |
| Diccionario | {"a": 1} |
Datos con propiedades/claves |
| Tupla | (1, 2, 3) |
Datos inmutables, constantes |
| Set | {1, 2, 3} |
Eliminar duplicados |
Resumen
| Estructura | Sintaxis | Usar cuando... |
|---|---|---|
| Lista | [1, 2, 3] |
Colección ordenada, se modifica |
| Diccionario | {"a": 1} |
Datos con propiedades/claves |
| Tupla | (1, 2, 3) |
Datos inmutables, constantes |
| Set | {1, 2, 3} |
Eliminar duplicados |