Управление путями файловой системы Python 3 с помощью модуля pathlib

Python 3 включает модуль pathlib для управления путями файловой системы независимо от операционной системы. Модуль pathlib похож на os.path, но pathlib предлагает интерфейс более высокого уровня и часто в разы удобнее, чем os.path.

Файлы на компьютере можно идентифицировать с помощью иерархических путей. Например, мы можем идентифицировать файл wave.txt на компьютере по этому пути:

/Users/planetearth/ocean/wave.txt

Операционные системы представляют пути немного по-разному. Windows может представлять путь к файлу wave.txt как C:\Users\planetearth\ocean\wave.txt.

Модуль pathlib будет вам полезен, если в вашей программе Python вы создаете или перемещаете файлы в файловой системе, запрашиваете списки файлов, которые соответствуют заданному расширению или шаблону, или создаете подходящие для операционной системы пути к файлам на основе коллекций необработанных строк. Для выполнения многих из этих задач вы можете использовать другие инструменты (например, модуль os.path), но модуль pathlib позволяет работать с ними в удобочитаемом формате и с минимальным объемом кода.

В этом мануале мы рассмотрим несколько способов использования модуля pathlib для представления и управления путями файловой системы.

Требования

Чтобы получить максимальную пользу от этого мануала, рекомендуем сначала изучить основы программирования на Python 3. Вы можете найти полезную информацию о Python 3 здесь.

Создание класса Path

Модуль pathlib предоставляет несколько классов, но одним из наиболее важных является класс Path. Экземпляры класса Path отображают путь к файлу или каталогу в файловой системе компьютера.

Например, следующий код создает экземпляр Path, представляющий часть пути к файлу wave.txt:

from pathlib import Path
wave = Path("ocean", "wave.txt")
print(wave)

Если мы запустим этот код, мы получим следующий результат:

ocean/wave.txt

from pathlib import Path делает класс Path доступным для программы. Затем Path («ocean», «wave.txt») создает новый экземпляр Path. Вывод показывает, что Python добавил соответствующий разделитель операционной системы (/) между двумя компонентами пути, которые мы ему задали: «ocean» и «wave.txt».

Примечание: В зависимости от операционной системы ваш результат может несущественно отличаться от результатов, показанных в этом руководстве. Например, если вы работаете в Windows, в данном случае вы получите ocean\wave.txt.

В настоящее время объект Path, присвоенный переменной wave, содержит относительный путь. Другими словами, файл ocean/wave.txt может существовать в нескольких местах нашей файловой системы. Например, он может находиться в /Users/user_1/ocean/wave.txt или в /Users/user_2/research/ocean/wave.txt – мы не указали, какой именно из этих файлов мы имеем в виду. Абсолютный путь – это путь, который относится к одному расположению в файловой системе.

Вы можете использовать Path.home(), чтобы получить абсолютный путь к домашнему каталогу текущего пользователя:

home = Path.home()
wave_absolute = Path(home, "ocean", "wave.txt")
print(home)
print(wave_absolute)

Если мы запустим этот код, мы получим примерно следующий результат:

/Users/planetearth
/Users/planetearth/ocean/wave.txt

Примечание: Как упоминалось ранее, результат будет зависеть от вашей операционной системы. Ваш домашний каталог, конечно, также будет отличаться от нашего условного /Users/planetearth.

Path.home() возвращает экземпляр Path с абсолютным путем к домашнему каталогу текущего пользователя. Затем мы передаем этот экземпляр Path и строки «ocean» и «wave.txt» в другой конструктор Path, чтобы создать абсолютный путь к файлу wave.txt. Выходные данные показывают, что первая строка – это домашний каталог, а вторая — это домашний каталог плюс ocean/wave.txt.

Этот пример также иллюстрирует важную особенность класса Path: конструктор Path принимает как строки, так и уже существующие объекты Path.

Давайте более внимательно рассмотрим поддержку строк и объектов Path в конструкторе Path:

shark = Path(Path.home(), "ocean", "animals", Path("fish", "shark.txt"))
print(shark)

Если мы запустим этот код, мы получим такой вывод:

/Users/planetearth/ocean/animals/fish/shark.txt

shark – это путь к файлу, который мы создали, используя объекты Path (Path.home() и Path(«fish», «shark.txt»)). Конструктор Path обрабатывает оба типа объектов и аккуратно объединяет их, используя соответствующий разделитель операционной системы, в данном случае /.

Доступ к атрибутам файла

Теперь, когда вы научились создавать экземпляры Path, давайте посмотрим, как использовать эти экземпляры для доступа к информации о файле.

Мы можем использовать атрибуты name и suffix для доступа к именам и суффиксам файлов:

wave = Path("ocean", "wave.txt")
print(wave)
print(wave.name)
print(wave.suffix)

Запустив этот код, мы получим следующий результат:

/Users/planetearth/ocean/wave.txt
wave.txt
.txt

Этот вывод показывает, что имя файла в конце пути – wave.txt, а суффикс этого файла — .txt.

Экземпляры Path также предлагают функцию with_name, которая позволяет легко создавать новые объекты Path с другими именами:

wave = Path("ocean", "wave.txt")
tides = wave.with_name("tides.txt")
print(wave)
print(tides)

Если мы запустим этот код, мы получим следующий результат:

ocean/wave.txt
ocean/tides.txt

Код сначала создает экземпляр Path, который указывает на файл wave.txt. Затем мы вызываем метод with_name для wave, чтобы вернуть второй экземпляр Path, указывающий на новый файл tides.txt. Часть пути ocean/ (что указывает на каталог) остается неизменной, и в результате остается конечный путь – ocean/tides.txt.

Доступ к порождающим объектам

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

shark = Path("ocean", "animals", "fish", "shark.txt")
print(shark)
print(shark.parent)

Если мы запустим этот код, мы получим вывод, который выглядит следующим образом:

ocean/animals/fish/shark.txt
ocean/animals/fish

Атрибут parent в экземпляре Path возвращает ближайший порождающий объект данного пути. В этом случае он возвращает каталог, содержащий файл shark.txt: ocean/animals/fish.

Мы можем получить доступ к атрибуту parent несколько раз подряд, чтобы пройти вверх по дереву порождающих объектов данного файла:

shark = Path("ocean", "animals", "fish", "shark.txt")
print(shark)
print(shark.parent.parent)

Запустив этот код, вы получите:

ocean/animals/fish/shark.txt
ocean/animals

Результат похож на предыдущий, но в этот раз мы прошли еще один уровень выше, обратившись к атрибуту .parent дважды. Два каталога выше файла shark.txt — это каталог ocean/animals.

Вывод списка файлов с помощью метода glob

Также класс Path можно использовать для вывода списка файлов с помощью метода glob.

Допустим, у нас есть такая структура каталогов:

└── ocean
├── animals
│   └── fish
│       └── shark.txt
├── tides.txt
└── wave.txt

Каталог ocean содержит файлы tides.txt и wave.txt. У нас есть файл shark.txt, вложенный в каталог ocean, каталог animals и каталог fish: ocean/animals/fish.

Чтобы перечислить все файлы .txt в каталоге ocean, можно использовать такой код:

for txt_path in Path("ocean").glob("*.txt"):
print(txt_path)

Этот код даст следующий результат:

ocean/wave.txt
ocean/tides.txt

Шаблон метода glob «*.txt» находит все файлы, заканчивающиеся на .txt. Поскольку данный пример кода выполняет этот метод в каталоге ocean, он возвращает два файла: wave.txt и tides.txt.

Примечание: Если вы хотите продублировать результаты, показанные в этом примере, в вашей системе, вам необходимо имитировать в ней структуру каталогов, показанную здесь.

Метод glob также можно использовать рекурсивно. Чтобы вывести все файлы .txt в каталоге ocean и во всех его подкаталогах, можно написать такой код:

for txt_path in Path("ocean").glob("**/*.txt"):
print(txt_path)

Если мы запустим его, мы получим следующий результат:

ocean/wave.txt
ocean/tides.txt
ocean/animals/fish/shark.txt

Часть шаблона ** будет рекурсивно отвечать этому каталогу и всем его подкаталогам. Таким образом, мы получаем не только файлы wave.txt и tides.txt, а и файл shark.txt, который был вложен в ocean/animals/fish.

Вычисление относительных путей

Для вычисления путей относительно друг друга можно использовать метод Path.relative_to. Метод relative_to полезен, если, например, вы хотите получить часть длинного пути к файлу.

Давайте рассмотрим следующий код:

shark = Path("ocean", "animals", "fish", "shark.txt")
below_ocean = shark.relative_to(Path("ocean"))
below_animals = shark.relative_to(Path("ocean", "animals"))
print(shark)
print(below_ocean)
print(below_animals)

Если вы запустите его, вы получите такой вывод:

ocean/animals/fish/shark.txt
animals/fish/shark.txt
fish/shark.txt

Метод relative_to возвращает новый объект Path относительно данного аргумента. В нашем примере мы вычисляем путь к shark.txt относительно каталога ocean, а затем относительно каталогов ocean и animals.

Если relative_to не может вычислить ответ, потому что получил неправильный путь, он выдает ValueError:

shark = Path("ocean", "animals", "fish", "shark.txt")
shark.relative_to(Path("unrelated", "path"))

К примеру, из нашего кода мы могли бы получить примерно такое сообщение ValueError:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/Python3.8/pathlib.py", line 899, in relative_to
raise ValueError("{!r} does not start with {!r}"
ValueError: 'ocean/animals/fish/shark.txt' does not start with 'unrelated/path'

unrelated/path не является частью ocean/animals/fish/shark.txt, поэтому Python не может вычислить относительный путь.

Заключение

Модуль pathlib – мощный компонент стандартной библиотеки Python, который позволяет нам быстро управлять путями файловой системы в любой операционной системе. В этом мануале вы научились использовать некоторые ключевые утилиты pathlib для доступа к атрибутам файлов, вывода списка файлов с помощью шаблонов glob и просмотра порождающих файлов и каталогов.

Модуль pathlib предоставляет другие классы и утилиты, которые мы не рассматривали в этом руководстве. Теперь, когда вы владеете основами, вы можете обратиться к документации модуля pathlib, чтобы узнать больше об остальных классах и утилитах pathlib.

Tags: , ,

Добавить комментарий