Какая альтернатива `os.walk` выбрасывает StopIteration, только если он посетил каждый каталог в дереве? - PullRequest
0 голосов
/ 01 октября 2019

os.walk возвращает итератор, который предназначен для посещения каждого каталога в некотором дереве. Я хочу что-то вроде os.walk, которое будет выдавать StopIteration (или что-то в этом роде) тогда и только тогда, когда посещен каждый каталог в дереве.

os.walk выбрасывает StopIteration, когда каждый каталог в дереве посещен или . При этом возникает некоторая ошибка. Например, рассмотрим следующую распечатку и сообщение об ошибке:

checking for empty folders under F:\

checking for empty folders under F:\$RECYCLE.BIN

checking for empty folders under F:\$RECYCLE.BIN\S-1-5-18

Traceback (most recent call last):
  File "D:/FILE_MGMT_PYTHON/DRIVER.PY", line 228, in remove_empty_dirs
    directories = next(os.walk(cur))[1]
StopIteration

Мой диск F:\ содержит тысячи каталогов и файлов. Невозможно, чтобы их всех посетили.

Предостережение: я не сделал F:\ корнем для прогулки.
F:\$RECYCLE.BIN\S-1-5-18 является корнем для прогулки. Таким образом, итератор никогда не поднимется выше F:\$RECYCLE.BIN\S-1-5-18

Сначала я подумал, что F:\$RECYCLE.BIN\S-1-5-18 пуст, и поэтому F:\$RECYCLE.BIN\S-1-5-18 был последним каталог под деревом с корнем в F:\$RECYCLE.BIN\S-1-5-18

Однако next(os.walk(path_to_an_empty_directory)) делает НЕ throw StopIteration

import os
import pathlib
import shutil

if True:
   path = pathlib.Path(os.getcwd()) / "I_am_a_directory"
   if path.is_dir():
       shutil.rmtree(path)
   os.mkdir(path)
   print(next(os.walk(path))[0])
   print("os.walk did not raise ", StopIteration.__name__)

РЕДАКТИРОВАТЬ:

Мой код выглядит примерно так:

import os
import pathlib

def take_a_walk(xpath):

    ipath = pathlib.Path(str(xpath))

    print(''.join(str(x) for x in [
        "VISITED ", str(ipath)
    ]))

    children = next(os.walk(ipath))[1]
    children = [ipath / child for child in children]
    for child in children:
        take_a_walk(child)
    return "Fahrvergnugen"

take_a_walk('F:\\')

1 Ответ

0 голосов
/ 03 октября 2019

Нам не нужна альтернатива os.walk per se, нам просто нужно присвоить аргумент параметру onerror.

По умолчанию, если при проверке пути возникает ошибка, итератор, возвращаемый os.walk, пропустит текущий путь и перейдет к следующему пути.

def r(err):
    raise err

os.walk(path, onerror=r)
...