Могу ли я заставить python3 os.walk посещать каталоги в алфавитном порядке? как?

Я хотел бы знать, можно ли заставить os.walk в python3 посещать каталоги в алфавитном порядке. Например, вот каталог и некоторый код, который будет перемещаться по этому каталогу:

ryan:~/bktest$ ls -1 sample
CD01
CD02
CD03
CD04
CD05

--------

def main_work_subdirs(gl):
    for root, dirs, files in os.walk(gl['pwd']):
        if root == gl['pwd']:
            for d2i in dirs:
                print(d2i)

Когда код python попадает в каталог выше, вот вывод:

ryan:~/bktest$ ~/test.py sample
CD03
CD01
CD05
CD02
CD04

Я хотел бы заставить ходить, чтобы посетить эти фильмы в алфавитном порядке, 01, 02... 05. В документе python3 для os.walk говорится:

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

Означает ли это, что я могу навязать алфавитный заказ на os.walk? Если да, то как?

Ответ 1

Да. Вы сортируете dirs в цикле.

def main_work_subdirs(gl):
    for root, dirs, files in os.walk(gl['pwd']):
        dirs.sort()
        if root == gl['pwd']:
            for d2i in dirs:
                print(d2i)

Ответ 2

Я знаю, что на этот вопрос уже дан ответ, но я хотел добавить одну маленькую деталь, и добавление более чем одной строки кода в комментариях - это просто замечательно.

В дополнение к желанию сортировки каталогов я также хотел отсортировать файлы так, чтобы моя итерация по "gl" была последовательной и предсказуемой. Для этого потребовалась еще одна сортировка:

for root, dirs, files in os.walk(gl['pwd']):
  dirs.sort()
  for filename in sorted(files):
    print(os.path.join(root, filename))

И, с выгодой изучения больше о Python, другой (лучший) способ:

from pathlib import Path
[print(p) for p in sorted(Path(gl['pwd']).glob('**/*')) if p.is_dir()]

Ответ 3

Этот ответ не является специфическим для этого вопроса, и проблема немного отличается, но решение может быть использовано в любом случае. Рассмотрим наличие этих файлов ("one1.txt", "one2.txt", "one10.txt"), и содержимое всех из них является строкой "default":

Я хочу пройтись по каталогу, содержащему эти файлы, найти конкретную строку в каждом файле и заменить его именем файла. Если вы используете любые другие методы, которые уже упоминались здесь и в других вопросах (например, dirs.sort() и dirs.sort() sorted(files) и sorted(dirs), результат будет примерно таким:

"one1.txt"--> "one10"
"one2.txt"--> "one1"
"one10.txt" --> "one2"

Но мы хотим, чтобы это было:

"one1.txt"--> "one1"
"one2.txt"--> "one2"
"one10.txt" --> "one10"

Я нашел этот метод, который изменяет содержимое файла в алфавитном порядке:

import re, os, fnmatch

def atoi(text):
    return int(text) if text.isdigit() else text

def natural_keys(text):
    '''
    alist.sort(key=natural_keys) sorts in human order
    http://nedbatchelder.com/blog/200712/human_sorting.html
    (See Toothy implementation in the comments)
    '''
    return [ atoi(c) for c in re.split('(\d+)', text) ]

def findReplace(directory, find, replace, filePattern):
    count = 0
    for path, dirs, files in sorted(os.walk(os.path.abspath(directory))):
        dirs.sort()
        for filename in sorted(fnmatch.filter(files, filePattern), key=natural_keys):
            count = count +1
            filepath = os.path.join(path, filename)
            with open(filepath) as f:
                s = f.read()
            s = s.replace(find, replace+str(count)+".png")
            with open(filepath, "w") as f:
                f.write(s)

Затем запустите эту строку:

findReplace(os.getcwd(), "default", "one", "*.xml")