Quel est l'objet en Python itertools.répéter?
Chaque utilisation je peux penser pour Python itertools.répéter()
classe, je ne peux penser à un autre tout aussi (voire plus) solution acceptable pour obtenir le même effet. Par exemple:
>>> [i for i in itertools.repeat('example', 5)]
['example', 'example', 'example', 'example', 'example']
>>> ['example'] * 5
['example', 'example', 'example', 'example', 'example']
>>> list(map(str.upper, itertools.repeat('example', 5)))
['EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE']
>>> ['example'.upper()] * 5
['EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE']
Est-il de toute affaire dans laquelle il serait la solution la plus appropriée? Si oui, dans quelles circonstances?
- J'ai ajouté un nouvel élément de réponse qui montre l'original en cas d'utilisation de motivation pour itertools répéter. Aussi, j'ai juste mis à jour le Python docs afin de refléter cette note d'utilisation.
- 3 des 4 exemples de code ne sera pas réellement de travail. La première crée un générateur d'expression, pas un
tuple
(vous vouleztuple(itertools.repeat('example', 5))
), le second multiplie'example'
lui-même pour faire'exampleexampleexampleexampleexample'
parce que('example')
ne pas faire untuple
en premier lieu (vous avez besoin('example',) * 5
), et votre troisième exemple utilisemap
, qui permettrait le retour d'unmap
objet, parce que Python 3map
est paresseux (vous auriez l'envelopper danslist
pour obtenir le résultat fourni). C'est une question intéressante, mais truquer vos exemples de code ça fait mal. - J'ai été assez nouveau pour Python quand j'ai fait ce post et je viens de rapidement tapé quelques exemples sans contrôle de la production réelle. Un peu pédant, mais j'ai corrigé maintenant de toute façon. Merci! 🙂
Vous devez vous connecter pour publier un commentaire.
La
itertools.repeat
fonction est paresseux; il utilise seulement la mémoire nécessaire pour un élément. D'autre part, la(a,) * n
et[a] * n
idiomes créer de n copies de l'objet en mémoire. Pour les cinq éléments, la multiplication de l'idiome est probablement mieux, mais vous remarquerez peut-être un problème de ressource si vous avez eu à répéter quelque chose, disons, un million de fois.Encore, il est difficile d'imaginer que de nombreuses statique utilise pour
itertools.repeat
. Cependant, le fait queitertools.repeat
est un fonction vous permet de l'utiliser dans de nombreuses applications fonctionnelles. Par exemple, vous pourriez avoir un certain fonction de la bibliothèquefunc
qui opère sur un objet iterable d'entrée. Parfois, vous pourriez avoir des pré-construit des listes de différents articles. D'autres fois, vous pouvez le faire fonctionner sur une même liste. Si la liste est grande,itertools.repeat
vous permettront d'économiser de la mémoire.Enfin,
repeat
rend possible la soi-disant "itérateur de l'algèbre" décrite dans leitertools
de la documentation. Même lesitertools
module lui-même utilise lerepeat
fonction. Par exemple, le code suivant est donné comme l'équivalent de la mise en œuvre deitertools.izip_longest
(même si le vrai code est écrit en C). Notez l'utilisation derepeat
sept lignes à partir du bas:[a] * n
ne crée pas de n copies de un en mémoire. Il crée n références à une copie unique d'un. Dans certains cas, la différence peut être très importante; essayeza = [[]] * 5; a[0].append(1)
.Le but principal de itertools.répétez est de fournir un flux de valeurs constantes pour être utilisé avec carte ou zip:
Le but secondaire est qu'il donne un moyen très rapide de la boucle un nombre fixe de fois comme ceci:
C'est plus rapide que:
L'ancien l'emporte, car tout ce qu'il faut faire est de mettre à jour le compteur de référence de l'existant Aucun objet. Ce dernier perd à cause de la range() ou xrange() besoins pour la fabrication de 10 000 integer distinctes des objets.
Note, Guido utilise lui-même que l'accélération de la boucle de la technique des timeit() module. Voir la source à https://hg.python.org/cpython/file/2.7/Lib/timeit.py#l195 :
repeat
est un trésor. Pourquoi est-ce caché dansitertools
et pas intégré?for _ in range(x): do()
est un modèle commun.Votre exemple de
foo * 5
ressemble superficiellement similaire àitertools.repeat(foo, 5)
, mais il est tout à fait différent.Si vous écrivez
foo * 100000
, l'interprète devez créer plus de 100 000 exemplaires defoo
avant de pouvoir vous donner une réponse. C'est donc un très cher et la mémoire de convivialité opération.Mais si vous écrivez
itertools.repeat(foo, 100000)
, l'interprète peut retourner un itérateur qui exerce la même fonction, et n'a pas besoin de calculer un résultat jusqu'à ce que vous en avez besoin-dire, en l'utilisant dans une fonction qui veut connaître chaque résultat dans la séquence.C'est le principal avantage de itérateurs: ils peuvent reporter le calcul d'une partie (ou la totalité) de la liste jusqu'à ce que vous avez vraiment besoin d'une réponse.
for i in range(100000):
et ensuite accéder àfoo
l'intérieur de la boucle au lieu de demander à cette fonction, quelle est la valeur que vous lui avez donné?range
est un itérateur en Python 3, mais en Python 2, il renvoie une liste. En Python 2, utilisezxrange
pour un itérateur; en Python 3, utilisationlist(range(...))
pour une liste.range
et Py2xrange
sont paresseux, mais ils ne sont pas réellement des itérateurs eux-mêmes. Ils sont iterables, pas iteraret. Ils sont immuables séquences (légèrement paralysé sur Python 2xrange
, mais assez complet sur Python 3), seulement ceux qui calculent leur contenu à la demande. Cela fait une différence quand vous réitérer la même deux fois;r = range(10)
(xrange
sur Py2), suivie parsum(r)
puissum(r)
nouveau produira le même résultat à chaque fois; si c'était un itérateur, l'appel de la deuxième serait de produire des0
(parce que le premier appel d'échappement de l'itérateur).C'est un itérateur. Gros indice: c'est dans le module itertools. À partir de la documentation liée à:
De sorte que vous ne jamais avoir tout ça en mémoire. Un exemple où vous souhaitez l'utiliser, il pourrait être
cela vous permettra un nombre arbitraire de
4
s, ou ce que vous pourriez avoir besoin d'une liste infinie de.while True:
et lax
sur la ligne 7 à4
et qu'il ferait exactement la même chose, serait plus lisible, et serait un peu plus rapide. C'est pourquoi je me demandais si il avait eu un but.while True:
serait plus lent quefor x in itertools.repeat(4):
, parce queTrue
n'était pas un mot-clé à cette époque, alorswhile True:
chargé et testé pour truthiness sur chaque boucle pour être sûr que personne n'avait choisi (while 1:
était un vrai sans condition de boucle infinie).repeat
gardé l'itérateur sur la pile (pas de recherche dans le haut-ins portée) et est enregistré que le travail. Heureusement, sur Python 3True
etFalse
sont des mots clés, etwhile True:
est vraiment une inconditionnelle de boucle infinie lors de l'octet de code de niveau.Comme mentionné avant, il fonctionne bien avec
zip
:Un autre exemple:
Résultat:
De le faire sans le répète, j'aurais impliquer
len(fruits)
.inventory = {fruit: 0 for fruit in fruits}
est plus lisible et un peu plus rapide.dict.fromkeys(fruits, 0)
est le plus rapide (pas de seulement trois éléments avec une valeur constante, due à une légère hausse des frais fixes, mais comme le nombre d'éléments dansfruits
augmente,dict.fromkeys
tire à l'avance, à partir d'environ huit articles); asymptotiquement sur ma machine, il fonctionne dans environ 2/3 le temps de ladict
de la compréhension pour d'énormes entrées. Que de 3.6 (avec des garanties de commande pourdict
s),dict.fromkeys(x)
est une façon vraiment efficace de uniquify intrants tout en préservant la commande (à la différence deset(x)
, qui perd de la commande).J'ai l'habitude d'utiliser répéter en collaboration avec la chaîne et du cycle. Voici un exemple:
Met les 2 premiers fruits comme une valeur de 10, puis il passe en boucle les valeurs 1 et 2 pour les autres fruits.