📜 Как показано в исходном материале
Исходная лекция использует модуль os и строковые пути. Перед действием обычно делается проверка через os.path.exists:
import os
file_path = "example.txt"
if os.path.exists(file_path):
if os.path.isfile(file_path):
print(f"'{file_path}' — файл.")
else:
print(f"'{file_path}' существует, но это не файл.")
else:
print(f"'{file_path}' не существует.")
Сборка пути выполняется через os.path.join:
full_path = os.path.join(os.getcwd(), "docs", "data.txt")
Этот подход называется LBYL — Look Before You Leap (смотри, прежде чем прыгать).
❌ Что можно улучшить
- Множество проверок
os.path.existsзагромождают код и создают состояние гонки: объект может исчезнуть между проверкой и действием. - Строковые пути не несут информации о файловой системе; легко ошибиться с разделителем.
- Функции
os.pathразбросаны по модулю и часто требуют повторного указания пути.
✅ Рекомендуемый современный вариант
Модуль pathlib появился в Python 3.4 и предоставляет класс Path. Он объединяет большинство операций с путями в одном объекте:
from pathlib import Path
file_path = Path("example.txt")
if file_path.is_file():
print(f"'{file_path}' — файл.")
elif file_path.is_dir():
print(f"'{file_path}' — папка.")
else:
print(f"'{file_path}' не существует.")
Сборка пути выглядит естественно:
from pathlib import Path
base = Path.cwd()
full_path = base / "docs" / "data.txt"
Сравнение решений
| Задача | os.path | pathlib |
|---|---|---|
| Текущая директория | os.getcwd() |
Path.cwd() |
| Сборка пути | os.path.join(a, b, c) |
a / b / c |
| Абсолютный путь | os.path.abspath(p) |
p.resolve() |
| Имя файла | os.path.basename(p) |
p.name |
| Родительская директория | os.path.dirname(p) |
p.parent |
| Проверка существования | os.path.exists(p) |
p.exists() |
| Рекурсивный поиск | os.walk(p) |
p.rglob("*.txt") |
EAFP вместо LBYL
В Python часто предпочитают стиль EAFP — Easier to Ask for Forgiveness than Permission. Вместо предварительной проверки делаем действие и ловим ожидаемое исключение:
import os
# LBYL: сначала проверяем
if os.path.exists("data.txt"):
with open("data.txt", "r", encoding="utf-8") as file:
content = file.read()
else:
content = ""
# EAFP: сначала пробуем
try:
with open("data.txt", "r", encoding="utf-8") as file:
content = file.read()
except FileNotFoundError:
content = ""
EAFP избавляет от лишних проверок и безопаснее в многопоточных сценариях.
pathlib и стиль EAFP не являются основной темой исходной лекции, но являются рекомендуемой практикой в современном Python. Поведение методов Path на разных операционных системах лучше уточнять в официальной документации.
🕰️ Когда старый подход ещё можно встретить
os.path и строковые пути всё ещё широко используются в старых проектах, учебных материалах и скриптах, где важна совместимость с Python 2. Для новых проектов на Python 3 рекомендуется отдавать предпочтение pathlib.