Работа с путями в Python: pathlib с нуля до рабочего кода
Как перестать склеивать пути строками и перейти на pathlib. Разберём чтение, запись, обход папок и типичные ошибки на Python 3.10+.

За 20–30 минут вы научитесь строить пути, проверять существование файлов, читать и записывать содержимое, обходить каталоги и не ломаться на разнице между Windows и Linux. Всё через модуль pathlib из стандартной библиотеки — ничего доустанавливать не нужно. Примеры проверены на Python 3.10 и работают вплоть до 3.13.
Что нужно до начала
Проверьте версию интерпретатора — pathlib есть с Python 3.4, но пара удобных методов появилась позже, я отмечу это по ходу.
python --version
# Должно вывести Python 3.10.x или новее
Отдельно устанавливать ничего не нужно: pathlib входит в стандартную библиотеку. Достаточно строки from pathlib import Path в начале файла.
Почему не str и os.path.join
Строковый путь вида "data" + "/" + "file.txt" ломается на Windows, где разделитель — обратный слэш. os.path.join эту проблему решает, но возвращает обычную строку, к которой приходится каждый раз применять отдельные функции: os.path.exists, os.path.basename, os.path.splitext. pathlib собирает это в один объект с методами.
Путь — это не строка, а объект со своим поведением. Как только вы перестаёте думать о нём как о наборе символов, половина ошибок с разделителями и расширениями исчезает сама.
Шаг 1. Создать путь
Оператор / у объекта Path перегружен и склеивает части пути правильным разделителем для текущей ОС.
from pathlib import Path
# Путь к папке рядом со скриптом
base_dir = Path("data")
# Склеиваем через /, а не через строки
file_path = base_dir / "reports" / "june.csv"
print(file_path)
# На Linux: data/reports/june.csv
# На Windows: data\reports\june.csv
Проверка: print выводит путь с разделителем вашей ОС — значит объект собран верно.
Путь к самому скрипту
Частая задача — открыть файл, лежащий рядом с .py-файлом, независимо от того, откуда запущен скрипт.
from pathlib import Path
# Папка, в которой лежит текущий файл
script_dir = Path(__file__).resolve().parent
config_path = script_dir / "config.json"
print(config_path)
resolve() превращает относительный путь в абсолютный и убирает .. и символические ссылки. parent отрезает имя файла и даёт папку.
Шаг 2. Проверить, что файл существует
from pathlib import Path
file_path = Path("data/reports/june.csv")
if file_path.exists():
print("Файл на месте")
else:
print("Файла нет")
# Отдельно проверить, что это именно файл, а не папка
print(file_path.is_file())
print(file_path.is_dir())
Проверка: если файла нет, exists() вернёт False и программа не упадёт — падение будет только при попытке открыть несуществующий файл на чтение.
Шаг 3. Прочитать и записать содержимое
Для небольших текстовых файлов pathlib даёт методы, которые сами открывают и закрывают файл — open и with писать не нужно.
from pathlib import Path
notes = Path("data/notes.txt")
# Запись текста (файл будет создан или перезаписан)
notes.write_text("Первая строка\nВторая строка\n", encoding="utf-8")
# Чтение всего текста целиком
content = notes.read_text(encoding="utf-8")
print(content)
Всегда указывайте encoding="utf-8" явно. Без него Python на Windows использует системную кодировку, и файл с кириллицей читается кракозябрами.
Для больших файлов read_text не подходит — он грузит всё в память. Тогда открывайте построчно:
from pathlib import Path
log = Path("data/app.log")
# open у Path работает как встроенный open
with log.open(encoding="utf-8") as f:
for line in f:
if "ERROR" in line:
print(line.rstrip())
Проверка: после write_text файл появится в папке data, а read_text вернёт ровно то, что вы записали.
Шаг 4. Создать папки
Записать файл в несуществующую папку нельзя — сначала папку нужно создать.
from pathlib import Path
target_dir = Path("data/2024/reports")
# parents=True создаёт все промежуточные папки
# exist_ok=True не падает, если папка уже есть
target_dir.mkdir(parents=True, exist_ok=True)
Без parents=True метод упадёт с FileNotFoundError, если промежуточной папки 2024 ещё нет. Без exist_ok=True — упадёт с FileExistsError при повторном запуске.
Шаг 5. Обойти файлы в папке
Для перебора файлов есть два метода: iterdir — только содержимое одной папки, glob — по шаблону, в том числе рекурсивно.
from pathlib import Path
data_dir = Path("data")
# Все элементы прямо в папке (файлы и подпапки)
for item in data_dir.iterdir():
print(item)
# Только csv-файлы в этой папке
for csv_file in data_dir.glob("*.csv"):
print(csv_file.name)
# Все csv-файлы во всех вложенных папках
for csv_file in data_dir.glob("**/*.csv"):
print(csv_file)
Шаблон ** означает «любая глубина вложенности». Проверка: glob("*.csv") вернёт только файлы с расширением .csv в самой папке, вложенные — пропустит.
Шаг 6. Разобрать путь на части
У объекта Path есть готовые свойства вместо ручного разбора строки.
from pathlib import Path
p = Path("data/reports/june.csv")
print(p.name) # june.csv — имя с расширением
print(p.stem) # june — имя без расширения
print(p.suffix) # .csv — расширение с точкой
print(p.parent) # data/reports — родительская папка
Чтобы сменить расширение, не режьте строку — используйте with_suffix:
from pathlib import Path
p = Path("data/reports/june.csv")
json_path = p.with_suffix(".json")
print(json_path) # data/reports/june.json
Таблица: что где взять
| Задача | Метод или свойство | Результат для data/reports/june.csv |
|---|---|---|
| Имя файла | .name | june.csv |
| Имя без расширения | .stem | june |
| Расширение | .suffix | .csv |
| Родительская папка | .parent | data/reports |
| Абсолютный путь | .resolve() | /полный/путь/data/reports/june.csv |
| Сменить расширение | .with_suffix(".json") | data/reports/june.json |
Если не получилось
- FileNotFoundError: [Errno 2] No such file or directory — вы читаете или открываете файл, которого нет по этому пути. Проверьте
file_path.exists()перед открытием и выведитеfile_path.resolve(), чтобы увидеть, куда вы на самом деле смотрите. - FileNotFoundError при mkdir — нет промежуточной папки. Добавьте
parents=True. - FileExistsError при mkdir — папка уже создана. Добавьте
exist_ok=True. - UnicodeDecodeError при read_text — файл в другой кодировке или вы читаете бинарный файл как текст. Укажите
encoding="utf-8", а для картинок и архивов используйтеread_bytes(). - PermissionError — нет прав на запись в папку или файл открыт другой программой. Проверьте права на каталог и закройте файл в редакторе.
Что дальше
Когда базовые операции освоены, посмотрите на shutil из стандартной библиотеки — он копирует и перемещает файлы целиком (shutil.copy, shutil.move), чего в pathlib нет. Для временных файлов и папок есть модуль tempfile. А чтобы удалить файл или пустую папку, используйте Path.unlink() и Path.rmdir() — но рекурсивное удаление дерева делает именно shutil.rmtree(), будьте с ним осторожны на проде.
Проектная работа: От проблемы до защиты: продукт, этапы, вопросы комиссии
Спросить за 15 ₽Источники: pathlib — Object-oriented filesystem paths, документация Python
Частые вопросы
У меня Python 3.8 — примеры сработают?
Чем pathlib лучше os.path, если и то и другое работает?
Как передать путь из pathlib в функцию, которая ждёт строку?
Почему кириллица в файле читается кракозябрами?
glob не находит файлы во вложенных папках — что не так?
Как безопасно удалить файл, чтобы скрипт не упал, если его уже нет?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.