web-dev-qa-db-fra.com

Python compréhension de liste pour les boucles

Je lis le Python et je me sens confus à propos de cette partie:

La compréhension de la liste prend en charge plus d'une déclaration. Il évaluera les éléments de tous les objets de manière séquentielle et bouclera sur les objets plus courts si un objet est plus long que les autres.

>>>item = [x+y for x in 'cat' for y in 'pot']
>>>print item
['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'to', 'tt']

Je comprends l'utilisation de boucles imbriquées mais je ne reçois pas

... et bouclera sur les objets plus courts si un objet est plus long que les autres

Qu'est-ce que ça veut dire? (plus court, plus long ...)

16
ChandlerQ

Ce type de boucles imbriquées crée un produit cartésien des deux séquences. Essayez-le:

>>> [x+y for x in 'cat' for y in 'potty']
['cp', 'co', 'ct', 'ct', 'cy', 'ap', 'ao', 'at', 'at', 'ay', 'tp', 'to', 'tt', 'tt', 'ty']
>>> [x+y for x in 'catty' for y in 'pot']
['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'to', 'tt', 'tp', 'to', 'tt', 'yp', 'yo', 'yt']

Le intérieur 'x' dans la liste de compréhension ci-dessus (c'est-à-dire le for x in 'cat' partie) est identique à extérieur for x in 'cat': dans cet exemple:

>>> li=[]
>>> for x in 'cat':
...    for y in 'pot':
...       li.append(x+y)
# li=['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'to', 'tt']

Donc, l'effet de raccourcir ou de raccourcir un est le même que d'allonger la boucle 'x' ou 'y' en deux boucles imbriquées:

>>> li=[]
>>> for x in 'catty':
...    for y in 'pot':
...       li.append(x+y)
... 
>>> li==[x+y for x in 'catty' for y in 'pot']
True

Dans chaque cas, la séquence la plus courte est bouclée à nouveau jusqu'à épuisement de la séquence la plus longue. Contrairement à Zip où l'appariement se terminerait à la fin de la séquence la plus courte.

Modifier

Il semble y avoir confusion (dans les commentaires) entre les boucles imbriquées et Zip.

Boucles imbriquées:

Comme indiqué ci-dessus, ceci:

[x+y for x in '12345' for y in 'abc']

est identique à deux boucles imbriquées "for" avec "x" la boucle externe.

Les boucles imbriquées exécuteront la boucle intérieure y la plage de x dans les temps de boucle extérieure.

Alors:

>>> [x+y for x in '12345' for y in 'ab']
    ['1a', '1b',   # '1' in the x loop
     '2a', '2b',   # '2' in the x loop, b in the y loop
     '3a', '3b',   # '3' in the x loop, back to 'a' in the y loop
     '4a', '4b',   # so on
     '5a', '5b'] 

Vous pouvez obtenir le même résultat avec produit d'itertools:

>>> from itertools import product
>>> [x+y for x,y in product('12345','ab')]
['1a', '1b', '2a', '2b', '3a', '3b', '4a', '4b', '5a', '5b']

Zip est similaire mais s'arrête une fois la séquence plus courte épuisée:

>>> [x+y for x,y in Zip('12345','ab')]
['1a', '2b']
>>> [x+y for x,y in Zip('ab', '12345')]
['a1', 'b2']

Vous pouvez utiliser itertools pour un Zip qui compressera jusqu'à ce que la séquence la plus longue soit épuisée, mais le résultat est différent:

>>> import itertools
>>> [x+y for x,y in itertools.Zip_longest('12345','ab',fillvalue='*')]
['1a', '2b', '3*', '4*', '5*'] 
22
dawg

Eh bien, la documentation Python ne parle pas d'un tel cas court/long: http://docs.python.org/2/tutorial/datastructures.html#list-comprehensions . Avoir deux "pour" dans une compréhension de liste signifie avoir deux boucles. L'exemple pointé par @drewk est correct.

Permettez-moi de le copier pour des raisons d'explication:

>>> [x+y for x in '123' for y in 'pot']
['1p', '1o', '1t', '2p', '2o', '2t', '3p', '3o', '3t']
>>>
>>> [x+y for x in '1' for y in 'pot']
['1p', '1o', '1t']
>>>

Dans les deux cas, le premier "pour" forme la boucle extérieure et le second "pour" forme la boucle intérieure. C'est le seul invariant ici.

6
Manoj Pandey