Link Search Menu Expand Document

List comprehensions

Una de las principales ventajas de Python es que una misma funcionalidad puede ser escrita de maneras muy diferentes, ya que su sintaxis es muy rica en lo que se conoce como expresiones idiom谩ticas o idiomatic expressions. Las list comprehension o comprensi贸n de listas son una de ellas.

Vayamos al grano, las list comprehension nos permiten crear listas de elementos en una sola l铆nea de c贸digo. Por ejemplo, podemos crear una lista con los cuadrados de los primeros 5 n煤meros de la siguiente forma

cuadrados = [i**2 for i in range(5)]
#[0, 1, 4, 9, 16]

De no existir, podr铆amos hacer lo mismo de la siguiente forma, pero necesitamos alguna que otra l铆nea m谩s de c贸digo.

cuadrados = []
for i in range(5):
    cuadrados.append(i**2)
#[0, 1, 4, 9, 16]

El resultado es el mismo, pero resulta menos claro. Antes de continuar, veamos la sintaxis general de las comprensiones de listas.

# lista = [expresi贸n for elemento in iterable]

Es decir, por un lado tenemos el for elemento in iterable, que itera un determinado iterable y 鈥渁lmacena鈥 cada uno de los elementos en elemento como vimos en este otro post sobre el for. Por otro lado, tenemos la expresi贸n, que es lo que ser谩 a帽adido a la lista en cada iteraci贸n.

La expresi贸n puede ser una operaci贸n como hemos visto anteriormente i**2, pero tambi茅n puede ser un valor constante. El siguiente ejemplo genera una lista de cinco unos.

unos = [1 for i in range(5)]
#[1, 1, 1, 1, 1]

La expresi贸n tambi茅n puede ser una llamada a una funci贸n. Se podr铆a escribir el ejemplo anterior del c谩lculo de cuadrados de la siguiente manera.

def eleva_al_2(i):
    return i**2

cuadrados = [eleva_al_2(i) for i in range(5)]
#[0, 1, 4, 9, 16]

Como puedes observar, las posibilidades son bastante amplias. Cualquier elemento que sea iterable puede ser usado con las list comprehensions. Anteriormente hemos iterado range() pero podemos hacer lo mismo para una lista. En el siguiente ejemplo vemos como dividir todos los n煤meros de una lista entre 10.

lista = [10, 20, 30, 40 , 50]
nueva_lista = [i/10 for i in lista]
#[1.0, 2.0, 3.0, 4.0, 5.0]

A帽adiendo condicionales

En el apartado anterior hemos visto como modificar todos los elementos de un iterable (como una lista) de diferentes maneras. La primera elevando cada elemento al cuadrado, y la segunda dividiendo cada elemento por diez.

Pero, 驴y si quisi茅ramos realizar la operaci贸n sobre el elemento s贸lo si una determinada condici贸n se cumple? Pues tenemos buenas noticias, porque es posible a帽adir un condicional if. La expresi贸n gen茅rica ser铆a la siguiente.

# lista = [expresi贸n for elemento in iterable if condici贸n]

Por lo tanto la expresi贸n s贸lo se aplicar谩 al elemento si se cumple la condici贸n. Veamos un ejemplo con una frase, de la que queremos saber el n煤mero de erres que tiene.

frase = "El perro de san roque no tiene rabo"
erres = [i for i in frase if i == 'r']
#['r', 'r', 'r', 'r']

Lo que hace el c贸digo anterior es iterar cada letra de la frase, y si es una r, se a帽ade a la lista. De esta manera el resultado es una lista con tantas letras r como la frase original tiene, y podemos calcular las veces que se repite con len().

print(len(erres))
#4

Sets comprehension

Las set comprehensions son muy similares a las listas que hemos visto con anterioridad. La 煤nica diferencia es que debemos cambiar el () por {}. Como resulta evidente, dado que los set no permiten duplicados, si intentamos a帽adir un elemento que ya existe en el set, simplemente no se a帽adir谩.

frase = "El perro de san roque no tiene rabo"
mi_set = {i for i in frase if i == "r"}
#{'r'}

Dictionary comprehension

Y por 煤ltimo, tambi茅n tenemos las comprensiones de diccionarios. Son muy similares a las anteriores, con la 煤nica diferencia que debemos especificar la key o llave. Veamos un ejemplo.

lista1 = ['nombre', 'edad', 'regi贸n']
lista2 = ['Pelayo', 30, 'Asturias']

mi_dict = {i:j for i,j in zip(lista1, lista2)}
#{'nombre': 'Pelayo', 'edad': 30, 'regi贸n': 'Asturias'}

Como se puede ver, usando : asignamos un valor a una llave. Hemos usado tambi茅n zip(), que nos permite iterar dos listas paralelamente. Por lo tanto, en este ejemplo estamos convirtiendo dos listas a un diccionario.

Conclusiones

Las comprensiones de listas, sets o diccionarios son una herramienta muy 煤til para hacer que nuestro c贸digo resulte m谩s compacto y f谩cil de leer. Siempre que tengamos una colecci贸n iterable que queramos modificar, son una buena opci贸n para evitar tener que escribir bucles for.

Las comprensiones est谩n tambi茅n muy relacionadas con el concepto de programaci贸n funcional y otra funciones que Python nos ofrece como filter o map, por lo que si no las conoces te recomendamos que leas sobre ellas.

En ciertas ocasiones, las comprensiones no resultan s贸lo 煤tiles por que puedan ser escritas en una sola l铆nea de c贸digo, sino que tambi茅n pueden llegar a ser m谩s r谩pidas que otros m茅todos. Es muy importante por lo tanto medir su tiempo de ejecuci贸n para saber si son una buena elecci贸n.

Y por 煤ltimo, aunque su uso resulte de lo m谩s Pyth贸nico y elegante (algo que a muchos programadores de Python les encanta), hay que tener cuidado con su uso y no abusar de ellas. Resulta f谩cil caer en la tentaci贸n de acabar escribiendo comprensiones que son tan largas que pr谩cticamente son imposibles de leer, algo que puede no ser muy buena idea.