Python · Синтаксис · Проміжний
pathlib
Навчіться працювати з файловими шляхами за допомогою сучасного модуля pathlib у Python — чистіший і потужніший за os.path.
Короткий вступ до теми та пояснення перед вправами (вправи нижче):
Читання, запис та пошук файлів
#Довідник: pathlib
#Вправи:
Атрибути Path
#Маючи рядок шляху `"/home/user/projects/data/report_2024.csv"`, створіть об'єкт `Path` з нього і виведіть: - Повне ім'я файлу (`name`) - Ім'я без розширення (`stem`) - Розширення (`suffix`) - Батьківську директорію (`parent`) - Всі компоненти шляху (`parts`)
from pathlib import Path
p = Path("/home/user/projects/data/report_2024.csv")
# Виведіть: name, stem, suffix, parent, parts
print(p.name) # ???
print(p.stem) # ???
print(p.suffix) # ???
print(p.parent) # ???
print(p.parts) # ???
Рішення
from pathlib import Path
p = Path("/home/user/projects/data/report_2024.csv")
print(p.name) # report_2024.csv
print(p.stem) # report_2024
print(p.suffix) # .csv
print(p.parent) # /home/user/projects/data
print(p.parts) # ("/", "home", "user", "projects", "data", "report_2024.csv")
Побудова шляху через /
#Напишіть функцію `build_path(base, *parts)`, яка приймає базову директорію як рядок і будь-яку кількість частин шляху, з'єднує їх через оператор `/` і повертає фінальний об'єкт `Path`. Приклад: `build_path("/home/user", "projects", "myapp", "config.json")` → `Path("/home/user/projects/myapp/config.json")`.
from pathlib import Path
def build_path(base, *parts):
pass
result = build_path("/home/user", "projects", "myapp", "config.json")
print(result) # /home/user/projects/myapp/config.json
Рішення
from pathlib import Path
def build_path(base, *parts):
p = Path(base)
for part in parts:
p = p / part
return p
# Коротше: Path(base).joinpath(*parts)
result = build_path("/home/user", "projects", "myapp", "config.json")
print(result) # /home/user/projects/myapp/config.json
Змінити розширення
#Напишіть функцію `change_extension(path_str, new_ext)`, яка приймає рядок шляху і нове розширення (з крапкою, наприклад `".txt"`), і повертає новий `Path` зі зміненим розширенням. Приклад: `change_extension("/home/user/data.csv", ".json")` → `Path("/home/user/data.json")`. Використовуйте `p.with_suffix()`.
from pathlib import Path
def change_extension(path_str, new_ext):
pass
print(change_extension("/home/user/data.csv", ".json"))
# /home/user/data.json
print(change_extension("/docs/report.txt", ".md"))
# /docs/report.md
Рішення
from pathlib import Path
def change_extension(path_str, new_ext):
return Path(path_str).with_suffix(new_ext)
print(change_extension("/home/user/data.csv", ".json"))
# /home/user/data.json
print(change_extension("/docs/report.txt", ".md"))
# /docs/report.md
Безпечне читання файлу
#Напишіть функцію `safe_read(path_str, encoding="utf-8")`, яка читає вміст файлу за `path_str` і повертає його як рядок. Якщо файл не існує — повертає `None`. При будь-якій іншій помилці — теж `None`. Використовуйте `Path.read_text()`.
from pathlib import Path
def safe_read(path_str, encoding="utf-8"):
pass
Path("/tmp/test_pathlib.txt").write_text("hello", encoding="utf-8")
print(safe_read("/tmp/test_pathlib.txt")) # hello
print(safe_read("/tmp/missing.txt")) # None
Рішення
from pathlib import Path
def safe_read(path_str, encoding="utf-8"):
try:
return Path(path_str).read_text(encoding=encoding)
except Exception:
return None
Path("/tmp/test_pathlib.txt").write_text("hello", encoding="utf-8")
print(safe_read("/tmp/test_pathlib.txt")) # hello
print(safe_read("/tmp/missing.txt")) # None
Записати і перевірити
#Напишіть функцію `write_and_verify(path_str, content)`, яка: 1. Записує `content` у файл за `path_str` через `Path.write_text()` 2. Читає назад через `Path.read_text()` 3. Повертає `True` якщо вміст збігається, `False` інакше Використовуйте `encoding="utf-8"` для обох операцій.
from pathlib import Path
def write_and_verify(path_str, content):
pass
print(write_and_verify("/tmp/verify_test.txt", "Hello pathlib!"))
# True
Рішення
from pathlib import Path
def write_and_verify(path_str, content):
p = Path(path_str)
p.write_text(content, encoding="utf-8")
return p.read_text(encoding="utf-8") == content
print(write_and_verify("/tmp/verify_test.txt", "Hello pathlib!"))
# True
Підрахунок файлів за розширенням
#Напишіть функцію `count_by_extension(dir_path)`, яка приймає рядок шляху до директорії і повертає словник, де кожне розширення файлу відповідає кількості файлів з цим розширенням у директорії (без рекурсії). Приклад: якщо директорія містить `a.py`, `b.py`, `c.txt`, `d.txt`, `e.md`, результат: `{".py": 2, ".txt": 2, ".md": 1}`.
from pathlib import Path
def count_by_extension(dir_path):
pass
# Приклад: якщо в директорії a.py, b.py, c.txt, d.txt, e.md
# результат: {".py": 2, ".txt": 2, ".md": 1}
Рішення
from pathlib import Path
def count_by_extension(dir_path):
counts = {}
for p in Path(dir_path).iterdir():
if p.is_file():
ext = p.suffix
counts[ext] = counts.get(ext, 0) + 1
return counts
import tempfile
with tempfile.TemporaryDirectory() as d:
for name in ["a.py", "b.py", "c.txt", "d.txt", "e.md"]:
Path(d, name).write_text("", encoding="utf-8")
print(count_by_extension(d))
# {".py": 2, ".txt": 2, ".md": 1}
Знайти великі файли
#Напишіть функцію `find_large_files(dir_path, min_size_bytes)`, яка рекурсивно шукає у директорії всі файли більші за `min_size_bytes` і повертає їх шляхи як відсортований список об'єктів `Path`. Використовуйте `p.rglob("*")` і `p.stat().st_size`.
from pathlib import Path
def find_large_files(dir_path, min_size_bytes):
pass
# Повертає відсортований список Path-об'єктів для файлів > min_size_bytes
Рішення
from pathlib import Path
def find_large_files(dir_path, min_size_bytes):
return sorted(
p for p in Path(dir_path).rglob("*")
if p.is_file() and p.stat().st_size > min_size_bytes
)
for f in find_large_files(".", 1000):
print(f)
Гарантувати директорію
#Напишіть функцію `ensure_dir(path_str)`, яка створює директорію за `path_str` якщо вона не існує. Вона має: - Створювати всі проміжні батьківські директорії за потреби - Не кидати помилку якщо директорія вже існує - Повертати об'єкт `Path` директорії Використовуйте `Path.mkdir(parents=True, exist_ok=True)`.
from pathlib import Path
def ensure_dir(path_str):
pass
p = ensure_dir("/tmp/myapp/logs/2024")
print(p.is_dir()) # True
print(p) # /tmp/myapp/logs/2024
Рішення
from pathlib import Path
def ensure_dir(path_str):
p = Path(path_str)
p.mkdir(parents=True, exist_ok=True)
return p
p = ensure_dir("/tmp/myapp/logs/2024")
print(p.is_dir()) # True
print(p) # /tmp/myapp/logs/2024
Резервна копія файлу
#Напишіть функцію `backup(path_str)`, яка створює резервну копію файлу додаючи `.bak` до його імені. Якщо файл не існує — кидає `FileNotFoundError`. Повертає `Path` резервного файлу. Приклад: `backup("/home/user/data.txt")` створює `/home/user/data.txt.bak` і повертає цей шлях.
from pathlib import Path
import shutil
def backup(path_str):
pass
Path("/tmp/data_original.txt").write_text("important", encoding="utf-8")
bak = backup("/tmp/data_original.txt")
print(bak) # /tmp/data_original.txt.bak
Рішення
from pathlib import Path
import shutil
def backup(path_str):
p = Path(path_str)
if not p.exists():
raise FileNotFoundError(f"File not found: {p}")
bak = p.with_suffix(p.suffix + ".bak")
shutil.copy2(str(p), str(bak))
return bak
Path("/tmp/data_original.txt").write_text("important", encoding="utf-8")
bak = backup("/tmp/data_original.txt")
print(bak) # /tmp/data_original.txt.bak
print(bak.read_text(encoding="utf-8")) # important
Знайти Python-файли
#Напишіть функцію `find_python_files(start_dir)`, яка рекурсивно знаходить всі файли `.py` у `start_dir`, сортує їх за іменем і повертає список їх відносних шляхів (відносно `start_dir`) як рядки. Використовуйте `Path.rglob("*.py")` і `p.relative_to(start_dir)`.
from pathlib import Path
def find_python_files(start_dir):
pass
# Повертає список відносних рядків шляху відсортованих за іменем
for f in find_python_files("."):
print(f)
Рішення
from pathlib import Path
def find_python_files(start_dir):
base = Path(start_dir)
return sorted(
str(p.relative_to(base))
for p in base.rglob("*.py")
)
for f in find_python_files("."):
print(f)