Listas
Una lista es una colección ordenada y mutable de elementos. Puede contener datos de cualquier tipo: números, cadenas, booleanos, incluso otras listas. Es el tipo de colección más usado en Python.
Crear una lista
Las listas se escriben entre corchetes, con los elementos separados por comas:
>>> frutas = ["manzana", "pera", "naranja"]
>>> numeros = [1, 2, 3, 4, 5]
>>> mixta = ["hola", 42, True, 3.14]
>>> vacia = []
También puedes construir una lista a partir de una cadena con list() o dividiendo con .split(), que ya vimos en la lección de strings:
>>> letras = list("hola")
>>> print(letras)
['h', 'o', 'l', 'a']
>>> palabras = "uno dos tres".split()
>>> print(palabras)
['uno', 'dos', 'tres']
Acceder a los elementos
Cada elemento tiene una posición llamada índice. El primer elemento tiene índice 0, el segundo 1, y así sucesivamente. Se accede a ellos con corchetes:
>>> frutas = ["manzana", "pera", "naranja"]
>>> print(frutas[0])
manzana
>>> print(frutas[1])
pera
>>> print(frutas[2])
naranja
Python también acepta índices negativos: -1 es el último elemento, -2 el penúltimo, etc.:
>>> print(frutas[-1])
naranja
>>> print(frutas[-2])
pera
Si usas un índice que no existe, Python lanza un IndexError:
>>> print(frutas[10])
IndexError: list index out of range
Modificar elementos
A diferencia de los strings, las listas son mutables: puedes cambiar un elemento asignándole un nuevo valor por su índice:
>>> frutas = ["manzana", "pera", "naranja"]
>>> frutas[1] = "kiwi"
>>> print(frutas)
['manzana', 'kiwi', 'naranja']
Añadir elementos
.append() añade un elemento al final de la lista. Es la forma más habitual de construir listas dinámicamente:
>>> frutas = ["manzana", "pera"]
>>> frutas.append("naranja")
>>> print(frutas)
['manzana', 'pera', 'naranja']
.insert() añade un elemento en una posición concreta. El resto de elementos se desplazan hacia la derecha:
>>> frutas.insert(1, "kiwi") # inserta en la posición 1
>>> print(frutas)
['manzana', 'kiwi', 'pera', 'naranja']
Para unir dos listas puedes usar + o .extend():
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> print(a + b) # crea una lista nueva
[1, 2, 3, 4, 5, 6]
>>> a.extend(b) # modifica a en el sitio
>>> print(a)
[1, 2, 3, 4, 5, 6]
Nota: append() añade un único elemento. Si le pasas una lista, la añade como un elemento anidado, no la fusiona. Para fusionar usa extend() o +.
>>> nums = [1, 2, 3]
>>> nums.append([4, 5])
>>> print(nums)
[1, 2, 3, [4, 5]] # una lista dentro de otra
>>> nums = [1, 2, 3]
>>> nums.extend([4, 5])
>>> print(nums)
[1, 2, 3, 4, 5] # fusionada
Eliminar elementos
.remove() elimina la primera ocurrencia del valor indicado:
>>> frutas = ["manzana", "pera", "naranja", "pera"]
>>> frutas.remove("pera")
>>> print(frutas)
['manzana', 'naranja', 'pera']
.pop() elimina el elemento en la posición indicada y lo devuelve. Sin argumento, elimina y devuelve el último:
>>> frutas = ["manzana", "pera", "naranja"]
>>> eliminada = frutas.pop(1)
>>> print(eliminada)
pera
>>> print(frutas)
['manzana', 'naranja']
>>> ultima = frutas.pop()
>>> print(ultima)
naranja
del elimina un elemento por su índice sin devolver nada. También puede eliminar la lista completa:
>>> colores = ["rojo", "verde", "azul"]
>>> del colores[0]
>>> print(colores)
['verde', 'azul']
.clear() vacía la lista pero la mantiene:
>>> colores.clear()
>>> print(colores)
[]
Longitud de una lista
len() devuelve el número de elementos:
>>> frutas = ["manzana", "pera", "naranja"]
>>> print(len(frutas))
3
>>> print(len([]))
0
Recorrer una lista con for
Como vimos en la lección de bucles, for recorre cualquier secuencia. Con listas, entrega un elemento en cada vuelta:
>>> frutas = ["manzana", "pera", "naranja"]
>>> for fruta in frutas:
... print(fruta)
manzana
pera
naranja
Un caso más realista: sumar todos los valores de una lista, o filtrar los que cumplan una condición:
>>> precios = [12.5, 8.0, 23.99, 5.5, 17.0]
>>> total = 0 # acumulador: empieza en cero
>>> for precio in precios:
... total += precio # equivale a: total = total + precio
>>> print("total:", total)
total: 66.99
En cada vuelta del bucle, total += precio toma el valor acumulado hasta ese momento y le suma el precio actual. Al terminar el bucle, total contiene la suma de todos los elementos. Es un patrón muy habitual llamado acumulador.
Filtrar elementos que cumplen una condición es igual de común: se recorre la lista y se van añadiendo a una nueva los que pasen el filtro:
>>> caros = [] # lista vacía donde irán los resultados
>>> for precio in precios:
... if precio > 10:
... caros.append(precio)
>>> print(caros)
[12.5, 23.99, 17.0]
Python tiene una sintaxis compacta para este patrón llamada list comprehension. El ejemplo anterior se puede escribir en una sola línea:
>>> caros = [precio for precio in precios if precio > 10]
>>> print(caros)
[12.5, 23.99, 17.0]
La estructura es [expresión for elemento in lista if condición]. La parte if es opcional; sin ella simplemente transforma cada elemento:
>>> dobles = [precio * 2 for precio in precios]
>>> print(dobles)
[25.0, 16.0, 47.98, 11.0, 34.0]
Nota: Las list comprehensions son más concisas pero no siempre más legibles. Si la lógica dentro es compleja, el bucle explícito es más claro.
Si necesitas también el índice, usa enumerate():
>>> for i, fruta in enumerate(frutas):
... print(i, fruta)
0 manzana
1 pera
2 naranja
Slicing: obtener sublistas
El slicing permite extraer una porción de la lista. La sintaxis es lista[inicio:fin], donde inicio se incluye y fin no:
>>> numeros = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> print(numeros[2:5]) # del índice 2 al 4
[2, 3, 4]
>>> print(numeros[:4]) # desde el principio hasta el 3
[0, 1, 2, 3]
>>> print(numeros[6:]) # desde el 6 hasta el final
[6, 7, 8, 9]
>>> print(numeros[-3:]) # los tres últimos
[7, 8, 9]
>>> print(numeros[::2]) # de dos en dos
[0, 2, 4, 6, 8]
>>> print(numeros[::-1]) # al revés
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
El slicing siempre devuelve una lista nueva; la original no cambia.
El operador in
Para comprobar si un valor está en la lista, usa in. Devuelve True o False:
>>> frutas = ["manzana", "pera", "naranja"]
>>> print("pera" in frutas)
True
>>> print("kiwi" in frutas)
False
>>> if "manzana" in frutas:
... print("hay manzanas")
hay manzanas
Métodos de ordenación y búsqueda
.sort() ordena la lista en el sitio (modifica la original). sorted() devuelve una lista nueva ordenada sin tocar la original:
>>> numeros = [3, 1, 4, 1, 5, 9, 2]
>>> numeros.sort()
>>> print(numeros)
[1, 1, 2, 3, 4, 5, 9]
>>> letras = ["c", "a", "b"]
>>> print(sorted(letras)) # lista nueva ordenada
['a', 'b', 'c']
>>> print(letras) # la original no cambió
['c', 'a', 'b']
Para ordenar en orden descendente, pasa el argumento reverse=True:
>>> numeros.sort(reverse=True)
>>> print(numeros)
[9, 5, 4, 3, 2, 1, 1]
.reverse() invierte el orden de la lista en el sitio (sin ordenar, solo invierte):
>>> colores = ["rojo", "verde", "azul"]
>>> colores.reverse()
>>> print(colores)
['azul', 'verde', 'rojo']
.count() cuenta cuántas veces aparece un valor. .index() devuelve el índice de la primera ocurrencia:
>>> nums = [1, 2, 3, 2, 2, 4]
>>> print(nums.count(2))
3
>>> print(nums.index(3))
2
Nota: .index() lanza un ValueError si el valor no existe. Comprueba con in antes si no estás seguro.
is vs ==
Ya vimos == para comparar valores. Con listas aparece una distinción importante: == compara el contenido, mientras que is compara la identidad (si son exactamente el mismo objeto en memoria):
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> print(a == b) # mismo contenido
True
>>> print(a is b) # objetos distintos en memoria
False
>>> c = a # c apunta al mismo objeto que a
>>> print(c is a)
True
>>> c.append(4) # modificar c también modifica a
>>> print(a)
[1, 2, 3, 4]
Un error clásico que todo principiante comete es pensar que lista_b = lista_a crea una copia. En realidad, solo estás creando un segundo nombre para la misma lista: son el mismo objeto en memoria. Para copiar de verdad, siempre debes usar .copy():
>>> a = [1, 2, 3]
>>> b = a.copy() # copia independiente
>>> b.append(99)
>>> print(a) # a no ha cambiado
[1, 2, 3]
>>> print(b)
[1, 2, 3, 99]
Nota: Reserva is para comparar con None (if resultado is None). Para todo lo demás, usa ==.
Listas anidadas
Una lista puede contener otras listas. Se accede a los elementos internos encadenando corchetes:
>>> tablero = [
... ["X", "O", "X"],
... ["O", "X", "O"],
... ["X", "O", "X"],
... ]
>>> print(tablero[0]) # primera fila
['X', 'O', 'X']
>>> print(tablero[1][2]) # fila 1, columna 2
'O'
En la próxima lección: tuplas y diccionarios: otras formas de agrupar datos en Python.