⚖️ Старый и современный подход

⚡ Различия в двух словах

Из источника: строковые пути и функции os.path с предварительными проверками os.path.exists.

Современная практика: объектно-ориентированный pathlib.Path, перегрузка / для построения путей и стиль EAFP через try/except.

Вывод: os.path всё ещё работает и встречается в старых проектах, но для нового кода предпочтительнее pathlib.

📜 Как показано в исходном материале

Исходная лекция использует модуль 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")

Этот подход называется LBYLLook 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.pathpathlib
Текущая директория 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 часто предпочитают стиль EAFPEasier 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.