Как специалист по исследованию данных, я ежедневно работаю с путями и файлами для чтения и записи данных.
Обычно я использую модуль Python os.path
для выполнения таких операций, как объединение путей, проверка содержимого каталога и создание папок. С помощью этого модуля можно с легкостью получить доступ к файловой системе.
В этой статье я опровергну эту практику, представив другую библиотеку управления путями — Pathlib.
Мы посмотрим, как работает эта библиотека, чем она отличается от модуля os.path, какие возможности и преимущества она предоставляет и когда ее следует (или не следует) использовать.
Проблема модуля OS
Модуль os
популярен, и он существует уже долгое время. Однако мне всегда казалось, что он обрабатывает пути неестественным образом. Вот причины, которые заставили меня усомниться в использовании этого модуля
ОS
— большой модуль. В нем, конечно, есть подмодульpath
для управления путями и их объединения. Однако если нужно выполнить системные операции с этими путями (создать папку, перечислить содержимое внутри нее или переименовать и удалить файл), то приходится использовать другие методы, которые либо присутствуют где-то еще в иерархии пакетов (os.makedirs,
os.listdir,
os.rename
и т. д.), либо импортированы из других модулей, таких какshutil
илиglob
. Хорошенько “покопавшись”, вы сможете найти эти методы, но это кажется ненужным усилием.OS
представляет пути в их самом грубом формат — строковых значениях. Это сильно ограничивает возможности, так как не дает прямого доступа к такой информации, как свойства файла и его метаданные, и не позволяет выполнять операции с файловой системой путем вызова некоторых специальных методов.
Например, чтобы проверить, существует ли путь, вы вводите что-то вродеos.path.exists(some_path)
. Но не проще ли было бы получить доступ к этой информации непосредственно из объектаpath
через метод или атрибут класса?- Модуль
os
не позволяет находить пути, соответствующие заданному шаблону, внутри иерархии. Допустим, нужно рекурсивно найти все файлы__init__.py
внутри сложной структуры папок. Чтобы сделать это, придется объединитьos
с другим модулем под названиемglob
. К этому, конечно, можно привыкнуть, но неужели вам нужно два модуля для выполнения такой задачи? - Это скорее вопрос личного предпочтения, но я всегда считал синтаксис
os
немного громоздким.
Что такое Pathlib?
Pathlib является частью стандартной библиотеки Python. Она была введена в версию Python 3.4 (см. PEP 428) с целью представления путей не в виде простых строк, а в виде многофункциональных объектов Python с множеством полезных методов и атрибутов.
Вот определение из официальной документации:
“Цель этой библиотеки — предоставить простую иерархию классов для работы с путями файловой системы и обычными операциями, которые пользователи выполняют с ними”.
Pathlib призвана облегчить вышеупомянутые трудности, возникающие при использовании модуля os
. Давайте посмотрим на некоторые из возможностей этого компонента Python.
Более подробную информацию об этой библиотеке можно найти в официальной документации.
У Pathlib более интуитивно понятный синтаксис
Чтобы создать путь с помощью Pathlib, нужно импортировать класс Path и передать ему строку. Эта строка указывает на путь в файловой системе, который не обязательно должен существовать.
from pathlib import Path
path = Path("/Users/ahmed.besbes/projects/posts")
path
# PosixPath('/Users/ahmed.besbes/projects/posts')
print(cwd)
# /Users/ahmed.besbes/projects/posts
Теперь у вас есть доступ к объекту Path
. Как выполнять простые операции?
- Объединение путей
Pathlib
использует оператор /
для объединения путей. Сначала эта функция может показаться забавной, но на самом деле она облегчает чтение кода.
Давайте сравним. Чтобы объединить пути с помощью модуля os
, нужно сделать примерно следующее:
import os
in_file = os.path.join(os.getcwd(), "raw_data", "input.xlsx")
out_file = os.path.join(os.getcwd(), "processed_data", "output.xlsx")
С Pathlib тот же код будет выглядеть вот так:
from pathlib import Path
in_file = Path.cwd() / "raw_data" / "input.xlsx"
out_file = Path.cwd() / "processed_data" / "output.xlsx"
По сути, Pathlib усовершенствовал оператор /
для выполнения объединения путей.
- Получение текущего рабочего/ домашнего каталога
Под эту задачу уже предусмотрены методы:
from path import Pathlib
cwd = Path.cwd()
home = Path.home()
- Чтение файла
Вы можете либо использовать open
с контекстным менеджером, как это делается в случае обычного пути, либо использовать read_text
или read_bytes
.
>>> path = pathlib.Path.home() / file.txt'
>>> path.read_text()
Очевидно, что функций у Pathlib гораздо больше. Рассмотрим наиболее интересные из них.
Простое создание файлов и каталогов
После того, как объект Path создан, он может самостоятельно выполнять операции с файловой системой, вызывая свои внутренние методы. Например, объект может создать папку или открыть файл, просто вызвав методы mkdir
и touch
.
Вот как объект Path создает папку:
from pathlib import Path
random_folder = Path("random_folder")
random_folder.exists()
# False
random_folder.mkdir(exist_ok=True)
random_folder.exists()
# True
Тот же принцип используется и при создании файлов:
from pathlib import Path
random_file = Path("random_file.txt")
random_file.exists()
# False
random_file.touch()
random_file.exists()
# True
Конечно, вы можете выполнить эти операции с помощью модуля os
, но для этого необходимо вызвать другую функцию, например makedirs
:
import os
random_folder = os.path.join("random_folder")
os.makedirs(random_folder, exist_ok=True)
Перемещение по иерархии файловой системы с помощью обращения к родителям
Каждый объект Path имеет свойство parent
, которое возвращает объект Path родительской папки. Это облегчает работу с большими иерархиями папок. Поскольку Path являются объектами, для доступа к нужному родителю можно использовать цепочку методов:
from pathlib import Path
path = Path("/Users/ahmed.besbes/Downloads/")
path
# PosixPath('/Users/ahmed.besbes/Downloads')
path.parent
# PosixPath('/Users/ahmed.besbes')
path.parent.parent
# PosixPath('/Users')
path.parent.parent.parent
# PosixPath('/')
Чтобы избежать построения цепочки свойств parent
для доступа к n-му предыдущему родителю, можно вызвать свойство parents
, которое возвращает список всех родителей, предшествующих текущей папке:
import pathlib
path = Path("/Users/ahmed.besbes/Downloads/")
list(path.parents)
# [PosixPath('/Users/ahmed.besbes'), PosixPath('/Users'), PosixPath('/')]
Выполнение итераций в каталогах и подгонка под шаблон
Предположим, у вас есть объект Path, который указывает на каталог. Pathlib позволяет легко итерировать содержимое этого каталога, а также получать файлы и папки, соответствующие определенному шаблону.
Помните модуль glob
, который импортировался вместе с модулем os
, чтобы получить пути, соответствующие шаблону?
Так вот, объекты Path включают метод glob
и его рекурсивную версию rglob
для выполнения аналогичных задач, но с гораздо более легким синтаксисом.
Допустим, нужно подсчитать количество файлов Python в конкретной папке. Вот как это можно сделать:
from pathlib import Path
# Действительно, довольно большая папка!
path = Path("/Users/ahmed.besbes/anaconda3/")
python_files = path.rglob("**/*.py")
next(python_files)
# PosixPath('/Users/ahmed.besbes/anaconda3/bin/rst2xetex.py')
next(python_files)
# PosixPath('/Users/ahmed.besbes/anaconda3/bin/rst2latex.py')
next(python_files)
# PosixPath('/Users/ahmed.besbes/anaconda3/bin/rst2odt_prepstyles.py')
...
len(list(python_files))
# 67481
Каждый объект Path имеет множество полезных атрибутов
Каждый объект Path имеет множество полезных методов и атрибутов, которые совершают операции, ранее выполнявшиеся другими библиотеками, а не os
(например, glob
и shutil
).
.exists()
: проверка наличия пути в файловой системе..is_dir()
: проверка соответствия пути каталогу..is_file()
: проверка соответствия пути файлу..is_absolute()
: проверка абсолютности пути..chmod()
: изменение режима файла и разрешений.is_mount()
: проверка того, является ли путь точкой монтирования..suffix
: получение расширение файла.
Это еще не все методы. Вы можете ознакомиться с полным их перечнем здесь.
Это была краткая статья о некоторых возможностях Pathlib. Если вы используете версию Python +3.4 и думаете о переходе на Pathlib, смело делайте это. Переход с os на Pathlib довольно прост.
Читайте также:
- Как проверить наличие файла или каталога в R, Python и Bash?
- Python PyQt5: современные графические интерфейсы для Windows, MacOS и Linux
- Как PyPy ускоряет Python до уровня C?
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Ahmed Besbes: Why You Should Start Using Pathlib as an Alternative to the OS Module