Comment zip (*[iter (s)]*n) fonctionne-t-il en Python?

s = [1,2,3,4,5,6,7,8,9]
n = 3

zip(*[iter(s)]*n) # returns [(1,2,3),(4,5,6),(7,8,9)]

Comment fonctionne zip(*[iter(s)]*n) ? A quoi ressemblerait-il s'il était écrit avec plus de code verbeux?

83
demandé sur Brickgao 2010-02-10 02:07:21

6 réponses

iter() est un itérateur sur une séquence. [x] * n produit une liste contenant n quantité x , c'est à dire une liste de longueur n , où chaque élément est x . *arg décompose une séquence en arguments pour un appel de fonction. Par conséquent, vous passez le même itérateur 3 fois à zip() , et il tire un article de l'itérateur à chaque fois.

x = iter([1,2,3,4,5,6,7,8,9])
print zip(x, x, x)
90
répondu Ignacio Vazquez-Abrams 2015-12-08 01:17:17

les autres grandes réponses et commentaires expliquent bien les rôles de argument unpacking et zip () .

Comme Ignacio et ujukatzel dites, vous passez à zip() trois références à la même itérateur et zip() fait 3-n-uplets de nombres entiers dans l'ordre-de chaque référence de l'itérateur:

1,2,3,4,5,6,7,8,9  1,2,3,4,5,6,7,8,9  1,2,3,4,5,6,7,8,9
^                    ^                    ^            
      ^                    ^                    ^
            ^                    ^                    ^

et puisque vous demandez un échantillon de code plus verbeux:

chunk_size = 3
L = [1,2,3,4,5,6,7,8,9]

# iterate over L in steps of 3
for start in range(0,len(L),chunk_size): # xrange() in 2.x; range() in 3.x
    end = start + chunk_size
    print L[start:end] # three-item chunks

suivant les valeurs de start et end :

[0:3) #[1,2,3]
[3:6) #[4,5,6]
[6:9) #[7,8,9]

FWIW, vous pouvez obtenir le même résultat avec map() avec un argument initial de None :

>>> map(None,*[iter(s)]*3)
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]

pour en savoir plus sur zip() et map() : http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip /

39
répondu bernie 2017-05-23 10:31:38

je pense qu'une chose qui manque dans toutes les réponses (probablement évidente pour ceux qui connaissent les itérateurs) mais pas si évidente pour les autres est -

puisque nous avons le même itérateur, il est consommé et les éléments restants sont utilisés par le zip. Donc, si nous utilisions simplement la liste et non l'iter par exemple.

l = range(9)
zip(*([l]*3)) # note: not an iter here, the lists are not emptied as we iterate 
# output 
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7), (8, 8, 8)]

en utilisant iterator, pops les valeurs et ne garde disponible, donc pour zip une fois 0 est consommé 1 est disponible, puis 2 et ainsi de suite. Une chose très subtile, mais très intelligente!!!

23
répondu gabhijit 2015-05-21 17:29:40

iter(s) renvoie un itérateur pour S.

[iter(s)]*n fait une liste de n fois le même itérateur pour S.

ainsi, en faisant zip(*[iter(s)]*n) , il extrait un article de tous les trois itérateurs de la liste dans l'ordre. Comme tous les itérateurs sont le même objet, il ne fait que regrouper la liste en morceaux de n .

8
répondu sttwister 2010-02-10 19:43:21

un conseil pour utiliser zip De cette façon. Il tronquera votre liste si sa longueur n'est pas également divisible. Pour contourner ce problème, vous pouvez utiliser les itértools .izip_longest si vous pouvez accepter les valeurs de remplissage. Ou vous pourriez utiliser quelque chose comme ceci:

def n_split(iterable, n):
    num_extra = len(iterable) % n
    zipped = zip(*[iter(iterable)] * n)
    return zipped if not num_extra else zipped + [iterable[-num_extra:], ]

Utilisation:

for ints in n_split(range(1,12), 3):
    print ', '.join([str(i) for i in ints])

Imprime:

1, 2, 3
4, 5, 6
7, 8, 9
10, 11
5
répondu jmagnusson 2013-01-31 16:34:53

il est probablement plus facile de voir ce qui se passe dans Python interpreter ou ipython avec n = 2 :

In [35]: [iter("ABCDEFGH")]*2
Out[35]: [<iterator at 0x6be4128>, <iterator at 0x6be4128>]

Donc, nous avons une liste de deux itérateurs qui pointent vers le même objet itérateur. Rappelez-vous que iter sur un objet renvoie un objet itérateur et dans ce scénario, il est le même itérateur deux fois en raison du *2 Python syntactic sugar. Les itérateurs ne fonctionnent également qu'une seule fois.

en outre, zip prend n'importe quel nombre d'itérables ( séquences sont itérables ) et crée des tuples à partir de l'élément d'entrée de chacune des séquences. Comme les deux itérateurs sont identiques dans notre cas, zip déplace le même itérateur deux fois pour chaque tuple de sortie à 2 éléments.

In [41]: help(zip)
Help on built-in function zip in module __builtin__:

zip(...)
    zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

    Return a list of tuples, where each tuple contains the i-th element
    from each of the argument sequences.  The returned list is truncated
    in length to the length of the shortest argument sequence.

l'opérateur déballage ( * ) assure que les itérateurs courent jusqu'à épuisement ce que dans ce case est jusqu'à ce qu'il n'y ait pas assez d'entrées pour créer un tuple à 2 éléments.

cette valeur peut être étendue à n'importe quelle valeur de n et zip(*[iter(s)]*n) comme décrit.

0
répondu akhan 2018-07-22 06:26:00