Управление путями файловой системы Python 3 с помощью модуля pathlib
Development, Python | Комментировать запись
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: pathlib, Python, Python 3