このシナリオを考えてみましょう:
#!/ usr/bin/env python #-*-coding:utf-8-*- import os walk = os.walk( ' /home') walk、dirs、dirsのファイルの場合: dirs + filesのパス名の場合: print os.path.join(root、pathname ) root、dirs、ウォークインファイルの場合: dirs + filesのパス名の場合: print os.path.join(root、pathname)
この例は多少冗長であることは知っていますが、同じwalk
データを複数回使用する必要があることを考慮する必要があります。私はベンチマークシナリオを持っています。同じwalk
データの使用は、役立つ結果を得るために必須です。
私はもう試した walk2 = walk
を複製して2回目の反復で使用しますが、機能しませんでした。問題は...どうすればコピーできますか?可能ですか?
前もって感謝します。
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()
が人間の言葉で説明するのは難しいですが、これはそのためです。
関数の一部は、その関数を実行せずにfunction-paramsに入力します。したがって、関数/ジェネレータファクトリとして機能します。
この回答は、他の回答が表明した内容を拡張/詳しく説明することを目的としています。解決策は必然的に、達成したい正確にによって異なります。
_os.walk
_のまったく同じ結果を複数回繰り返したい場合は、_os.walk
_イテラブルの項目(つまり、walk = list(os.walk(path))
)からリストを初期化する必要があります。
データが同じであることを保証する必要がある場合は、それがおそらく唯一の選択肢です。ただし、これが不可能または望ましくないシナリオがいくつかあります。
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ジェネレーターリスナー」コードを使用すると、os.walk
のように、単一のジェネレーターに多数のリスナーを設定したり、後で誰かが "チャイムイン"したりすることができます。
def walkme():os.walk( '/ home')
m1 = Muxer(walkme)m2 = Muxer(walkme)
次に、m1とm2はスレッドで実行され、自由に処理できます。
参照: https://Gist.github.com/earonesty/cafa4626a2def6766acf5098331157b
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]