В этой статье мы на примерах разберем, как использовать модуль Pathlib в Python. Все операционные системы имеют разные правила построения путей к файлам. Например, в Linux для путей используется косая черта (слэш, /
), а в Windows — обратная косая черта (обратный слэш, \
).
Эта небольшая разница может вызвать ряд проблем, если вы работаете над проектом и хотите, чтобы разработчики могли работать с вашим кодом и в других операционных системах.
К счастью, если вы программируете на Python, модуль Pathlib сделает за вас всю тяжелую работу. Он обеспечит одинаковую работу ваших путей к файлам в разных операционных системах. Кроме того, данный модуль предоставляет функции и операции, которые помогут вам сэкономить время при обработке путей и управлении ими.
Установка
Pathlib поставляется по умолчанию с Python (версии 3.4 и выше). Однако если вы используете версию Python ниже 3.4, у вас не будет доступа к этому модулю.
Как работает Pathlib?
Чтобы понять, как создается базовый путь с помощью Pathlib, давайте рассмотрим пример. Создадим новый файл Python с именем example.py и поместим его в определенный каталог.
Откройте файл и введите следующее содержимое:
import pathlib p = pathlib.Path(__file__) print(p)
В этом примере мы импортируем модуль Pathlib. Затем мы создаем новую переменную с именем p
для хранения пути. Здесь мы используем объект Path
из Pathlib со встроенной в Python переменной с именем __file__
. Эта переменная служит ссылкой на путь к файлу, в котором мы ее пишем (example.py).
Если мы выведем значение p
, мы получим путь к файлу, в котором мы сейчас находимся:
/home/rochdikhalid/dev/src/package/example.py
Как показано выше, Pathlib создает путь к этому файлу, помещая конкретный скрипт в объект Path
. Pathlib содержит множество объектов, таких как PosixPath()
и PurePath()
, к которым мы еще вернемся.
Pathlib делит пути файловой системы на два разных класса, которые представляют два типа объектов пути: Pure Path и Concrete Path.
Pure Path предоставляет утилиты для обработки пути к файлу и управления им без выполнения операций записи, в то время как Concrete Path позволяет манипулировать и выполнять операции записи в файл.
Другими словами, Concrete Path является подклассом Pure Path. Он наследует манипуляции от родительского класса и добавляет операции ввода/вывода, которые выполняют системные вызовы.
[python_ad_block]Pure Path в Python
Pure Path управляют путем к файлу на вашем компьютере, даже если он принадлежит другой операционной системе.
Например, предположим, что вы работаете в Linux и хотите использовать путь к файлу Windows. Здесь объекты класса Pure path помогут вам заставить путь работать на вашем компьютере. Они сделают это с помощью нескольких базовых операций, таких как создание дочерних путей или доступ к отдельным частям пути.
Однако Pure Path не смогут выполнить некоторые другие операции, такие как создание каталога или файла, потому что на самом деле вы не находитесь в этой операционной системе.
Как использовать Pure Path
Как вы можете видеть на диаграмме выше, Pure Path состоят из трех классов, которые обрабатывают любой путь к файловой системе на вашем компьютере.
PurePath()
— это корневой узел, который обеспечивает операции обработки для каждого объекта пути в Pathlib.
Когда вы создаете экземпляр PurePath()
, он создает два класса для обработки путей Windows и путей, отличных от Windows. PurePath()
создает общий объект пути «agnostic path»
, независимо от операционной системы, в которой вы работаете.
In [*]: pathlib.PurePath('setup.py') Out[*]: PurePosixPath('setup.py')
PurePath()
в приведенном выше примере создает PurePosixPath()
, потому что мы предположили, что работаем на машине с Linux. Но если вы создадите его экземпляр в Windows, вы получите что-то вроде PureWindowsPath('setup.py')
.
PurePosixPath()
— это дочерний узел PurePath()
, реализованный для путей файловой системы, отличной от Windows.
In [*]: pathlib.PurePosixPath('setup.py') Out[*]: PurePosixPath('setup.py')
Вы не получите никакой ошибки, если создадите экземпляр PurePosixPath()
в Windows, потому что этот простой класс не выполняет системных вызовов.
PureWindowsPath()
— это дочерний узел PurePath()
, реализованный для путей файловой системы Windows.
In [*]: pathlib.PureWindowsPath('setup.py') Out[*]: PureWindowsPath('setup.py')
С PureWindowsPath()
дела обстроят так же, как и с PurePosixPath(): поскольку этот класс не выполняет системных вызовов, его создание не вызовет ошибок для других операционных систем.
Свойства PurePath
Каждый подкласс в PurePath()
предоставляет следующие свойства:
1. PurePath().parent
выводит родительский класс:
In [*]: pathlib.PurePath('/src/goo/scripts/main.py').parent Out[*]: PurePosixPath('/src/goo/scripts')
В приведенном выше примере мы используем свойство .parent
, чтобы получить путь к логическому родителю main.py.
2. PurePath().parents[]
выводит предков пути:
In [*]: p = pathlib.PurePath('/src/goo/scripts/main.py') p.parents[0] Out[*]: PurePosixPath('/src/goo/scripts') In [*]: p.parents[1] Out[*]: PurePosixPath('/src/goo')
Нужно обязательно указывать индекс в квадратных скобках, как это показано выше. В Python 3.10 и выше вы также можете использовать срезы и отрицательные значения индекса.
3. PurePath().name
предоставляет имя последнего компонента вашего пути:
In [*]: pathlib.PurePath('/src/goo/scripts/main.py').name Out[*]: 'main.py'
В этом примере последний компонент пути — main.py. Таким образом, свойство .name
выводит имя файла main.py.
4. А PurePath().suffix
предоставляет расширение файла последнего компонента вашего пути:
In [*]: pathlib.PurePath('/src/goo/scripts/main.py').suffix Out[*]: '.py'
Свойство .suffix
, в отличие от .name
, выводит только расширение файла и исключает его имя.
5. PurePath().stem
выводит, наоборот, только имя конечного компонента вашего пути без суффикса:
In [*]: pathlib.PurePath('/src/goo/scripts/main.py').stem Out[*]: 'main'
Как видно выше, свойство .stem
исключает суффикс конечного компонента main.py и предоставляет только имя файла.
Методы PurePath
Кроме того, каждый подкласс PurePath()
предоставляет следующие методы:
1. PurePath().is_absolute()
проверяет, является ли ваш путь абсолютным:
In [*]: p = pathlib.PurePath('/src/goo/scripts/main.py') p.is_absolute() Out[*]: True In [*]: o = pathlib.PurePath('scripts/main.py') o.is_absolute() Out[*]: False
Обратите внимание, что абсолютный путь состоит из корня и имени диска. В этом случае PurePath()
не позволяет нам узнать имя диска.
Если вы используете PureWindowsPath()
, вы можете представить абсолютный путь, содержащий имя диска, например PureWindowsPath('c:/Program Files')
.
2. PurePath().is_relative()
проверяет, принадлежит ли путь другому заданному пути:
In [*]: p = pathlib.PurePath('/src/goo/scripts/main.py') p.is_relative_to('/src') Out[*]: True In [*]: p.is_relative_to('/data') Out[*]: False
В этом примере указанный путь /src
является частью или принадлежит пути p
, в то время как другой указанный путь — /data
— вызывает значение False
, поскольку он не имеет никакого отношения к пути p
.
3. PurePath().joinpath()
объединяет путь с заданными аргументами (дочерние пути):
In [*]: p = pathlib.PurePath('/src/goo') p.joinpath('scripts', 'main.py') Out[*]: PurePosixPath('/src/goo/scripts/main.py')
Обратите внимание, что нет необходимости добавлять слэши в указанные вами аргументы, так как метод .joinpath()
сделает это за вас.
4. PurePath().match()
проверяет, соответствует ли путь заданному шаблону:
In [*]: pathlib.PurePath('/src/goo/scripts/main.py').match('*.py') Out[*]: True In [*]: pathlib.PurePath('/src/goo/scripts/main.py').match('goo/*.py') Out[*]: True In [*]: pathlib.PurePath('src/goo/scripts/main.py').match('/*.py') Out[*]: False
Исходя из приведенных выше примеров, шаблон должен соответствовать пути. Если данный шаблон является абсолютным, путь также должен быть абсолютным.
5. PurePath().with_name()
изменяет имя конечного компонента вместе с его суффиксом:
In [*]: p = pathlib.PurePath('/src/goo/scripts/main.py') p.with_name('app.js') Out[*]: PurePosixPath('/src/goo/scripts/app.js') In [*]: p Out[*]: PurePosixPath('/src/goo/scripts/main.py')
Метод .with_name()
не изменяет имя последнего компонента навсегда. Кроме того, если указанный путь не содержит имени, возникает ошибка, как указано в официальной документации.
6. PurePath().with_stem()
изменяет только имя конечного компонента пути:
In [*]: p = pathlib.PurePath('/src/goo/scripts/main.py') p.with_stem('app.py') Out[*]: PurePosixPath('/src/goo/scripts/app.py') In [*]: p Out[*]: PurePosixPath('/src/goo/scripts/main.py')
Это похоже на метод .with_name()
, но.with_stem()
временно изменяет лишь имя последнего компонента. Кроме того, если указанный путь не содержит имени, произойдет ошибка.
7. PurePath().with_suffix()
временно изменяет суффикс или расширение конечного компонента вашего пути:
In [*]: p = pathlib.PurePath('/src/goo/scripts/main.py') p.with_suffix('.js') Out[*]: PurePosixPath('/src/goo/scripts/main.js')
Если имя данного пути не содержит суффикса, метод .with_suffix()
добавит суффикс за вас:
In [*]: p = pathlib.PurePath('/src/goo/scripts/main') p.with_suffix('.py') Out[*]: PurePosixPath('/src/goo/scripts/main.py')
А если мы не включим суффикс и оставим аргумент пустым, текущий суффикс будет удален.
In [*]: p = pathlib.PurePath('/src/goo/scripts/main.py') p.with_suffix('') Out[*]: PurePosixPath('/src/goo/scripts/main')
Некоторые методы, такие как .with_stem()
и .is_relative_to()
, недавно были добавлены в Python 3.9 и выше. Поэтому, если вы вызовете эти методы с помощью Python 3.8 или ниже, возникнет ошибка.
Concrete Paths в Python
Concrete Paths позволяет обрабатывать, манипулировать и выполнять операции записи над различными путями файловой системы.
Другими словами, этот тип объекта пути помогает нам создать, например, новый файл, новый каталог и выполнять другие операции ввода/вывода, не находясь в этой операционной системе.
Как использовать Concrete Paths
Concrete Paths обрабатывают любой путь к файловой системе и выполняют системные вызовы на вашем компьютере. Эти объекты пути являются дочерними путями PurePath и состоят из трех подклассов, как и PurePath:
1. Path()
является дочерним классом PurePath()
. Он обеспечивает операции обработки с возможностью выполнения операций записи.
Когда вы создаете экземпляр Path()
, он создает два класса для обработки путей Windows и путей, отличных от Windows. Как и PurePath()
, Path()
также создает общий объект пути «agnostic path»
, независимо от операционной системы, в которой вы работаете.
In [*]: pathlib.Path('setup.py') Out[*]: PosixPath('setup.py')
Path()
в приведенном выше примере создает PosixPath()
, потому что мы предполагаем, что работаем на машине с Linux. Но если вы создадите его в Windows, вы получите что-то вроде WindowsPath('setup.py')
2. PosixPath()
— это дочерний класс Path()
и PurePosixPath()
, реализованный для обработки и управления путями файловой системы, отличной от Windows.
In [*]: pathlib.PosixPath('setup.py') Out[*]: PosixPath('setup.py')
Вы получите сообщение об ошибке, если создадите экземпляр PosixPath()
на компьютере с Windows, потому что нельзя выполнять системные вызовы, работая в другой операционной системе.
3. WindowsPath()
— это дочерний класс Path()
и PureWindowsPath()
, реализованный для путей файловой системы Windows.
In [*]: pathlib.WindowsPath('setup.py') Out[*]: WindowsPath('setup.py')
Создание WindowsPath()
, если вы работаете в другой операционной системе, тоже вызовет ошибку.
Свойства Concrete Paths
Поскольку Concrete Paths является подклассом PurePath, мы можем использовать все свойства PurePath()
. Это означает, что мы можем использовать, например, свойство .with_suffix
для добавления суффикса к конкретному пути:
In [*]: p = pathlib.Path('/src/goo/scripts/main') p.with_suffix('.py') Out[*]: PosixPath('/src/goo/scripts/main.py')
Или можем проверить, относится ли указанный путь к исходному пути, с помощью .is_relative_to
:
In [*]: p = pathlib.Path('/src/goo/scripts/main.py') p.is_relative_to('/src') Out[*]: True
Всегда помните, что Concrete Paths наследуют операции обработки от PurePath и добавляют операции записи, которые выполняют системные вызовы и конфигурации ввода/вывода.
Методы Concrete Paths
Каждый подкласс Path()
предоставляет следующие методы для обработки путей и выполнения системных вызовов:
1. Path().itertir()
возвращает содержимое каталога. Допустим, у нас есть папка, содержащая следующие файлы:
data population.json density.json temperature.yml stats.md details.txt
Чтобы вернуть содержимое каталога /data
, вы можете использовать метод .itertir()
:
In [*]: p = pathlib.Path('/data') for child in p.iterdir(): print(child) Out[*]: PosixPath('/data/population.json') PosixPath('/data/density.json') PosixPath('/data/temprature.yml') PosixPath('/data/stats.md') PosixPath('/data/details.txt')
Метод .itertir()
создает итератор, который случайным образом перечисляет файлы.
2. Path().exists()
проверяет, существует ли файл/каталог по текущему пути. Давайте воспользуемся каталогом из предыдущего примера (наш текущий каталог — /data
):
In [*]: p = pathlib.Path('density.json').exists() p Out[*]: True
Метод .exists()
возвращает True
, поскольку данный файл существует в каталоге /data
. Метод возвращает False
, если файл не существует.
In [*]: p = pathlib.Path('aliens.py').exists() p Out[*]: False
То же самое относится и к каталогам: метод возвращает True
, если данный каталог существует, и False
, если его нет.
3. Path().mkdir()
создает новый каталог по заданному пути:
In [*]: p = pathlib.Path('data') directory = pathlib.Path('data/secrets') directory.exists() Out[*]: False In [*]: directory.mkdir(parents = False, exist_ok = False) directory.exists() Out[*]: True
Согласно официальной документации, метод .mkdir()
принимает три аргумента. Мы пока сосредоточимся только на parents
и exists_ok
.
Оба аргумента имеют значение False
по умолчанию. Аргумент parents
вызывает ошибку FileNotFound
в случае отсутствия родителя, тогда как exists_ok
вызывает ошибку FileExists
, если данный каталог уже существует.
В приведенном выше примере вы можете установить для аргументов значение True
, чтобы игнорировать упомянутые ошибки и обновить каталог.
4. Мы также можем создать новый файл по указанному пути, используя метод Path().touch()
:
In [*]: file = pathlib.Path('data/secrets/secret_one.md') file.exists() Out[*]: False In [*]: file.touch(exist_ok = False) file.exists() Out[*]: True
Здесь для exists_ok
тоже можно установить значение True
, чтобы игнорировать ошибку FileExists
и обновлять файл.
5. Path().rename()
переименовывает файл/каталог по указанному пути. Давайте рассмотрим пример, используя наш каталог /data
:
In [*]: p = pathlib.Path('density.json') n = pathlib.Path('density_2100.json') p.rename(n) Out[*]: PosixPath('density_2100.json')
Если вы передадите методу несуществующий файл, он вызовет ошибку FileNotFound
. То же самое относится и к каталогам.
6. Path().read_text()
возвращает содержимое файла в строковом формате:
In [*]: p = pathlib.Path('info.txt') p.read_text() Out[*]: 'some text added'
Кроме того, вы можете использовать метод write_text()
для записи содержимого в файл:
In [*]: p = pathlib.Path('file.txt') p.write_text('we are building an empire') Out[*]: 'we are building an empire'
Обратите внимание, что метод .write_text()
был добавлен в Python 3.5 и недавно обновлен в Python 3.10, где получил некоторые дополнительные параметры.
Важный момент
Вы можете спросить себя, зачем использовать пути файловой системы Windows, ведь каждый пакет должен быть совместим и с другими операционными системами.
Вы правы, если цель состоит в том, чтобы сделать путь, не зависящий от ОС. Но иногда мы не можем этого сделать из-за настроек, уникальных для систем Windows или Posix. Некоторые пакеты нацелены на решение проблем, присутствующих только в экосистеме Windows, и Python поддерживает эти юзкейсы в данной библиотеке.
Заключение
Итак, мы познакомились с модулем Pathlib в Python и на примерах разобрали, как его использовать Надеемся, вы поняли, насколько он полезен для обработки и управления путями файловой системы.
В официальной документации вы найдете больше методов и свойств, которые сможете применить к путям вашей файловой системы.
Перевод статьи «Python Path – How to Use the Pathlib Module with Examples».