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]
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
esn ** 2
-
VARIABLE
esn
-
SEQUENCE
esrange(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)
usandon
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