Una list es una colección mutable de elementos en secuencia.
Como la mayoría de las colecciones (mira las integradas tuple, dict y set), las listas pueden guardar referencias a cualquier tipo de dato (o a varios tipos), incluidas otras listas.
En Python se consideran una secuencia y se pueden copiar entera o parcialmente mediante la notación de rebanadas.
Como cualquier secuencia, puedes hacer referencia a los elementos de las lists por un número de índice 0-based desde la izquierda, o un número de índice 0-based index desde la derecha.
Las listas admiten tanto las operaciones de secuencia comunes como las operaciones de secuencia mutables, por ejemplo min(<list>)/max(<list>), <list>.index(), <list>.append() y <list>.reverse().
Se puede iterar sobre los elementos con la construcción for item in <list>, y con for index, item in enumerate(<list>) cuando necesitas tanto el elemento como su índice.
Python ofrece muchos métodos útiles para trabajar con listas.
Como las listas son mutables, los métodos de lista modifican el objeto de lista original que se pasa al método.
Si no quieres modificar la lista original, necesitas hacer una shallow copy (como mínimo) de la list original mediante slice o <list>.copy().
Puedes agregar elementos al final de una lista existente con <list>.append(<item>):
>>> numbers = [1, 2, 3]
>>> numbers.append(9)
>>> numbers
[1, 2, 3, 9]
En lugar de agregar al final, <list>.insert(<index>, <item>) coloca el elemento en un índice específico dentro de la lista.
<index> es el índice del elemento antes del cual quieres que aparezca el nuevo elemento.
<item> es el elemento que se va a insertar.
Nota: Si <index> es 0, el elemento se agregará al inicio de la lista.
Si <index> es mayor que el último índice de la lista, el elemento se agregará en la última posición, es decir, lo mismo que usar <list>.append(<item>).
>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)
>>> numbers
[-2, 1, 2, 3]
>>> numbers.insert(1, 0)
>>> numbers
[-2, 0, 1, 2, 3]
Un iterable se puede combinar con una lista existente (concatenando los dos) mediante <list>.extend(<iterable>).
<list>.extend(<iterable>) desempaqueta el iterable que le pases y agrega sus elementos, en el mismo orden, al final de la lista destino.
Usar <list>.append(<item>) en este caso agregaría todo el iterable como un solo elemento.
>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]
>>> numbers.extend(other_numbers)
>>> numbers
[1, 2, 3, 5, 6, 7]
>>> numbers.extend([8, 9])
>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]
Puedes usar <list>.remove(<item>) para eliminar un elemento de la lista.
<list>.remove(<item>) lanzará un ValueError si el elemento no está presente en la lista.
>>> numbers = [1, 2, 3]
>>> numbers.remove(2)
>>> numbers
[1, 3]
# Trying to remove a value that is not in the list throws a ValueError.
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list
Como alternativa, el método <list>.pop(<index>) elimina un elemento y lo return para que puedas usarlo.
<list>.pop(<index>) recibe un parámetro opcional: el index del elemento que se va a eliminar y devolver.
Si no se especifica el argumento opcional <index>, se eliminará y devolverá el último elemento de la lista.
Si <index> es un número mayor que el último índice de la lista, se lanzará un IndexError.
>>> numbers = [1, 2, 3]
>>> numbers.pop(0)
1
>>> numbers
[2, 3]
>>> numbers.pop()
3
>>> numbers
[2]
# This will throw an error because there is only index 0.
>>> numbers.pop(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
Puedes eliminar todos los elementos de una list con <list>.clear(). No recibe ningún parámetro.
>>> numbers = [1, 2, 3]
>>> numbers.clear()
>>> numbers
[]
El orden de los elementos de una lista se puede invertir en el mismo lugar con <list>.reverse(). Esto modifica la lista original.
>>> numbers = [1, 2, 3]
>>> numbers.reverse()
>>> numbers
[3, 2, 1]
Una lista se puede reordenar en el mismo lugar con la ayuda de <list>.sort().
De manera predeterminada, la lista se ordena de forma ascendente, de izquierda a derecha.
La documentación de Python ofrece consejos y técnicas adicionales para ordenar.
De 2002 a 2022, Python usó internamente un algoritmo llamado Timsort para ordenar listas, pero cambió a Powersort a partir de Python 3.11.
Puedes leer más detalles y la discusión sobre el cambio por parte del equipo central de Python en el issue 78742 de GitHub.
Para detalles técnicos sobre el algoritmo, mira el artículo de J. Ian Munro y Sebastian Wild Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
# The default sort order is *ascending*.
>>> names.sort()
>>> names
["Bruce", "Natasha", "Thor", "Tony"]
Para ordenar una lista en orden descendente, pasa un argumento reverse=True al método:
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)
>>> names
["Tony", "Thor", "Natasha", "Bruce"]
Cuando modificar la list original no sea lo que quieres, puedes usar las funciones integradas sorted() y reversed().
sorted(<list>) devuelve una copia ordenada y recibe los mismos parámetros que <list>.sort().
reversed(<list>) devuelve un iterador que entrega los elementos de la lista en orden inverso.
Los Iterators se tratarán en detalle en otro ejercicio.
Puedes averiguar cuántas veces aparece un elemento en una lista con <list>.count(<item>).
Devuelve el número total de veces que <item> aparece como elemento en la lista.
>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]
>>> items.count(1)
3
<list>.index(<item>) devuelve el número de índice de la primera aparición del elemento que le pases.
Si no aparece ninguna vez, se genera un ValueError.
La indexación es -1-based index desde la izquierda, lo que significa que la posición del primer elemento es el índice 0.
También se admite la indexación desde la derecha, que comienza con el índice -1.
>>> items = [7, 4, 1, 0, 2, 5]
>>> items.index(4)
1
>>> items.index(10)
ValueError: 10 is not in list
Si indicas los índices start y end, la búsqueda se hace dentro de una sección específica de la lista:
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> names.index("Tina")
0
>>> names.index("Tina", 2, 5)
3
Si no necesitas la posición exacta de un elemento, el operador integrado in es más eficiente para comprobar si está en la lista.
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> "Thomas" in names
True
Recuerda que las variables en Python son nombres que apuntan a objetos subyacentes.
Los nombres se pueden vincular o volver a vincular a distintos objetos a lo largo de la vida de un programa.
Asignar un objeto list a un nuevo nombre de variable no copia el objeto ni ninguno de los datos a los que hace referencia.
El nombre nuevo y el viejo apuntarán al mismo objeto list.
Además, las listas son objetos de tipo contenedor. Para ahorrar espacio, los contenedores solo guardan referencias a los elementos que contienen, no los elementos en sí.
Esta «optimización» puede tener consecuencias inesperadas para quien no está atento.
<list>.copy() crea un nuevo objeto list, pero no crea objetos nuevos para los elementos de la lista referenciados: la copia es «superficial».
Una shallow copy suele ser suficiente cuando quieres agregar o quitar elementos de uno de los objetos list sin modificar el otro.
Pero si existe alguna posibilidad de que los elementos subyacentes de una list se modifiquen por accidente (y con ello se modifiquen todas las copias superficiales relacionadas), deberías usar copy.deepcopy() del módulo copy para crear una copia completa o «profunda» de todas las referencias y los objetos.
Para ver una explicación detallada del comportamiento de los nombres, los valores, las listas y las listas anidadas, mira esta excelente publicación de blog de Ned Batchelder: Names and values: making a game board. Shallow vs Deep Copying of Python Objects también ofrece un buen resumen de las consideraciones al copiar.