web-dev-qa-db-fra.com

Que signifie «compréhension de liste»? Comment ça marche et comment puis-je l'utiliser?

J'ai le code suivant:

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

Quand je l'exécute dans le shell Python, il renvoie:

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

J'ai cherché et il semble que cela s'appelle un compréhension de la liste, mais comment ça marche?

50
Kevin Guan

De la documentation :

La compréhension des listes fournit un moyen concis de créer des listes. Les applications courantes sont de créer de nouvelles listes où chaque élément est le résultat de certaines opérations appliquées à chaque membre d'une autre séquence ou itérable, ou de créer une sous-séquence de ces éléments qui remplissent une certaine condition.


A propos de votre question, la compréhension de la liste fait la même chose que le "plain" suivant Python:

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

Comment l'écrivez-vous sur une seule ligne? Hmm ... nous pouvons ... probablement ... utiliser map() avec lambda :

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

Mais n'est-il pas plus clair et plus simple d'utiliser simplement une compréhension de liste?

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

Fondamentalement, nous pouvons tout faire avec x. Pas seulement x**2. Par exemple, exécutez une méthode de x:

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

Ou utilisez x comme argument d'une autre fonction:

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

Nous pouvons également, par exemple, utiliser x comme clé d'un objet dict. Voyons voir:

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

Que diriez-vous d'une combinaison?

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

Etc.


Vous pouvez également utiliser if ou if...else Dans une liste de compréhension. Par exemple, vous ne voulez que des nombres impairs dans range(10). Tu peux faire:

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

Ah c'est trop complexe. Et la version suivante?

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

Pour utiliser une expression ternaire if...else, Vous devez mettre le if ... else ... Après x, pas après range(10):

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

Avez-vous entendu parler de compréhension des listes imbriquées ? Vous pouvez mettre deux ou plusieurs fors dans une liste de compréhension. Par exemple:

>>> [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]

Parlons de la première partie, for x in [[1, 2, 3], [4, 5, 6]] Qui donne [1, 2, 3] Et [4, 5, 6]. Ensuite, for i in x Donne 1, 2, 3 Et 4, 5, 6 .

Attention: Vous devez toujours mettre for x in [[1, 2, 3], [4, 5, 6]] avant 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

Nous avons également set comprehensions, dict comprehensions et expressions de générateur.

les compréhensions d'ensemble et les compréhensions de liste sont fondamentalement les mêmes, mais la première renvoie un set au lieu d'un liste:

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

C'est la même chose que:

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

A dict compréhension ressemble une compréhension d'ensemble, mais il utilise {key: value for key, value in ...} ou {i: i for i in ...} au lieu de {i for i in ...}.

Par exemple:

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

Et cela équivaut à:

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

Est-ce que (i for i in range(5)) Donne un Tuple? Non !, c'est une expression de générateur . Qui renvoie un générateur :

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

C'est la même chose que:

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

Et vous pouvez l'utiliser comme générateur:

>>> 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

Remarque: Si vous utilisez une compréhension de liste à l'intérieur d'une fonction, vous n'avez pas besoin du [] si cette fonction pouvait boucler sur un générateur. Par exemple, sum() :

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

Connexes (sur les générateurs): Comprendre les générateurs en Python .

78
Kevin Guan

Il existe des compréhensions de listes, de dictionnaires et d'ensembles, mais aucune compréhension de tuple (mais explorez les "expressions de générateur").

Ils résolvent le problème que les boucles traditionnelles dans Python sont des instructions (ne retournent rien) et non des expressions qui retournent une valeur.

Ils ne sont pas la solution à tous les problèmes et peuvent être réécrits sous forme de boucles traditionnelles. Ils deviennent gênants lorsque l'état doit être maintenu et mis à jour entre les itérations.

Ils consistent généralement en:

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

mais peut être tordu de nombreuses façons intéressantes et bizarres.

Elles peuvent être analogues aux opérations traditionnelles de map() et filter() qui existent toujours dans Python et continuent d'être utilisées.

Lorsqu'ils sont bien faits, ils ont un quotient de satisfaction élevé.

7
cdlane

J'ai vu beaucoup de confusion ces derniers temps (sur d'autres SO questions et des collègues) sur le fonctionnement des listes de compréhension. Un tout petit peu de formation en mathématiques peut aider avec pourquoi la syntaxe est comme ça, et ce que les compréhensions de liste signifient vraiment.

La syntaxe

Il est préférable de considérer les compréhensions de liste comme des prédicats sur un ensemble/une collection, comme nous le ferions en mathématiques en utilisant la notation de générateur d'ensemble. La notation me semble en fait assez naturelle, car je suis titulaire d'un diplôme de premier cycle en mathématiques. Mais oubliez-moi, Guido van Rossum (inventeur de Python) est titulaire d'une maîtrise en mathématiques et a une formation en mathématiques.

Définir le cours intensif de notation du générateur

Voici (les bases) du fonctionnement de la notation de générateur de set:

enter image description here

Ainsi, cette notation de constructeur d'ensemble représente l'ensemble de nombres strictement positifs (c'est-à-dire [1,2,3,4,...]).

Points de confusion

1) Le filtre de prédicat dans la notation set builder spécifie uniquement les éléments que nous voulons conserver, et les prédicats de compréhension de liste font la même chose. Vous n'avez pas pour inclure une logique spéciale pour omettre des éléments, ils sont omis sauf s'ils sont inclus par le prédicat. Le prédicat vide (c'est-à-dire aucun conditionnel à la fin) inclut tous les éléments de la collection donnée.

2) Le filtre de prédicat dans la notation set builder va à la fin, et de même dans les listes de compréhension. (certains) Les débutants pensent quelque chose comme [x < 5 for x in range(10)] leur donnera la liste [0,1,2,3,4], alors qu'en fait il affiche [True, True, True, True, True, False, False, False, False, False]. Nous obtenons la sortie [True, True, True, True, True, False, False, False, False, False] Parce que nous avons demandé Python d'évaluer x < 5 Pour tous éléments dans range(10). Aucun prédicat n'implique que nous obtenons tout de l'ensemble (tout comme dans la notation de générateur d'ensemble).

Si vous gardez la notation de générateur de définition à l'esprit lorsque vous utilisez des compréhensions de liste, elles sont un peu plus faciles à avaler.

HTH!

2
Matt Messersmith

Si vous préférez une façon plus visuelle de comprendre ce qui se passe, cela vous aidera peut-être:

# 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)

... produit la sortie [3, 4]

2
Dave Rove

Introduction

Une compréhension de liste est un moyen déclaratif de haut niveau pour créer une liste en Python. Les principaux avantages des compréhensions sont la lisibilité et la maintenabilité. Beaucoup de gens les trouvent très lisibles, et même les développeurs qui ne les ont jamais vus auparavant peuvent généralement deviner correctement ce que cela signifie.

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

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

Les deux extraits de code produiront squares pour être égal à [0, 1, 4, 9, 16].

Notez que dans le premier extrait, ce que vous saisissez déclare le type de liste que vous souhaitez, tandis que le second spécifie comment le créer. C'est pourquoi une compréhension est un niveau élevé et déclaratif.

Syntaxe

[EXPRESSION for VARIABLE in SEQUENCE]

EXPRESSION est n'importe quelle Python, mais il est typique d'avoir une variable dedans. Cette variable est indiquée dans le champ VARIABLE. SEQUENCE définit la source des valeurs que la variable énumère.

Considérant l'extrait 1, [n ** 2 for n in range(5)]:

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

Notez que si vous vérifiez le type de squares vous obtiendrez que la compréhension de la liste est juste une liste régulière:

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

En savoir plus sur EXPRESSION

L'expression peut être tout ce qui se réduit à une valeur:

  • Expressions arithmétiques telles que n ** 2 + 3 * n + 1
  • Un appel de fonction comme f(n) utilisant n comme variable
  • Une opération de tranche comme s[::-1]
  • La méthode appelle bar.foo()
  • ...

Quelques exemples:

>>> [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']

Filtrage:

L'ordre des éléments dans la liste finale est déterminé par l'ordre de SEQUENCE. Cependant, vous pouvez filtrer les éléments en ajoutant une clause if:

[EXPRESSION for VARIABLE in SEQUENCE if CONDITION]

CONDITION est une expression qui s'évalue en True ou False. Techniquement, la condition ne doit pas dépendre de VARIABLE, mais elle l'utilise généralement.

Exemples:

>>> [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']

N'oubliez pas non plus que Python vous permet d'écrire d'autres types de compréhensions autres que des listes:

  • compréhension de dictionnaire
  • définir les compréhensions
0
lmiguelvargasf