tutorial for español else compressed comprehension python list list-comprehension

python - for - ¿Qué significa "comprensión de la lista"? ¿Cómo funciona y cómo puedo usarlo?



python list comprehension tutorial (5)

Últimamente he visto mucha confusión (sobre otras preguntas SO y de compañeros de trabajo) sobre cómo funcionan las comprensiones de listas. Un poquito de educación matemática puede ayudar a entender por qué la sintaxis es así y qué significan realmente las comprensiones de listas.

La sintaxis

Es mejor pensar en las comprensiones de listas como predicados sobre un conjunto / colección, como lo haríamos en matemáticas usando la notación de generador de conjuntos. La notación en realidad me parece bastante natural, porque tengo una licenciatura en Matemáticas. Pero olvídate de mí, Guido van Rossum (inventor de Python) tiene una maestría en Matemáticas y tiene experiencia en matemáticas.

Establecer curso acelerado de notación de constructor

Aquí están los (muy básicos) cómo funciona la notación de generador de conjuntos:

Por lo tanto, esta notación de generador de conjuntos representa el conjunto de números que son estrictamente positivos (es decir, [1,2,3,4,...] ).

Puntos de confusión

1) El filtro de predicado en la notación de generador de conjuntos solo especifica qué elementos queremos mantener, y los predicados de comprensión de lista hacen lo mismo. No tiene que incluir una lógica especial para omitir elementos, se omiten a menos que el predicado los incluya. El predicado vacío (es decir, sin condicional al final) incluye todos los elementos de la colección dada.

2) El filtro de predicado en la notación del generador de conjuntos va al final, y de manera similar en las comprensiones de listas. (algunos) Los principiantes piensan que algo como [x < 5 for x in range(10)] les dará la lista [0,1,2,3,4] , cuando en realidad arroja [True, True, True, True, True, False, False, False, False, False] . Obtenemos la salida [True, True, True, True, True, False, False, False, False, False] porque le pedimos a Python que evaluara x < 5 para todos los elementos en el range(10) . Ningún predicado implica que obtenemos todo del conjunto (al igual que en la notación de generador de conjuntos).

Si mantiene la notación de generador de conjuntos en el fondo de su mente mientras usa las comprensiones de listas, son un poco más fáciles de tragar.

HTH!

Tengo el siguiente código:

[x**2 for x in range(10)]

Cuando lo ejecuto en el shell de Python, devuelve:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

He buscado y parece que esto se llama comprensión de lista , pero ¿cómo funciona?


Hay listas, diccionarios y conjuntos de comprensiones, pero no hay comprensiones de tuplas (aunque explore "expresiones generadoras").

Abordan el problema de que los bucles tradicionales en Python son declaraciones (no devuelven nada) no expresiones que devuelven un valor.

No son la solución a todos los problemas y pueden reescribirse como bucles tradicionales. Se vuelven incómodos cuando el estado necesita ser mantenido y actualizado entre iteraciones.

Generalmente consisten en:

[<output expr> <loop expr <input expr>> <optional predicate expr>]

pero puede retorcerse de muchas maneras interesantes y extrañas.

Pueden ser análogos a las operaciones tradicionales map() y filter() que todavía existen en Python y continúan utilizándose.

Cuando se hace bien, tienen un alto coeficiente de satisfacción.


Si prefiere una forma más visual de descubrir lo que está sucediendo, entonces quizás esto ayude:

# for the example in the question... y = [] for x in range(10): y += [x**2] # is equivalent to... y = [x**2 for x in range(10)] # for a slightly more complex example, it is useful # to visualize where the various x''s end up... a = [1,2,3,4] b = [3,4,5,6] c = [] for x in a: if x in b: c += [x] # / / / # / _____/______/ # / / / # // / # // / # / / / # / / / c = [x for x in a if x in b] print(c)

... produce la salida [3, 4]


De la documentación :

Las comprensiones de listas proporcionan una forma concisa de crear listas. Las aplicaciones comunes son hacer nuevas listas donde cada elemento es el resultado de algunas operaciones aplicadas a cada miembro de otra secuencia o iterable, o crear una subsecuencia de esos elementos que satisfacen una determinada condición.

Sobre su pregunta, la comprensión de la lista hace lo mismo que el siguiente código Python "simple":

>>> l = [] >>> for x in range(10): ... l.append(x**2) >>> l [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

¿Cómo se escribe en una línea? Hmm ... podemos ... probablemente ... usar map() con lambda :

>>> list(map(lambda x: x**2, range(10))) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Pero, ¿no es más claro y sencillo usar una lista de comprensión?

>>> [x**2 for x in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Básicamente, podemos hacer cualquier cosa con x . No solo x**2 . Por ejemplo, ejecute un método de x :

>>> [x.strip() for x in (''foo/n'', ''bar/n'', ''baz/n'')] [''foo'', ''bar'', ''baz'']

O use x como argumento de otra función:

>>> [int(x) for x in (''1'', ''2'', ''3'')] [1, 2, 3]

También podemos, por ejemplo, usar x como la clave de un objeto dict . Veamos:

>>> d = {''foo'': ''10'', ''bar'': ''20'', ''baz'': ''30''} >>> [d[x] for x in [''foo'', ''baz'']] [''10'', ''30'']

¿Qué tal una combinación?

>>> d = {''foo'': ''10'', ''bar'': ''20'', ''baz'': ''30''} >>> [int(d[x].rstrip(''0'')) for x in [''foo'', ''baz'']] [1, 3]

Y así.

También puede usar if o if...else en una lista de comprensión. Por ejemplo, solo desea números impares en el range(10) . Tu puedes hacer:

>>> l = [] >>> for x in range(10): ... if x%2: ... l.append(x) >>> l [1, 3, 5, 7, 9]

Ah, eso es demasiado complejo. ¿Qué pasa con la siguiente versión?

>>> [x for x in range(10) if x%2] [1, 3, 5, 7, 9]

Para usar una expresión ternaria if...else , necesita poner if ... else ... después de x , no después del range(10) :

>>> [i if i%2 != 0 else None for i in range(10)] [None, 1, None, 3, None, 5, None, 7, None, 9]

¿Has oído hablar de la comprensión de la lista anidada ? Puede poner dos o más for s en una lista de comprensión . Por ejemplo:

>>> [i for x in [[1, 2, 3], [4, 5, 6]] for i in x] [1, 2, 3, 4, 5, 6] >>> [j for x in [[[1, 2], [3]], [[4, 5], [6]]] for i in x for j in i] [1, 2, 3, 4, 5, 6]

Hablemos de la primera parte, for x in [[1, 2, 3], [4, 5, 6]] que da [1, 2, 3] y [4, 5, 6] . Entonces, for i in x da 1 , 2 , 3 y 4 , 5 , 6 .

Advertencia: Siempre necesita poner for x in [[1, 2, 3], [4, 5, 6]] antes for i in x :

>>> [j for j in x for x in [[1, 2, 3], [4, 5, 6]]] Traceback (most recent call last): File "<input>", line 1, in <module> NameError: name ''x'' is not defined

También tenemos comprensiones establecidas , comprensiones dictadas y expresiones generadoras .

las comprensiones de conjuntos y las comprensiones de listas son básicamente las mismas, pero la primera devuelve un conjunto en lugar de una lista :

>>> {x for x in [1, 1, 2, 3, 3, 1]} {1, 2, 3}

Es lo mismo que:

>>> set([i for i in [1, 1, 2, 3, 3, 1]]) {1, 2, 3}

Una comprensión dict se parece a una comprensión establecida, pero utiliza {key: value for key, value in ...} o {i: i for i in ...} lugar de {i for i in ...} .

Por ejemplo:

>>> {i: i**2 for i in range(5)} {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Y es igual a:

>>> d = {} >>> for i in range(5): ... d[i] = i**2 >>> d {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

¿ (i for i in range(5)) da una tupla ? ¡No !, es una expresión generadora . Que devuelve un generador :

>>> (i for i in range(5)) <generator object <genexpr> at 0x7f52703fbca8>

Es lo mismo que:

>>> def gen(): ... for i in range(5): ... yield i >>> gen() <generator object gen at 0x7f5270380db0>

Y puedes usarlo como generador:

>>> gen = (i for i in range(5)) >>> next(gen) 0 >>> next(gen) 1 >>> list(gen) [2, 3, 4] >>> next(gen) Traceback (most recent call last): File "<input>", line 1, in <module> StopIteration

Nota: Si usa una lista de comprensión dentro de una función , no necesita el [] si esa función podría recorrer un generador. Por ejemplo, sum() :

>>> sum(i**2 for i in range(5)) 30

Relacionado (sobre generadores): Comprensión de los generadores en Python .


Introducción

Una comprensión de lista es una forma declarativa de alto nivel para crear una lista en Python. Los principales beneficios de las comprensiones son la legibilidad y la facilidad de mantenimiento. Mucha gente los encuentra muy legibles, e incluso los desarrolladores que nunca los han visto antes pueden adivinar correctamente lo que significa.

# Snippet 1 squares = [n ** 2 for n in range(5)] # Snippet 2 squares = [] for n in range(5): squares.append(n ** 2)

Ambos fragmentos de código producirán squares iguales a [0, 1, 4, 9, 16] .

Observe que en el primer fragmento, lo que escribe declara qué tipo de lista desea, mientras que el segundo especifica cómo crearla. Es por eso que una comprensión es de alto nivel y declarativa.

Sintaxis

[EXPRESSION for VARIABLE in SEQUENCE]

EXPRESSION es cualquier expresión de Python, pero es típico tener alguna variable en ella. Esta variable se establece en el campo VARIABLE . SEQUENCE define la fuente de valores a través de los cuales la variable enumera.

Considerando el fragmento 1, [n ** 2 for n in range(5)] :

  • EXPRESSION es n ** 2
  • VARIABLE es n
  • SEQUENCE es range(5)

Tenga en cuenta que si marca el tipo de squares , obtendrá que la comprensión de la lista es solo una lista normal:

>>> type(squares) <class ''list''>

Más sobre EXPRESIÓN

La expresión puede ser cualquier cosa que se reduzca a un valor:

  • Expresiones aritméticas como n ** 2 + 3 * n + 1
  • Una llamada a función como f(n) usando n como variable
  • Una operación de corte como s[::-1]
  • El método llama a bar.foo()
  • ...

Algunos ejemplos:

>>> [2 * x + 3 for x in range(5)] [3, 5, 7, 9, 11] >>> [abs(num) for num in range(-5, 5)] [5, 4, 3, 2, 1, 0, 1, 2, 3, 4] >>> animals = [''dog'', ''cat'', ''lion'', ''tiger''] >>> [animal.upper() for animal in animals] [''DOG'', ''CAT'', ''LION'', ''TIGER'']

Filtración:

El orden de los elementos en la lista final está determinado por el orden de la SEQUENCE . Sin embargo, puede filtrar elementos agregando una cláusula if :

[EXPRESSION for VARIABLE in SEQUENCE if CONDITION]

CONDITION es una expresión que se evalúa como True o False . Técnicamente, la condición no tiene que depender de VARIABLE , pero generalmente la usa.

Ejemplos:

>>> [n ** 2 for n in range(5) if n % 2 == 0] [0, 4, 16] >>> animals = [''dog'', ''cat'', ''lion'', ''tiger''] >>> [animal for animal in animals if len(animal) == 3] [''dog'', ''cat'']

Además, recuerde que Python le permite escribir otros tipos de comprensión además de las listas:

  • comprensión del diccionario
  • establecer comprensiones