Почему root, возвращаемое из os.walk (), содержит / в качестве разделителя каталогов, а os.sep (или os.path.sep) возвращает \ на Win10? - PullRequest
0 голосов
/ 16 апреля 2020

Почему элемент root, возвращаемый из os.walk () , показывает / в качестве разделителя каталогов, но os.sep (или os.path.sep ) показывает \ на Win10?

Я просто пытаюсь создать полный путь для набора файлов в папке следующим образом:

import os

base_folder = "c:/data/MA Maps"
for root, dirs, files in os.walk(base_folder):
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
            print(os.path.join(root, f))

print(os.path.sep)

Вот что я получаю как вывод:

c:/data/MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:/data/MA Maps\Map_of_Massachusetts_Norfolk_County.png
\

Я понимаю, что некоторые из библиотечных функций python (например, open ()) будут работать со смешанными разделителями пути (по крайней мере, на Windows), но полагаться на этот взлом действительно нельзя доверять во всех библиотеках. Похоже, что элементы, возвращенные из os.walk () и os.path ( .sep или .join () ) должен давать согласованные результаты в зависимости от используемой операционной системы . Кто-нибудь может объяснить, почему происходит это несоответствие?

PS - я знаю, что существует более согласованная библиотека для работы с путями файлов (и множеством других манипуляций с файлами) , называемая pathlib , который был введен в python 3.4 и, похоже, все это исправляет. Если ваш код используется в версии 3.4 или выше, лучше ли использовать методы pathlib для решения этой проблемы? Но если ваш код предназначен для систем, использующих python до 3.4, как лучше всего решить эту проблему?

Вот хорошее базовое c объяснение pathlib : Python 3 Быстрый совет: простой способ справиться с путями к файлам на Windows, Ma c и Linux

Вот мой код и результат с использованием pathlib :

import os
from pathlib import Path

# All of this should work properly for any OS. I'm running Win10.

# You can even mix up the separators used (i.e."c:\data/MA Maps") and pathlib still
# returns the consistent result given below.
base_folder = "c:/data/MA Maps" 

for root, dirs, files in os.walk(base_folder):
    # This changes the root path provided to one using the current operating systems
    # path separator (/ for Win10).
    root_folder = Path(root)
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
             # The / operator, when used with a pathlib object, just concatenates the
             # the path segments together using the current operating system path separator.
             print(root_folder / f)


c:\data\MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:\data\MA Maps\Map_of_Massachusetts_Norfolk_County.png

Это даже можно сделать более кратко, используя только pathlib и понимание списка (со всеми разделителями пути, правильно обработанными для используемой ОС):

from pathlib import Path

base_folder = "c:/data/MA Maps"
path = Path(base_folder)
files = [item for item in path.iterdir() if item.is_file() and 
                                            str(item).endswith(".png") and 
                                            (str(item).find("_N") != -1)]
for file in files:
    print(file)


c:\data\MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:\data\MA Maps\Map_of_Massachusetts_Norfolk_County.png

Это очень Pythoni c и, по крайней мере, я чувствую, что его легко читать и понимать. .iterdir () действительно мощный и делает работу с файлами и директориями достаточно простой и кросс-платформенной. Что ты думаешь?

1 Ответ

2 голосов
/ 16 апреля 2020

Функция os.walk всегда возвращает начальную часть dirpath без изменений от того, что вы ей передаете. Он не пытается нормализовать сами разделители, он просто сохраняет то, что вы ему дали. Он использует стандартные системные разделители для остальной части пути, поскольку объединяет имя каждого подкаталога в каталог root с os.path.join. Вы можете увидеть текущую версию реализации функции os.walk в репозитории CPython источника .

Один из вариантов нормализации разделителей в выходных данных - нормализация базовый путь, который вы передаете в os.walk, возможно, используя pathlib. Если вы нормализуете исходный путь, все выходные данные должны использовать системные разделители пути автоматически, поскольку это будет нормализованный путь, который будет сохранен при рекурсивном обходе, а не нестандартный. Вот очень базовое c преобразование вашего первого блока кода для нормализации base_folder с использованием pathlib при сохранении всего остального кода в его простоте. Лучше, чем ваша версия, использующая больше возможностей pathlib, - это суждение, которое я оставлю на ваше усмотрение.

import os
from pathlib import Path

base_folder = Path("c:/data/MA Maps")    # this will be normalized when converted to a string
for root, dirs, files in os.walk(base_folder):
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
            print(os.path.join(root, f))
...