1.6 · Listas y tuplas¶
Objetivos. Al terminar este capítulo podrás: crear y recorrer listas;
modificarlas, segmentarlas (rebanado) y filtrarlas con comprehensions; y usar
tuplas cuando el dato no debe cambiar. Como ampliación guiada, aplicarás
enumerate, zip, map y filter a colecciones.
Evidencia de logro. Procesarás una colección de datos (p. ej. notas de alumnos) con rebanado, comprehensions y funciones de secuencias, eligiendo entre lista y tupla según la necesidad.
Contexto y motivación¶
Las colecciones permiten trabajar con varios datos como una unidad: una lista de precios, un historial o una tabla. En IA es habitual trabajar con colecciones, por ejemplo, con las características de un modelo, las muestras de un dataset o los resultados de una consulta.
Python ofrece dos estructuras de secuencia fundamentales: la lista (mutable, se puede cambiar) y la tupla (inmutable, no se puede modificar después de crearla). Elegir entre ellas depende de si los datos deben cambiar.
Vocabulario¶
| Término | Significado |
|---|---|
| Lista | Secuencia mutable ([...]) |
| Tupla | Secuencia inmutable ((...)) |
| Índice | Posición (empieza en 0; negativo cuenta desde el final) |
| Rebanado (slicing) | Extraer una subsecuencia [inicio:fin:paso] |
| Mutabilidad | Si el objeto se puede modificar después de crearlo |
| Comprehension | Forma compacta de crear una colección a partir de otra |
| Iterable | Objeto que se puede recorrer (list, tuple, str…) |
Prerrequisitos¶
1.5 · Bucles (sabes recorrer) y manejo de variables.
1. Crear y acceder a listas¶
lista = [10, 20, 30, 40]
print(lista[0]) # primer elemento
print(lista[-1]) # último (índice negativo)
print(lista[1:3]) # de la posición 1 a la 2 (el 3 no entra)
Salida esperada:
Los índices empiezan en 0. Los negativos cuentan desde el final: [-1] es el
último, [-2] el penúltimo.
2. Modificar listas¶
Las listas son mutables: puedes cambiar, añadir y borrar elementos.
numeros = [1, 2, 3]
numeros.append(4) # añadir al final
numeros[0] = 99 # cambiar un elemento
del numeros[1] # borrar el índice 1
print(numeros)
Salida esperada:
Sigue el estado paso a paso: [1, 2, 3] → [1, 2, 3, 4] → [99, 2, 3, 4] →
[99, 3, 4]. Fíjate en que del numeros[1] borra la posición 1 (el 2), no
el valor 1.
Un método es una operación que pertenece al objeto y se escribe detrás de él
con un punto: numeros.append(4). Los que usarás casi a diario: append(v)
(añadir al final), insert(i, v) (insertar en la posición i), remove(v)
(borrar la primera aparición del valor v), pop() (sacar y devolver el
último), sort() (ordenar la propia lista) y reverse() (invertirla).
3. Rebanado (slicing)¶
a = [0, 1, 2, 3, 4, 5]
print(a[1:4]) # posiciones 1, 2, 3
print(a[:3]) # desde el inicio hasta 2
print(a[3:]) # desde 3 hasta el final
print(a[::-1]) # invertida
print(a[::2]) # cada 2 elementos
Salida esperada:
La sintaxis es [inicio:fin:paso], con fin excluido. [::-1] invierte la
lista y a[::2] selecciona un elemento de cada dos.
El slicing devuelve una COPIA
a[1:4] crea una lista nueva; no modifica a. Es útil para trabajar con
subconjuntos sin tocar el original.
4. Métodos y funciones útiles¶
numeros = [3, 1, 4, 1, 5]
print(numeros.count(1)) # cuántas veces aparece el 1
print(numeros.index(4)) # posición del valor 4
numeros.sort() # ordena la propia lista
print(numeros)
print(sorted(numeros, reverse=True)) # devuelve otra lista ordenada
print(len(numeros), sum(numeros), min(numeros), max(numeros))
Salida esperada:
Cómo leer la salida: el 1 aparece 2 veces; el 4 está en la posición
2; tras sort() la propia lista queda ordenada; sorted(..., reverse=True)
devuelve otra lista de mayor a menor; y la última línea muestra longitud, suma,
mínimo y máximo.
Diferencia clave: numeros.sort() modifica la lista y devuelve None;
sorted(numeros) devuelve una lista nueva sin tocar la original. Para no
romper tus datos, prefiere sorted() salvo que necesites ordenar la propia
lista.
Evita l como nombre
En muchos tutoriales verás listas llamadas l. Es mala idea: en muchas
fuentes l se confunde con 1 y no dice qué contiene. Usa nombres como
numeros, precios o notas.
4.1 list(...)¶
El constructor list(...) crea una lista desde cualquier iterable:
Salida esperada:
4.2 Ampliación: ordenar por un campo con key¶
Cuando cada elemento tiene varios datos, como una tupla (nombre, edad),
puedes decir por cuál ordenar con el parámetro key:
personas = [("Ana", 20), ("Luis", 25), ("Marta", 18)]
print(sorted(personas, key=lambda p: p[1])) # por edad (asc)
print(sorted(personas, key=lambda p: p[1], reverse=True)) # por edad (desc)
print(max(personas, key=lambda p: p[1])) # la persona de más edad
Salida esperada:
lambda p: p[1] es una función breve que recibe un elemento (p, una
tupla) y devuelve su posición 1 (la edad). sorted, min y max la aplican
a cada elemento y comparan esos resultados. Las tuplas se explican en la
sección 9 y las funciones lambda, en 1.8 · Funciones;
de momento basta con leerla como «ordena por la edad».
5. Concatenar y repetir¶
a = [1, 2]
b = [3, 4]
print(a + b) # concatena y crea una lista nueva
print([0] * 3) # repite el elemento tres veces
Salida esperada:
+ une listas (crea una nueva) y * repite. Sirven para inicializar listas
([0] * 10 genera 10 ceros).
6. Copias y referencias (¡importante!)¶
Cuando haces b = a, no copias la lista: b apunta al mismo objeto.
Cambiar una cambia la otra:
Salida esperada:
Para hacer una copia independiente usa copy(), [:] o list():
a = [1, 2, 3]
c = a.copy() # o a[:] o list(a)
c.append(5)
print("a:", a, "| c:", c)
print("¿mismo objeto?", a is c)
Salida esperada:
== vs is en listas
a == c compara contenido (True); a is c compara identidad
(False). Recuerda: b = a referencia (comparte), c = a.copy() copia.
Esta diferencia explica muchos errores difíciles de localizar, como una
lista que parece cambiar por sí sola.
7. Listas anidadas (matrices)¶
Una lista puede contener otras listas:
m = [[1, 2], [3, 4]]
print(m[0][1]) # fila 0, columna 1
print([sum(fila) for fila in m]) # suma de cada fila
Salida esperada:
m[fila][columna] para acceder. Las listas anidadas modelan tablas, matrices y
datos jerárquicos, y se recorren con bucles o comprehensions anidados.
8. List comprehensions¶
Una comprehension crea una lista en una línea, filtra y transforma a la vez:
cuadrados = [x ** 2 for x in range(5)]
print(cuadrados)
pares = [x for x in range(10) if x % 2 == 0]
print(pares)
Salida esperada:
Se lee como una frase: "el cuadrado de x, para cada x en range(5)" y, en
el segundo, "si x es par". Es la forma idiomática de construir listas;
cuando el bucle es corto y claro, la comprehension es más legible y rápida que el
bucle equivalente.
Cuándo usar un bucle
Si la lógica es larga, un bucle normal es más legible. Una comprehension con 3 condiciones y 2 transformaciones se vuelve ilegible.
8.1 any y all¶
Con la misma sintaxis, pero sin corchetes, puedes comprobar una condición sobre toda la colección de una vez:
print(any(x > 3 for x in [1, 2, 3, 4])) # ¿algún elemento es mayor que 3?
print(all(x > 0 for x in [1, 2, 3])) # ¿todos son positivos?
Salida esperada:
any() devuelve True si al menos un elemento cumple la condición y
all() si la cumplen todos. Son útiles para preguntas como «¿algún pedido
supera 100?» o «¿todas las notas aprueban?».
9. Tuplas: datos inmutables¶
Una tupla es como una lista pero no se puede modificar:
punto = (3, 4)
print(punto[0], punto[1]) # acceso igual que en listas
x, y = punto # desempaquetado
print(x, y)
Salida esperada:
La tupla es perfecta para datos que van "juntos" y no cambian: coordenadas,
fechas, un par (clave, valor). Al ser inmutable, puede usarse como clave de un
dict (las listas no pueden).
Desempaquetado
Asignar varios valores a la vez es desempaquetar:
Salida esperada:
Es como "trocear" la secuencia en variables. Se usa muchísimo (lo verás al
recorrer dicts o con zip).
10. enumerate, zip, map, filter¶
Estas funciones te permiten recorrer y transformar sin escribir bucles largos.
10.1 enumerate: índice + valor¶
Salida esperada:
enumerate te da la posición y el valor a la vez. Es mucho más limpio que
manejarte un contador a mano.
10.2 zip: combinar varias secuencias¶
nombres = ["Ana", "Luis"]
edades = [20, 25]
for nombre, edad in zip(nombres, edades):
print(nombre, edad)
Salida esperada:
zip junta los elementos por posición: el primero con el primero, etc. Termina
en la secuencia más corta.
10.3 map y filter¶
Salida esperada:
map(función, iterable)aplica la función a cada elemento.filter(función, iterable)se queda con los elementos donde la función devuelveTrue.
str.upper es el método que pasa una cadena a mayúsculas, usado aquí como
función; y lambda x: x > 2 es una función breve que devuelve True para los
elementos mayores que 2 (se estudia en 1.8 · Funciones).
map/filter o comprehension
En general, una comprehension es más legible para lo mismo:
[x.upper() for x in ["a", "b"]]. Usa map/filter cuando ya tengas una
función definida (no un lambda) o quieras expresar un proceso encadenado.
Recuerda: map/filter devuelven iteradores (entregan los valores de
uno en uno, bajo demanda), por eso los envolvemos en list() para verlos.
11. Lista vs tupla: ¿cuándo cada una?¶
| Situación | Usa |
|---|---|
| Colección que cambia (añadir, ordenar, modificar) | lista [...] |
| Datos fijos que van juntos (coord., par clave/valor) | tupla (...) |
Usar como clave de un dict |
tupla (inmutable) |
| Recorrer sin cambiar nada | cualquiera (la tupla ocupa un poco menos de memoria) |
Regla práctica: si no vas a modificar la colección, una tupla es más segura (nadie la cambia por accidente y comunica "esto no cambia"). Para el resto, lista.
Errores frecuentes¶
- Confundir índice 0 con "el primero es 1".
- Creer que
lista[1:3]incluye el índice 3 (no lo incluye). - Pedir una posición que no existe (
numeros[10]en una lista de 5):IndexError: list index out of range. - Añadir elementos en un bucle con
+:appendes más claro y eficiente. - Usar
numeros.sort()esperando que devuelva la lista ordenada (devuelveNone), por ejemplo enordenada = numeros.sort(). - Olvidar que las tuplas son inmutables e intentar
t[0] = 5. - Creer que
b = acopia la lista (es una referencia; usaa.copy()). - Usar
ispara comparar el contenido de dos listas (usa==). - No usar
keyensorted/min/maxcon listas de tuplas o diccionarios. - No hacer una copia antes de modificar una lista que reutilizas.
Práctica de transferencia¶
Dada la lista notas = [7.5, 4.0, 9.0, 6.5, 3.0]:
- Muestra la nota más alta, la más baja y la media (
sum/len). - Con una comprehension, crea
aprobadas = [nota for nota in notas if nota >= 5]. - Usa
enumeratepara imprimir cada nota con su posición (1: 7.5…). - Convierte a tupla las notas y comprueba que no puedes cambiarla (¿qué error da?).
- Usa
zippara juntar["Ana", "Luis", "Marta"]connotasy muestra cada par. ¿Cuántos pares salen? ¿Por qué no salen cinco? - Demuestra la diferencia entre
b = notas(referencia) yc = notas.copy()(copia): cambia un elemento de la copia y explica qué pasa con el original. - Con
any()/all(), comprueba si hay alguna nota mayor que 9 y si todas superan el 4.
Producto evaluable¶
Primera versión del cuaderno 05_colecciones.py (se ampliará en 1.7) con:
- Los ejercicios 1–5 anteriores, cada uno con su celda de código y su interpretación en Markdown.
- Una celda que compare lista vs tupla (cambiar un elemento de cada una) y explique la diferencia.
- Una celda que muestre la diferencia entre referencia (
b = a) y copia (a.copy()), con su interpretación. - Una celda final que use una comprehension (o
any/all) para filtrar y transformar, justificando la elección.
Formato de entrega: cuaderno marimo ejecutado, con salida esperada, interpretación y conclusión.
Resumen y referencia rápida¶
| Tarea | Sintaxis |
|---|---|
| Crear lista / tupla | [1,2,3] / (1,2,3) |
| Acceder | l[0], l[-1] |
| Sub-lista | l[inicio:fin:paso] |
| Añadir/quitar | append, pop, remove, del |
| Ordenar | lista.sort() (la propia lista) · sorted(lista) (nueva) |
| Ordenar por campo | sorted(xs, key=lambda x: x[1]) |
| Copiar | a.copy() / a[:] / list(a) (no b = a) |
| Comprehension | [x**2 for x in lista if x > 2] |
| Índice+valor | enumerate(seq, start=1) |
| Unir secuencias | zip(a, b) |
| Transformar / filtrar | map(f, seq) · filter(f, seq) |
| Comprobar | any(...), all(...) |
| Indexar anidado | m[fila][columna] |
Siguiente: 1.7 · Diccionarios y conjuntos, que añadirá diccionarios y conjuntos al mismo cuaderno.