Ответ 1
Вы можете использовать itertools.tee()
:
walk, walk2 = itertools.tee(walk)
Обратите внимание, что это может потребовать значительного дополнительного хранения, как указано в документации.
Рассмотрим этот сценарий:
#!/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)
Я знаю, что этот пример является излишним, но вы должны учитывать, что нам нужно использовать одни и те же данные walk
более одного раза. У меня есть тестовый сценарий, и использование тех же walk
данных является обязательным для получения полезных результатов.
Я пробовал walk2 = walk
клонировать и использовать на второй итерации, но это не сработало. Вопрос... Как я могу его скопировать? Возможно ли это?
Спасибо заранее.
Вы можете использовать itertools.tee()
:
walk, walk2 = itertools.tee(walk)
Обратите внимание, что это может потребовать значительного дополнительного хранения, как указано в документации.
Если вы знаете, что собираетесь перебирать весь генератор для каждого использования, вы, вероятно, получите максимальную производительность, развернув генератор в список и используя список несколько раз.
walk = list(os.walk('/home'))
Определить функцию
def walk_home():
for r in os.walk('/home'):
yield r
Или даже это
def walk_home():
return os.walk('/home')
Оба используются следующим образом:
for root, dirs, files in walk_home():
for pathname in dirs+files:
print os.path.join(root, pathname)
Это хороший пример использования для functools.partial()
сделать быструю фабрику-генератор:
from functools import partial
import os
walk_factory = partial(os.walk, '/home')
walk1, walk2, walk3 = walk_factory(), walk_factory(), walk_factory()
То, что делает functools.partial()
, трудно описать человеческими словами, но это то, для чего оно.
Он частично заполняет функциональные параметры, не выполняя эту функцию. Следовательно, он действует как фабрика функций/генераторов.
Этот ответ призван расширить/уточнить, что высказали другие ответы. Решение обязательно будет меняться в зависимости от того, чего именно вы стремитесь достичь.
Если вы хотите повторять один и тот же результат os.walk
несколько раз, вам нужно будет инициализировать список из os.walk
итеративных элементов (т.е. walk = list(os.walk(path))
).
Если вы должны гарантировать, что данные остаются теми же, это, вероятно, ваш единственный вариант. Однако существует несколько сценариев, в которых это невозможно или желательно.
list()
list()
, если выход имеет достаточный размер (т.е. попытка list()
вся файловая система может заморозить ваш компьютер).list()
повторять, если вы хотите получить "свежие" данные перед каждым использованием.В случае, если list()
не подходит, вам нужно будет запустить генератор по требованию. Обратите внимание, что генераторы гасятся после каждого использования, поэтому это создает небольшую проблему. Чтобы "повторно запустить" ваш генератор несколько раз, вы можете использовать следующий шаблон:
#!/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
Вышеупомянутый шаблон дизайна позволит вам сохранить код DRY.
Этот код "Слушатели Python Generator" позволяет вам иметь много слушателей на одном генераторе, например, os.walk
, и даже иметь кого-то "включенного" позже.
def walkme(): os.walk( '/дом')
m1 = Muxer (walkme) m2 = Muxer (walkme)
тогда m1 и m2 могут работать даже в потоках и обрабатывать их на досуге.
Смотрите: https://gist.github.com/earonesty/cafa4626a2def6766acf5098331157b3
import queue
from threading import Lock
from collections import namedtuple
class Muxer():
Entry = namedtuple('Entry', 'genref listeners, lock')
already = {}
top_lock = Lock()
def __init__(self, func, restart=False):
self.restart = restart
self.func = func
self.queue = queue.Queue()
with self.top_lock:
if func not in self.already:
self.already[func] = self.Entry([func()], [], Lock())
ent = self.already[func]
self.genref = ent.genref
self.lock = ent.lock
self.listeners = ent.listeners
self.listeners.append(self)
def __iter__(self):
return self
def __next__(self):
try:
e = self.queue.get_nowait()
except queue.Empty:
with self.lock:
try:
e = self.queue.get_nowait()
except queue.Empty:
try:
e = next(self.genref[0])
for other in self.listeners:
if not other is self:
other.queue.put(e)
except StopIteration:
if self.restart:
self.genref[0] = self.func()
raise
return e
def __del__(self):
with self.top_lock:
try:
self.listeners.remove(self)
except ValueError:
pass
if not self.listeners and self.func in self.already:
del self.already[self.func]