Исключение каталогов в os.walk

Я пишу script, который спускается в дерево каталогов (используя os.walk()), а затем посещает каждый файл, соответствующий определенному расширению файла. Однако, поскольку некоторые деревья каталогов, в которых мой инструмент будет использоваться, также содержат вспомогательные каталоги, которые, в свою очередь, содержат LOT бесполезные (для целей этого script) вещи, я полагал, d добавьте опцию для указания пользователем списка каталогов для исключения из обхода.

Это достаточно просто с os.walk(). В конце концов, мне решать, действительно ли я хочу посетить соответствующие файлы /dirs, предоставленные os.walk(), или просто пропустить их. Проблема в том, что если у меня есть, например, дерево каталогов:

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

и я хочу исключить uselessStuff и все его дочерние элементы, os.walk() все равно спустится во все (потенциально тысячи) подкаталогов uselessStuff, что, разумеется, замедляет многое. В идеальном мире я мог бы сказать os.walk(), чтобы даже не потрудиться, уступая больше детям бесполезного Stuff, но, насколько мне известно, нет способа сделать это (есть?).

Есть ли у кого-нибудь идеи? Может быть, есть сторонняя библиотека, которая предоставляет что-то подобное?

Ответ 1

Изменение 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):

Когда значение "сверху вниз" истинно, вызывающий может изменить список dirnames на месте (например, через назначение del или slice), и прогулка будет только возвращаться в подкаталоги, имена которых остаются в dirnames; это можно использовать для обрезать поиск...

Ответ 2

... альтернативная форма превосходного ответа @unutbu, который читается чуть более непосредственно, учитывая, что целью является исключение каталогов за счет O (n ** 2) против O (n) времени.

(Для правильного выполнения требуется копирование списка dirs с list(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]