Вспомните прошлую тему: вы открывали файл через open(), читали его построчно и следили за кодировкой. Но файл всегда лежал рядом со скриптом. В жизни файлы разбросаны: «Загрузки» забиты отчётами, фото и архивами вперемешку. Сегодня научим Python ходить по папкам и раскладывать файлы по местам.
🎯 После урока сможете: собрать путь к файлу на любой системе, разобрать его на части, найти нужные файлы в папке, создать папки и разложить файлы по ним скриптом.
Путь — это объект, а не строка
Модуль pathlib даёт класс Path. Путь собирается оператором /, и Python сам поставит нужный разделитель: \ на Windows, / на macOS и Linux. Склеивать пути строками через + не нужно.
from pathlib import Path
home = Path.home() # домашняя папка пользователя
downloads = home / "Downloads"
report = downloads / "отчёт.pdf"
print(report)
# Windows: C:\Users\anna\Downloads\отчёт.pdf
# macOS: /Users/anna/Downloads/отчёт.pdf
Почему в коде "Downloads", а не «Загрузки»? Это одна и та же папка. На диске она называется Downloads, а Windows и macOS только показывают её по-русски. В пути пишите настоящее имя — Downloads. «Загрузки» в примерах ниже — учебная папка рядом со скриптом.
Path.cwd() вернёт текущую рабочую папку — ту, из которой запущен скрипт. Относительный путь вроде Path("data/расходы.csv") отсчитывается как раз от неё.
Проверьте себя
Контрольный вопрос. Нужно получить путь к файлу «фото.jpg» в папке «Загрузки». Какая строка работает на любой системе?
Подсказка: Путь собирают оператором /, разделитель Python подставит сам.
Онлайн-проверка ответа появится позже
Части пути: parent, name, stem, suffix
У пути есть готовые свойства. Не нужно резать строку по точкам и слэшам.

from pathlib import Path
p = Path("Загрузки/2024/отчёт.final.pdf")
print(p.parent) # Загрузки/2024 (на Windows со знаком \)
print(p.parent.name) # 2024
print(p.name) # отчёт.final.pdf
print(p.stem) # отчёт.final
print(p.suffix) # .pdf
print(p.with_suffix(".txt").name) # отчёт.final.txt
print(p.parts) # ('Загрузки', '2024', 'отчёт.final.pdf')
Расширение в
suffixвсегда с точкой:".pdf", а не"pdf". И регистр сохраняется: уФОТО.JPGсуффикс.JPG. Поэтому для сравнения беритеp.suffix.lower().
Проверьте себя
Контрольный вопрос. Что выведет код? Введите результат ровно как на экране.
Исходный код для этого задания:
from pathlib import Path p = Path("Загрузки/Отпуск/море.JPG") print(p.suffix)Подсказка: Перечитайте врезку про suffix: что он делает с точкой и меняет ли регистр букв.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Что выведет код? Введите результат.
Исходный код для этого задания:
from pathlib import Path p = Path("Документы/договор.v2.docx") print(p.stem)Подсказка: Если точек в имени несколько, какое расширение отрезает stem? Сравните с примером отчёт.final.pdf в уроке.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Что выведет код? Введите одно слово.
Исходный код для этого задания:
from pathlib import Path p = Path("Загрузки/2024/Март/счёт.pdf") print(p.parent.name)Подсказка: parent — папка файла, name у неё — последнее имя в пути.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Что выведет код? Введите имя файла.
Исходный код для этого задания:
from pathlib import Path p = Path("Фото/IMG_1.heic") print(p.with_suffix(".jpg").name)Подсказка: with_suffix меняет расширение, name даёт имя целиком.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Что выведет код? Введите число.
Исходный код для этого задания:
from pathlib import Path print(len(Path("Загрузки/2024/отчёт.docx").parts))Подсказка: parts — кортеж из всех частей пути.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Программа должна считать PDF-файлы, но выводит меньше, чем нужно. Что она выведет сейчас? Введите число.
Исходный код для этого задания:
from pathlib import Path names = ["a.PDF", "b.jpg", "c.pdf", "d.Pdf", "e.png"] count = 0 for n in names: if Path(n).suffix == ".pdf": count += 1 print(count)Подсказка: Сравнение учитывает регистр букв. Для «правильной» версии нужен suffix.lower().
Онлайн-проверка ответа появится позже
Проверить, что лежит по пути
p = Path("Загрузки/отчёт.pdf")
print(p.exists()) # True, если файл или папка есть
print(p.is_file()) # True, только если это файл
print(p.is_dir()) # True, только если это папка
Пока мы не прошли исключения (тема 2.1), правило простое: прежде чем открыть, переместить или удалить — проверьте exists().
Проверьте себя
Контрольный вопрос. Отметьте все методы, которые есть у объекта
Pathи возвращают True/False.Выберите все верные варианты.
Подсказка: Это проверки существования и типа. mkdir создаёт папку, а iterdir перебирает содержимое.
Онлайн-проверка ответа появится позже
Обойти папку: iterdir и glob
folder = Path.home() / "Downloads"
for item in folder.iterdir(): # всё содержимое, без вложенных папок
if item.is_file():
print(item.name, item.stat().st_size, "байт")
for pdf in folder.glob("*.pdf"): # только файлы по шаблону
print(pdf.name)
for py in folder.rglob("*.py"): # то же, но во всех вложенных папках
print(py)
В шаблоне * означает «любые символы». "*.pdf" — все файлы с расширением .pdf, "отчёт*" — всё, что начинается со слова «отчёт». item.stat().st_size — размер файла в байтах.
Проверьте себя
Контрольный вопрос. Нужно найти в папке все картинки с расширением .png. Какой шаблон подставить в
folder.glob("___")? Выберите вариант.Подсказка: Звёздочка заменяет любые символы имени. Без неё шаблон ищет файл ровно с таким именем.
Онлайн-проверка ответа появится позже
Создать папку и переименовать файл
target = Path("Загрузки/Картинки")
target.mkdir(parents=True, exist_ok=True)
old = Path("Загрузки/IMG_0012.jpg")
if old.exists():
old.rename(target / "море.jpg") # переименовать и заодно переместить
parents=True— создать и промежуточные папки, если их нет;exist_ok=True— не падать с ошибкой, если папка уже есть. Без него второй запуск скрипта сломается.
Проверьте себя
Контрольный вопрос. Скрипт сортировки запустили второй раз, и строка создания папки упала с ошибкой: папка уже существует. Какой параметр надо добавить в mkdir, чтобы повторный запуск не падал? Введите только имя параметра, без знака = и значения.
Исходный код для этого задания:
target = Path("Загрузки") / "Картинки" target.mkdir(parents=True)Подсказка: Параметр разрешает папке уже существовать.
Онлайн-проверка ответа появится позже
shutil: копировать, перемещать, удалять папки
pathlib умеет работать с отдельным путём, а для «тяжёлых» операций есть модуль shutil. Он принимает и объекты Path, и строки.
import shutil
shutil.copy("отчёт.pdf", "Архив/") # копия: исходник остаётся на месте
shutil.move("отчёт.pdf", "Документы/") # перенос: исходника больше нет
shutil.copytree("Проект", "Проект_копия") # скопировать папку целиком
shutil.rmtree("Временное") # удалить папку со всем содержимым
shutil.rmtreeудаляет безвозвратно, мимо корзины. Перед запуском выведите список того, что собираетесь удалить, через
Проверьте себя
Контрольный вопрос. Вы вызвали
shutil.copy("отчёт.pdf", "Архив/"). Что стало с исходным файлом?Подсказка: copy — копирует, move — переносит.
Онлайн-проверка ответа появится позже
А что с модулем os?
os — старший брат pathlib. В старом коде вы встретите os.path.join, os.listdir, os.makedirs. Всё это умеет и Path, поэтому в новом коде берите его. Но у os есть то, чего нет в pathlib, например переменные окружения (os.environ). Это настройки, которые система передаёт каждой запущенной программе: имя пользователя, путь к домашней папке и другие.
import os
print(os.listdir(".")) # имена файлов в текущей папке (строки)
print(os.path.join("data", "a.csv")) # data\a.csv или data/a.csv
print(os.environ.get("USERNAME") or os.environ.get("USER")) # имя пользователя
Собираем: сортировщик «Загрузок»
Главный приём урока: словарь «расширение → папка», цикл по файлам, перенос. Вот как выглядят «Загрузки» до и после.


from pathlib import Path
import shutil
RULES = {
".pdf": "Документы", ".docx": "Документы",
".jpg": "Картинки", ".png": "Картинки",
".zip": "Архивы",
}
downloads = Path.home() / "Downloads"
for item in downloads.iterdir():
if not item.is_file():
continue
folder_name = RULES.get(item.suffix.lower())
if folder_name is None:
continue # правила нет — не трогаем
target = downloads / folder_name
target.mkdir(exist_ok=True)
shutil.move(item, target / item.name)
print(item.name, "->", folder_name)
Осторожно с одинаковыми именами. Если в папке назначения уже лежит файл с тем же именем,
shutil.move(item, target / item.name)молча заменит его новым, и старый файл пропадёт — и на Windows, и на macOS и Linux. Если передать только папку,shutil.move(item, target), при совпадении имени будет ошибкаshutil.Error. Чтобы ничего не потерять, перед переносом проверьтеif (target / item.name).exists():и в этом случае пропустите файл или подберите ему свободное имя, напримеротчёт_1.pdf.
Прежде чем гонять скрипт по настоящим «Загрузкам», создайте тестовую папку с несколькими пустыми файлами и поставьте
downloads = Path("тест_загрузки"). Заменитеshutil.moveна
Проверьте себя
Контрольный вопрос. Скрипт подбирает свободное имя, чтобы при переносе не затереть файл с тем же именем. Что он выведет? Введите имя файла.
Исходный код для этого задания:
from pathlib import Path busy = {"отчёт.pdf", "отчёт_1.pdf"} name = "отчёт.pdf" new = Path(name) i = 1 while new.name in busy: new = Path(f"{Path(name).stem}_{i}{Path(name).suffix}") i += 1 print(new.name)Подсказка: Проверьте по шагам: какие имена уже заняты в busy.
Онлайн-проверка ответа появится позже
Задание. Миссия: сортировщик «Загрузок». Напишите функцию
sort_downloads(folder), которая раскладывает файлы папки по вложенным папкам по правилам ниже (расширение сравнивать без учёта регистра, файлы без правила не трогать, повторный запуск не должен падать). Создайте тестовую папку с пустыми файлами из списка (их удобно создать циклом черезtouch()) и запустите функцию.
В поле ответа введите число файлов, которые попали в папку «Картинки». Приложите файл программы .py; в поле ответа — число.Принято, если:
1. введённое число совпадает с эталоном;
2. приложен файл .py, который это число выдаёт на данных из условия;Самопроверка перед сдачей (преподаватель смотрит на занятии):
3. расширение приводится к нижнему регистру (suffix.lower());
4. файлы без правила остаются на месте;
5. повторный запуск не падает с ошибкой.Правила: .pdf, .docx → Документы; .jpg, .jpeg, .png → Картинки; .zip, .rar → Архивы.
Файлы в тестовой папке (45 шт.):
setup_257.rar
setup_815.mp3
backup_200.jpeg
IMG_0086.txt
мем_457.jpeg
backup_812.PNG
договор_873.jpg
IMG_0289.jpeg
IMG_0636.Jpeg
договор_701.docx
фильм_836.webp
file191.rar
фильм_613.PNG
file781.zip
backup_682.docx
file58.zip
счёт_868.mp3
скрин_38.mp3
file593.heic
setup_899.jpeg
договор_833.mp3
IMG_0084.rar
IMG_0335.docx
фильм_552.Jpeg
договор_523.png
IMG_0260.jpg
setup_853.txt
скрин_393.jpeg
backup_249.jpg
фильм_549.pdf
фильм_871.zip
IMG_0514.jpeg
мем_718.Jpeg
договор_197.txt
мем_995.png
мем_335.Jpeg
мем_426.pdf
мем_958.jpeg
фильм_414.jpeg
фильм_403.webp
IMG_0765.png
мем_801.webp
setup_935.heic
договор_640.JPG
скрин_739.mp3
Подсказка: Создайте файлы циклом: for n in names: (folder / n).touch(). После запуска сортировщика посчитайте файлы в «Картинках» через len(list((folder / «Картинки»).iterdir())).
✅ Готово, если: ответ раскрывает то, что просит критерий приёмки в задании выше.
Онлайн-проверка ответа появится позже
Задание. Миссия: найти пожирателей места. Напишите скрипт, который обходит папку через
rglob("*"), берёт у каждого файла размерstat().st_sizeи переносит в папку «Большие» все файлы крупнее 100 МБ (1 МБ = 1024 × 1024 байт). В конце скрипт печатает, сколько файлов перенесено и сколько ГБ они занимают (1 ГБ = 1024³ байт, округление до 2 знаков через round).
Гигабайтные файлы создавать не нужно: вынесите отбор в функциюpick_big(sizes), которая получает словарь «имя → размер», и прогоните её на списке из условия.
В поле ответа введите число ГБ для файлов из условия. Приложите файл программы .py; в поле ответа — число.Принято, если:
1. введённое число совпадает с эталоном;
2. приложен файл .py, который это число выдаёт на данных из условия;Самопроверка перед сдачей (преподаватель смотрит на занятии):
3. порог считается как 100 * 1024 * 1024 байт, сравнение строго «больше»;
4. папка «Большие» создаётся, если её нет, и сама не попадает в обход;
5. скрипт печатает число файлов и сумму в ГБ.Размеры файлов в байтах (40 шт.):
фото_77.jpg — 3158845773
архив_25.zip — 4285937585
презентация_62.pptx — 1009830
бэкап_62.7z — 99438924
дистрибутив_63.iso — 4304749768
дистрибутив_81.iso — 6920775
отчёт_40.pdf — 118896122
фото_76.jpg — 83970998
фото_36.jpg — 376750808
архив_54.zip — 3076579111
бэкап_9.7z — 1729934819
дистрибутив_86.iso — 1202003
дистрибутив_18.iso — 3857395233
бэкап_24.7z — 6156230
архив_83.zip — 8503947
архив_28.zip — 92480707
видео_92.mp4 — 1493338062
архив_20.zip — 376082
видео_59.mp4 — 146360748
презентация_74.pptx — 3685008875
презентация_40.pptx — 4080053292
дистрибутив_1.iso — 152183825
дистрибутив_2.iso — 2353867370
бэкап_8.7z — 155750652
отчёт_22.pdf — 1872532
фото_78.jpg — 1582142777
отчёт_25.pdf — 95385253
отчёт_97.pdf — 84184415
презентация_86.pptx — 1354682
отчёт_62.pdf — 152080564
фото_29.jpg — 2283434922
музыка_35.flac — 94476031
отчёт_28.pdf — 2183692
архив_77.zip — 3153198335
видео_74.mp4 — 2226346777
музыка_4.flac — 1522250
бэкап_98.7z — 140925917
архив_98.zip — 151747848
презентация_25.pptx — 94488778
архив_26.zip — 130638919
Подсказка: Сложите размеры всех файлов, у которых size > 100 * 1024 * 1024, разделите сумму на 1024 ** 3 и округлите через round(…, 2).
✅ Готово, если: ответ раскрывает то, что просит критерий приёмки в задании выше.
Онлайн-проверка ответа появится позже
Что дальше
Теперь вы умеете собирать пути через Path, разбирать их на части, искать файлы по шаблону, создавать папки и переносить файлы через shutil. В следующей теме откроем то, что лежит в папках: таблицу расходов в CSV и файл настроек в JSON.
← Назад · ↑ В начало урока · ⌂ К навигатору курса · Вперёд →
