web-dev-qa-db-fra.com

Commentez Zip (* [itérateur (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)? À quoi ressemblerait-il s'il était écrit avec du code plus détaillé?

87
Oliver Zheng

iter() est un itérateur sur une séquence. [x] * n produit une liste contenant n quantité de 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 extrait un élément de l’itérateur à chaque fois.

x = iter([1,2,3,4,5,6,7,8,9])
print Zip(x, x, x)
93

Les autres bonnes réponses et commentaires expliquent bien les rôles de argument en décompressant et Zip () .

En tant que Ignacio et ujukatzel say, vous passez à Zip() trois références au même itérateur et Zip() crée 3-tuples des entiers - dans l'ordre - de chaque référence à 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 exemple de code plus détaillé:

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

En 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 plus d'informations sur Zip() et map(): http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-Zip/

40
bernie

Je pense qu’une chose qui manque dans toutes les réponses (probablement évidente pour ceux qui connaissent les itérateurs) mais pas aussi évidente pour les autres est: 

Comme 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’itérateur

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

À l'aide de l'itérateur, affiche les valeurs et ne reste que disponible, ainsi pour Zip une fois que 0 est consommé, 1 est disponible, puis 2, etc. Une chose très subtile, mais assez intelligente !!!

27
gabhijit

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

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

Ainsi, lorsque vous utilisez Zip(*[iter(s)]*n), il extrait un élément de tous les trois itérateurs de la liste dans l’ordre. Puisque tous les itérateurs sont le même objet, il ne fait que regrouper la liste en morceaux de n.

8
sttwister

Un seul conseil pour utiliser Zip de cette façon. Il tronquera votre liste si sa longueur n’est pas divisible. Pour contourner ce problème, vous pouvez utiliser itertools.izip_longest si vous pouvez accepter les valeurs de remplissage. Ou vous pouvez 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:], ]

Usage:

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

Impressions:

1, 2, 3
4, 5, 6
7, 8, 9
10, 11
5
jmagnusson

Il est probablement plus facile de voir ce qui se passe dans l'interpréteur python ou ipython avec n = 2:

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

Nous avons donc une liste de deux itérateurs qui pointent sur le même objet itérateur. N'oubliez pas que iter sur un objet retourne un objet itérateur et que, dans ce scénario, il s'agit du même itérateur deux fois en raison du sucre syntaxique *2 python. Les itérateurs ne fonctionnent également qu'une fois.

En outre, Zip prend un nombre quelconque d'itérables ( séquences sont itérables ) et crée un nuplet à partir du ième élément de chacune des séquences d'entrée. Puisque les deux itérateurs sont identiques dans notre cas, Zip déplace le même itérateur deux fois pour chaque Tuple à 2 éléments de la sortie.

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 unpacking (*) s'assure que les itérateurs fonctionnent jusqu'à épuisement, ce qui est dans ce cas jusqu'à ce qu'il n'y ait plus assez d'entrée pour créer un Tuple à 2 éléments.

Cela peut être étendu à n'importe quelle valeur de n et Zip(*[iter(s)]*n) fonctionne comme décrit.

0
akhan