Comment cloner un objet Python generator?
Considérez le scénario suivant:
#!/usr/bin/env python # -*- coding: utf-8 -*- import os walk = os.walk('/home') for root, dirs, files in walk: for pathname in dirs+files: print os.path.join(root, pathname) for root, dirs, files in walk: for pathname in dirs+files: print os.path.join(root, pathname)
je sais que cet exemple est un peu redondant, mais vous devriez considérer que nous avons besoin d'utiliser le même walk
données plus d'une fois. J'ai un scénario de référence et l'utilisation de la même walk
données est obligatoire pour obtenir des résultats utiles.
j'ai essayé walk2 = walk
à cloner et à utiliser dans la deuxième itération, mais il n'a pas travaillé. La question est de... Comment je peux le copier? Est-il toujours possible?
je vous Remercie à l'avance.
5 réponses
Vous pouvez utiliser itertools.tee()
:
walk, walk2 = itertools.tee(walk)
notez que cela pourrait "nécessiter un stockage supplémentaire important", comme le souligne la documentation.
si vous savez que vous allez itérer à travers le générateur entier pour chaque utilisation, vous obtiendrez probablement la meilleure performance en déroulant le Générateur sur une liste et en utilisant la liste plusieurs fois.
walk = list(os.walk('/home'))
Définir une fonction
def walk_home():
for r in os.walk('/home'):
yield r
Ou encore
def walk_home():
return os.walk('/home')
les Deux sont utilisés comme ceci:
for root, dirs, files in walk_home():
for pathname in dirs+files:
print os.path.join(root, pathname)
C'est un bon cas d'utilisation pour functools.partial()
pour faire un rapide de générateur de l'usine:
from functools import partial
import os
walk_factory = partial(os.walk, '/home')
walk1, walk2, walk3 = walk_factory(), walk_factory(), walk_factory()
functools.partial()
n'est difficile à décrire avec des mots, mais ce^ est-ce que c'est.
partiellement remplit fonction-params sans exécuter cette fonction. Par conséquent, il agit comme une usine de fonction/générateur.
cette réponse vise à étendre/préciser ce que les autres réponses ont exprimé. La solution variera nécessairement selon ce que exactement - vous de l'objectif à atteindre.
si vous voulez itérer sur le même résultat exact de os.walk
plusieurs fois, vous devrez initialiser une liste à partir du os.walk
itérable les articles (c'est à dire walk = list(os.walk(path))
).
Si vous devez garantir que les données reste le même, c'est probablement votre seule option. Cependant, il existe plusieurs scénarios dans lesquels cela n'est pas possible ou souhaitable.
- il ne sera pas possible de
list()
un itérable si le résultat est de taille suffisante (c.-à-d. en essayant delist()
un système de fichiers entier peut geler votre ordinateur). - Il n'est pas souhaitable d'
list()
un itérable si vous souhaitez acquérir des données" fraîches " avant chaque utilisation.
Dans le cas où list()
n'est pas adapté, vous aurez besoin d'exécuter votre générateur sur demande. Notez que les générateurs sont éteints après chaque utilisation, de sorte que cela pose un léger problème. Afin de "réexécuter" votre générateur à plusieurs reprises, vous pouvez utiliser le modèle suivant:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
class WalkMaker:
def __init__(self, path):
self.path = path
def __iter__(self):
for root, dirs, files in os.walk(self.path):
for pathname in dirs + files:
yield os.path.join(root, pathname)
walk = WalkMaker('/home')
for path in walk:
pass
# do something...
for path in walk:
pass
susmentionnés modèle de conception vous permettra de garder votre code SEC.