Hola! Ahora guardamos muchas cosas juntas
En el capítulo 2 cada variable guardaba un solo valor. Eso alcanza para aprender y no alcanza para trabajar 🙂
En un archivo real tienes tres mil ventas, no una. Así que necesitas estructuras que guarden muchas cosas, y en Python son tres las que vas a usar todo el tiempo.
| Estructura | Se escribe | Se puede cambiar | Para qué |
|---|---|---|---|
| Lista | [1, 2, 3] | Sí | Lo que sea que tenga orden y vaya cambiando |
| Tupla | (1, 2, 3) | No | Cosas que no deben cambiar: coordenadas, una fila fija |
| Diccionario | {'ciudad': 'Lima'} | Sí | Datos con nombre. Es como llega cualquier API |
Listas: lo que más vas a usar
ciudades = ['Lima', 'Arequipa', 'Cusco', 'Piura', 'Trujillo'] print(ciudades[0]) print(ciudades[2]) print(len(ciudades))
Lima Cusco 5
Se cuenta desde cero. Ya lo vimos en el capítulo 1 con el
IndexError, y te lo repito porque es la fuente número uno de
errores por uno de diferencia.
Ahora el atajo que te evita hacer cuentas: los índices negativos.
print(ciudades[-1]) # la ultima, siempre print(ciudades[-2]) # la penultima
Trujillo Piura
Nunca más ciudades[len(ciudades) - 1]. Yo escribí esa
monstruosidad durante meses antes de que alguien me enseñara el -1 😅
Rebanadas, que es como se corta una lista
Los dos puntos dentro de los corchetes sacan un pedazo:
print(ciudades[0:3]) # de la 0 hasta ANTES de la 3 print(ciudades[:3]) # lo mismo, el 0 se sobreentiende print(ciudades[2:]) # de la 2 hasta el final print(ciudades[-2:]) # las dos ultimas print(ciudades[::2]) # de dos en dos
['Lima', 'Arequipa', 'Cusco'] ['Lima', 'Arequipa', 'Cusco'] ['Cusco', 'Piura', 'Trujillo'] ['Piura', 'Trujillo'] ['Lima', 'Cusco', 'Trujillo']
El límite de la derecha no se incluye. Eso confunde al
principio y tiene una gracia: ciudades[0:3] te da exactamente 3
elementos, y ciudades[:3] + ciudades[3:] te devuelve la lista
entera sin repetir ni perder nada.
Y una que parece un truco de fiesta y sirve de verdad:
print(ciudades[::-1])
['Trujillo', 'Piura', 'Cusco', 'Arequipa', 'Lima']
Modificar una lista
ventas = [480.37, 524.90, 154.83] ventas.append(2480.84) # agrega al final ventas.insert(0, 100.0) # inserta en una posicion print(ventas) ultimo = ventas.pop() # saca el ultimo Y te lo devuelve print(ultimo, ventas) ventas.remove(154.83) # quita por valor, no por posicion print(ventas)
[100.0, 480.37, 524.9, 154.83, 2480.84] 2480.84 [100.0, 480.37, 524.9, 154.83] [100.0, 480.37, 524.9]
Ojo con remove: quita la primera aparición del
valor, no todas. Y si el valor no está, revienta.
ventas.remove(999)
ValueError: list.remove(x): x not in list
Ordenar, y el error que da la primera vez
Hay dos formas de ordenar y confundirlas te deja con una variable vacía.
montos = [480.37, 154.83, 2480.84, 524.90] ordenados = sorted(montos) # devuelve una lista nueva print(ordenados) print(montos) # la original no se toco
[154.83, 480.37, 524.9, 2480.84] [480.37, 154.83, 2480.84, 524.9]
montos.sort() # ordena la original y devuelve None print(montos)
[154.83, 480.37, 524.9, 2480.84]
Y aquí el error clásico, que quiero que veas de frente:
resultado = montos.sort() print(resultado)
None
Sí: None. Porque .sort() ordena la lista en el sitio
y no devuelve nada. Si guardas su resultado, guardas la nada 🙃
La regla para acordarte: sorted() te da una lista nueva,
.sort() modifica la que ya tienes. Cuando dudes, usa
sorted(), que es más difícil de romper.
print(sorted(montos, reverse=True)) print(sorted(['Cusco', 'arequipa', 'Lima'], key=str.lower))
[2480.84, 524.9, 480.37, 154.83] ['arequipa', 'Cusco', 'Lima']
Ese key=str.lower es lo que evita que las mayúsculas se ordenen
antes que todas las minúsculas, que es lo que pasa por defecto.
La copia que no se copió
Presta atención a esto, que es el error más traicionero del principio y no falla: te da un resultado equivocado sin decir nada.
original = [1, 2, 3]
copia = original # esto NO es una copia
copia.append(4)
print('copia :', copia)
print('original:', original)
copia : [1, 2, 3, 4] original: [1, 2, 3, 4]
Se modificaron las dos 😱
Acuérdate del capítulo 2: una variable es una etiqueta, no una caja. Con
copia = original le pegaste una segunda etiqueta a la
misma lista. No hay dos listas, hay una con dos nombres.
Se comprueba así:
print(copia is original)
True
Para copiar de verdad hay tres formas, y las tres valen:
original = [1, 2, 3] copia_a = original.copy() copia_b = list(original) copia_c = original[:] # una rebanada completa copia_a.append(99) print(original, copia_a) print(copia_a is original)
[1, 2, 3] [1, 2, 3, 99] False
Con esto te ahorro una tarde de "pero si yo no toqué esa variable". A mí me pasó con un dataframe y perdí medio día buscando el fantasma 👻
Tuplas: las que no se pueden cambiar
Una tupla es una lista que no se puede modificar. Se escribe con paréntesis.
coordenada = (-12.0464, -77.0428) # Lima print(coordenada[0]) coordenada[0] = 0
TypeError: 'tuple' object does not support item assignment
¿Y para qué querría algo que no puedo cambiar? Por tres razones muy concretas:
- 🔒 Dice "esto no se toca". Un par de coordenadas, un rango de fechas fijo.
- 🗝️ Puede ser clave de un diccionario. Una lista no puede.
- 📦 Es lo que devuelve una función cuando devuelve varias cosas.
Ese último punto lo vas a ver todo el tiempo:
def minimo_y_maximo(numeros):
return min(numeros), max(numeros)
bajo, alto = minimo_y_maximo([480.37, 154.83, 2480.84])
print(bajo, alto)
154.83 2480.84
Eso de repartir una tupla en varias variables se llama desempaquetado y es puro Python. Lo vamos a usar mucho en el capítulo 5.
Diccionarios: datos con nombre
Aquí está la estructura que más te va a servir en datos, porque es como llega la información del mundo real.
venta = {
'cliente': 'C0045',
'ciudad': 'Trujillo',
'canal': 'Marketplace',
'monto': 480.37,
'unidades': 10,
}
print(venta['ciudad'])
print(venta['monto'] * 1.18)
Trujillo 566.8366
Ya no dependes de recordar que la ciudad estaba en la posición 1. Pides por nombre, que es como piensa una persona.
get, que evita que reviente
print(venta['descuento'])
KeyError: 'descuento'
Con corchetes, si la clave no existe, se cae. Con .get() te
devuelve None, o lo que tú digas:
print(venta.get('descuento'))
print(venta.get('descuento', 0))
None 0
Ese segundo caso es oro puro cuando procesas datos que a veces traen un campo y a veces no, que es siempre 🌸
Recorrer un diccionario
for clave in venta:
print(clave)
cliente ciudad canal monto unidades
for clave, valor in venta.items():
print(f'{clave:10} {valor}')
cliente C0045 ciudad Trujillo canal Marketplace monto 480.37 unidades 10
.items() es el que vas a usar el 90% de las veces. Los otros dos
son .keys() y .values(), y se llaman igual de fácil.
Lo que de verdad te va a llegar: una lista de diccionarios
Junta las dos estructuras y tienes la forma en que viene cualquier respuesta de una API, cualquier JSON, cualquier exportación de un sistema.
ventas = [
{'ciudad': 'Lima', 'canal': 'Web', 'monto': 480.37},
{'ciudad': 'Cusco', 'canal': 'Tienda', 'monto': 154.83},
{'ciudad': 'Lima', 'canal': 'WhatsApp', 'monto': 2480.84},
{'ciudad': 'Piura', 'canal': 'Web', 'monto': 524.90},
]
total = 0
for v in ventas:
total = total + v['monto']
print(f'Total: S/{total:,.2f}')
print(f'Ticket promedio: S/{total / len(ventas):,.2f}')
Total: S/3,640.94 Ticket promedio: S/910.24
Y ahora agrupemos por ciudad, que es la operación que más veces vas a hacer en tu vida con datos:
por_ciudad = {}
for v in ventas:
ciudad = v['ciudad']
por_ciudad[ciudad] = por_ciudad.get(ciudad, 0) + v['monto']
print(por_ciudad)
{'Lima': 2961.21, 'Cusco': 154.83, 'Piura': 524.9}
Guárdate ese patrón, que es un clásico: diccionario.get(clave, 0) +
algo. La primera vez que aparece una ciudad, .get devuelve 0
y arranca la suma; las siguientes, sigue sumando.
En el capítulo 11 esto mismo se escribe así: df.groupby('ciudad')
['monto'].sum(). Una línea. Pero quería que vieras primero lo que hay
por debajo, porque el día que groupby haga algo raro vas a saber
qué está pasando 💜
Comprensiones de lista
Esta es la forma corta de crear una lista a partir de otra, y es tan de Python que se nota cuando alguien no la usa.
montos = [480.37, 154.83, 2480.84, 524.90]
# La forma larga
con_igv = []
for m in montos:
con_igv.append(round(m * 1.18, 2))
# La forma de Python
con_igv_corto = [round(m * 1.18, 2) for m in montos]
print(con_igv)
print(con_igv == con_igv_corto)
[566.84, 182.7, 2927.39, 619.38] True
Se lee de izquierda a derecha casi como una frase: "redondea eme por 1,18, para cada eme en montos".
Y se le puede poner una condición al final:
grandes = [m for m in montos if m > 500] print(grandes) ciudades = ['Lima', 'cusco', 'AREQUIPA'] print([c.title() for c in ciudades])
[2480.84, 524.9] ['Lima', 'Cusco', 'Arequipa']
Un consejo de alguien que se pasó de lista: si tu comprensión no cabe en dos líneas, escríbela como bucle normal. La gracia es que se lea mejor, no que sea más corta.
Ejercicios
1. Primero, último y cuántos
Con una lista de cinco canales, imprime el primero, el último y cuántos hay, sin contar a mano.
canales = ['Web', 'Tienda', 'WhatsApp', 'Marketplace', 'Telefono'] print(canales[0], canales[-1], len(canales))
Web Telefono 5
2. Las tres del medio
De esa misma lista, saca solo los elementos 2, 3 y 4 con una rebanada.
print(canales[1:4])
['Tienda', 'WhatsApp', 'Marketplace']
Recuerda que el límite derecho no entra: 1:4 te da las posiciones
1, 2 y 3.
3. El top 3 de montos
De una lista de montos, saca los tres más altos ordenados de mayor a menor, sin modificar la lista original.
montos = [480.37, 154.83, 2480.84, 524.90, 95.5, 1200.0] top = sorted(montos, reverse=True)[:3] print(top) print(montos[0]) # la original intacta
[2480.84, 1200.0, 524.9] 480.37
4. Demuestra el aliasing
Crea una lista, hazle una copia falsa y una de verdad, y
comprueba con is cuál es cuál.
pedido = ['Abarrotes', 'Bebidas', 'Snacks']
falsa = pedido
buena = pedido.copy()
falsa.append('Limpieza')
print(pedido)
print(buena)
print(falsa is pedido, buena is pedido)
['Abarrotes', 'Bebidas', 'Snacks', 'Limpieza'] ['Abarrotes', 'Bebidas', 'Snacks'] True False
is pregunta si son el mismo objeto; == pregunta si
tienen el mismo contenido. Dos listas distintas con lo mismo dentro dan
True con == y False con is.
5. Un diccionario que no revienta
Con un diccionario de una venta que no trae la clave
descuento, calcula el monto final asumiendo 0 si no está.
venta = {'cliente': 'C0325', 'monto': 524.90}
descuento = venta.get('descuento', 0)
print(f'S/{venta["monto"] * (1 - descuento):.2f}')
S/524.90
Fíjate en las comillas dobles dentro del f-string que abre con comillas simples. Si usas las mismas por fuera y por dentro, Python se pierde.
6. Contar por categoría
Con una lista de canales repetidos, cuenta cuántas veces aparece cada uno.
canales = ['Web', 'Tienda', 'Web', 'WhatsApp', 'Web', 'Tienda']
conteo = {}
for c in canales:
conteo[c] = conteo.get(c, 0) + 1
print(conteo)
{'Web': 3, 'Tienda': 2, 'WhatsApp': 1}
Es el mismo patrón de la suma por ciudad, pero sumando 1 en vez del monto.
Cuando lo veas escrito así vas a reconocer value_counts() de pandas
sin que nadie te lo explique.
7. El máximo con nombre
De una lista de diccionarios de ventas, encuentra la de mayor monto e imprime su ciudad.
ventas = [
{'ciudad': 'Lima', 'monto': 480.37},
{'ciudad': 'Cusco', 'monto': 2480.84},
{'ciudad': 'Piura', 'monto': 524.90},
]
mayor = max(ventas, key=lambda v: v['monto'])
print(mayor['ciudad'], mayor['monto'])
Cusco 2480.84
Ese lambda es una función chiquita sin nombre que dice "para
comparar, mira el monto". Lo vemos con calma en el capítulo 5, tranqui.
8. Comprensión con condición
De la lista de ventas anterior, arma una lista solo con las ciudades cuyo monto pase los S/500.
print([v['ciudad'] for v in ventas if v['monto'] > 500])
['Cusco', 'Piura']
9. Quitar duplicados conservando el orden
De una lista con ciudades repetidas, saca las únicas. Hazlo de dos formas y compara.
ciudades = ['Lima', 'Cusco', 'Lima', 'Piura', 'Cusco', 'Lima']
print(sorted(set(ciudades)))
vistas = []
for c in ciudades:
if c not in vistas:
vistas.append(c)
print(vistas)
['Cusco', 'Lima', 'Piura'] ['Lima', 'Cusco', 'Piura']
set() es rapidísimo y pierde el orden original; el bucle lo
conserva. Cuál usar depende de si el orden significa algo, y muchas veces
significa.
10. La tupla que no se deja
Crea una tupla con un rango de fechas e intenta cambiar el primer valor. Después haz lo mismo con una lista y compara.
rango_tupla = ('2026-01-01', '2026-12-31')
rango_lista = ['2026-01-01', '2026-12-31']
rango_lista[0] = '2026-02-01'
print(rango_lista)
rango_tupla[0] = '2026-02-01'
TypeError: 'tuple' object does not support item assignment
La tupla te protege de un cambio accidental. Cuando algo no debe moverse en todo el programa, esa protección vale más que la flexibilidad.
Lo que te llevas
- 🔢 Se cuenta desde 0, y
[-1]es siempre el último. - ✂️ En una rebanada, el límite de la derecha no entra.
- ⚠️
copia = originalno copia nada: usa.copy(). - 🔀
sorted()devuelve una lista nueva;.sort()devuelveNone. - 🗂️ Una lista de diccionarios es como llega el mundo real, y agrupar con
.get(clave, 0)es el patrón que después hacegroupby.
En el capítulo 4 le enseñamos a Python a decidir y a repetir: if,
for y while. Ahí es donde esto deja de ser una
calculadora y empieza a ser un programa.
Que tengas un hermoso día! 🌟