os.walkのディレクトリを除外する


147

(os.walk()を使用して)ディレクトリツリーに降りてから、特定のファイル拡張子に一致する各ファイルにアクセスするスクリプトを作成しています。ただし、私のツールが使用される一部のディレクトリツリーにはサブディレクトリも含まれているため、LOTが含まれていますれているため、(このスクリプトの目的で)役に立たないものため、ユーザーが指定するオプションを追加すると考えました走査から除外するディレクトリのリスト。

これはos.walk()で十分簡単です。結局のところ、os.walk()によって生成されたそれぞれのファイル/ディレクトリに実際にアクセスするか、単にスキップするかは、私次第です。問題は、たとえば次のようなディレクトリツリーがある場合です。

root--
     |
     --- dirA
     |
     --- dirB
     |
     --- uselessStuff --
                       |
                       --- moreJunk
                       |
                       --- yetMoreJunk

そして、私は除外するuselessStuffまだ全ての(潜在的に数千人)のサブディレクトリに降ります)とそのすべての子、os.walkを(uselessStuff、多くのダウン物事を遅く言うまでもないです、、。理想的な世界では、私はos.walk()に、役に立たないStuffの子をこれ以上生成しないように指示することができますが、私の知る限り、それを行う方法はありません(ありますか?)。

誰かがアイデアを持っていますか?たぶん、そのようなものを提供するサードパーティのライブラリはありますか?

回答:


242

dirs インプレースを変更すると、がアクセスした(後続の)ファイルとディレクトリが削除されos.walkます。

# exclude = set([...])
for root, dirs, files in os.walk(top, topdown=True):
    dirs[:] = [d for d in dirs if d not in exclude]

ヘルプ(os.walk)から:

topdownがtrueの場合、呼び出し元はdirnamesリストをインプレースで(たとえば、delまたはスライスの割り当てを介して)変更でき、walkはdirnamesに名前が残っているサブディレクトリにのみ再帰します。これは、検索のプルーニングに使用できます...


31
なんでdirs[:] =
2014

56
@ben:インプレースをdirs[:] = value変更dirs ます。dirsコンテナーを変更せずにリストの内容を変更します。help(os.walk)言及あなたは道が影響を与えることを望む場合、これは必要とされているos.walkサブディレクトリを横断します。(元のリストを変更せずにdirs = value、変数dirsを新しいリストに再割り当て(または「バインド」)するだけdirsです。)
unutbu

6
また、使用することができますfilter()dirs[:] = list(filter(lambda x: not x in exclude, dirs))
NuclearPeon

2
@ p014k:あなたはあなた自身のジェネレータ関数呼び出し書くことができますos.walkし、収量をroot, dirs, files除いた後に.git(または任意の他、あなたが望む)からdirs
unutbu

3
@unutbuあるケースでは、この最適化により走査時間が100秒以上から約2秒に短縮されたことをお知らせします。それは私が価値ある最適化と呼んでいるものです。:D
2016

7

... O(n ** 2)対O(n)時間を犠牲にしてディレクトリを除外することを意図していることを考えると、@ unutbuの優れた回答のもう1つの形式は、もう少し直接読むことができます。

list(dirs)正しく実行するには、dirsリストのコピーを作成する必要があります)

# exclude = set([...])
for root, dirs, files in os.walk(top, topdown=True):
    [dirs.remove(d) for d in list(dirs) if d in exclude]

5
メモリを犠牲にしてより直接的になりたい場合は、を書くことをお勧めしますdirs[:] = set(dirs) - exclude。少なくとも\ $ O(n)\ $のままであり、その副作用のみについて理解を構築していない...
301_Moved_Permanently

3
これは本当に悪いことではありませんが、私の意見では慣用的なPythonではありません。
Torsten Bronger 2016

for d in list(dirs)少し奇妙です。dirsはすでにリストです。そして、あなたが持っているのは、実際にはリストの理解ではありません。dirs.remove(d)は何も返さないので、Nonesの完全なリストになります。@Torstenに同意します。
シーナハーン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.