Модуль pathlib, представленный в Python 3.4 (PEP 428), совершил революцию в работе с путями файловой системы. В отличие от устаревшего os.path, он предлагает объектно-ориентированный, интуитивный и платформонезависимый подход. Эта статья подробно разберет все аспекты pathlib с практическими примерами.
1. Зачем нужен pathlib?
Традиционные методы (os.path.join(), os.listdir() и др.) страдают от:
- Платформозависимости (разделители / vs \).
- Разрозненности функций.
- Неудобства при операциях с компонентами путей.
Преимущества pathlib:
- Единый объект пути вместо строк.
- Четкая иерархия классов.
- Методы, объединяющие функциональность os, os.path и glob.
- Поддержка контекстных менеджеров.
- Автоматическая нормализация путей.
2. Классовая иерархия
from pathlib import Path, PurePath, PureWindowsPath, PurePosixPath
- PurePath: Абстрактный класс без операций ввода-вывода.
- PurePosixPath: Для UNIX-путей.
- PureWindowsPath: Для Windows-путей.
- Path: Наследует PurePath, добавляет системные операции.
- PosixPath: Для UNIX (доступен в Linux/macOS).
- WindowsPath: Для Windows.
Правило: Всегда используйте Path (автовыбор подсистемы).
3. Создание путей
# Текущая директория
p = Path()
# Абсолютный путь
p = Path("/home/user/docs")
# Комбинирование
config = Path("/etc") / "nginx" / "nginx.conf" # Автоматическое добавление разделителей
# Из строки
p = Path("data/2025/report.csv")
4. Разбор компонентов пути
Любой Path предоставляет атрибуты для декомпозиции:
p = Path("/project/src/utils.py")
print(p.name) # "utils.py"
print(p.stem) # "utils"
print(p.suffix) # ".py"
print(p.parent) # Path("/project/src")
print(p.parts) # ('/', 'project', 'src', 'utils.py')
print(p.anchor) # "/" (корень)
5. Проверка свойств
p = Path("data.txt")
p.exists() # Существует ли?
p.is_file() # Это файл?
p.is_dir() # Это директория?
p.is_symlink()# Это символьная ссылка?
p.stat() # Метаданные (размер, время изменения)
6. Работа с файлами
Чтение/запись:
# Прочитать всё содержимое
data = p.read_text(encoding="utf-8")
# Записать
p.write_text("Hello, Pathlib!", encoding="utf-8")
# Контекстный менеджер
with p.open(mode="r") as f:
....print(f.readlines())
Управление файлами:
p.rename("new_data.txt") # Переименовать
p.replace("/backup/data.txt") # Переместить с заменой
p.unlink() # Удалить файл
p.touch() # Создать пустой файл
7. Работа с директориями**
Создание:
p = Path("project/logs/2025")
p.mkdir(parents=True, exist_ok=True) # Рекурсивное создание
Итерация по содержимому:
# Все элементы в директории
for child in Path("src").iterdir():
....print(child.name)
# Рекурсивный поиск файлов
py_files = list(Path(".").glob("**/*.py")) # Аналог: rglob("*.py")
Удаление:
# Только пустые директории
p.rmdir()
# Рекурсивное удаление (с файлами) - требует осторожности!
import shutil
shutil.rmtree(p)
8. Полезные методы
Абсолютные и относительные пути:
p = Path("docs/README.md")
p.resolve() # Абсолютный путь (с разрешением симлинков)
p.absolute() # Абсолютный путь без разрешения симлинков
p.relative_to("/home") # Относительный путь от заданной директории
Модификация путей:
p = Path("data.csv")
p.with_name("new.csv") # Заменить имя файла
p.with_stem("archive") # Заменить имя без расширения (Python 3.9+)
p.with_suffix(".zip") # Заменить расширение
Нормализация:
Path("a/../b/./c").resolve() # Автоматически преобразует в "b/c"
9. Реальные примеры
Пример 1: Поиск дубликатов по размеру
from collections import defaultdict
duplicates = defaultdict(list)
for path in Path("Photos").rglob("*"):
....if path.is_file():
........duplicates[path.stat().st_size].append(path)
for size, paths in duplicates.items():
....if len(paths) > 1:
........print(f"Size {size} bytes: {', '.join(str(p) for p in paths)}")
Пример 2: Пакетная смена расширений
for txt_file in Path("reports").glob("*.txt"):
new_path = txt_file.with_suffix(".md")
txt_file.replace(new_path)
Пример 3: Резервное копирование
backup_dir = Path("backup") / datetime.now().strftime("%Y%m%d")
backup_dir.mkdir(exist_ok=True)
for src in Path("data").iterdir():
....if src.is_file():
........dest = backup_dir / src.name
........dest.write_bytes(src.read_bytes()) # Копирование бинарного содержимого
10. Заключение
Почему pathlib?
- Устраняет платформозависимость.
- Делает код чище и читабельнее.
- Интегрирует разрозненные функции из os, glob и shutil.
- Поддерживается всеми современными библиотеками (pandas, pytest, Django).
Когда использовать os вместо pathlib?
- Работа с файловыми дескрипторами (os.open()).
- Низкоуровневые системные вызовы.
Рекомендация: Для нового кода всегда выбирайте pathlib. Это не только удобнее, но и безопаснее!
# Философия pathlib в одном примере
(Path.home() / "projects" / "README.md").read_text()
Официальная документация: Python pathlib
Хорошего кодирования! 🐍
Подписывайтесь:
Телеграм https://t.me/lets_go_code
Канал "Просто о программировании" https://dzen.ru/lets_go_code