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

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

Старый: глубокая вложенность if внутри if — код уходит вправо и его сложно читать.

Новый: плоские конструкции с логическими операторами, guard clauses и match-case для множества вариантов.

Вывод: используйте вложенность только тогда, когда она действительно отражает иерархию проверок; в остальных случаях стремитесь к плоскому коду.

📜 Как показано в исходном PDF

Исходный материал демонстрирует вложенные условия на примере проверки прав пользователя:

role = "admin"
section_access = True

if role == "admin":
    print("Вы администратор.")
    if section_access:
        print("У вас есть доступ к разделу.")
    else:
        print("У вас нет доступа к разделу.")
else:
    print("Вы не администратор.")

Что здесь происходит: сначала проверяется роль, и только для администратора проверяется доступ. Логика верная, но уже на двух уровнях вложенности код начинает «уходить вправо».

❌ Почему этот подход может быть не лучшим сейчас

  • Глубина вложенности. Каждый новый if внутри другого добавляет отступ. При трёх-четырёх уровнях строки уходят далеко вправо, и код сложно воспринимать.
  • Смешение ответственности. В одном блоке проверяется и роль, и доступ. Разделить эти проверки помогает быстрее находить ошибки.
  • Трудности с расширением. Добавить новую роль или новое условие доступа в глубоко вложенной структуре сложнее, чем в плоской.

✅ Рекомендуемый современный вариант

Тот же сценарий без лишней вложенности. Сначала обрабатываем простые случаи, затем основной:

role = "admin"
section_access = True

if role != "admin":
    print("Вы не администратор.")
elif not section_access:
    print("Вы администратор.")
    print("У вас нет доступа к разделу.")
else:
    print("Вы администратор.")
    print("У вас есть доступ к разделу.")

Что улучшилось: все проверки находятся на одном уровне отступа. Каждый блок отвечает за свой случай, и логика читается сверху вниз как набор правил.

Преимущества:
  • Меньше уровней отступов — код не уходит вправо.
  • Каждое условие видно сразу, не нужно разворачивать вложенные блоки.
  • Проще добавлять новые роли и проверки.

🛡️ Guard clauses (ранний возврат)

В функциях часто применяют приём guard clause: сначала проверяются «плохие» случаи и сразу возвращается результат, а основная логика остаётся на верхнем уровне.

📄 modern_guard.py
def describe_access(role, section_access):
    if role != "admin":
        return "Вы не администратор."
    if not section_access:
        return "У вас нет доступа к разделу."
    return "У вас есть доступ к разделу."

print(describe_access("admin", True))
Проверить по документации: guard clauses — это соглашение о стиле, а не синтаксис Python; подробнее можно найти в руководствах по чистому коду и PEP 8.

🎯 match-case вместо длинных цепочек elif

Если нужно сравнить одну переменную с множеством значений, современный Python предлагает match-case вместо длинной лестницы elif.

📄 modern_match.py
month = 3

match month:
    case 12 | 1 | 2:
        season = "Зима"
    case 3 | 4 | 5:
        season = "Весна"
    case 6 | 7 | 8:
        season = "Лето"
    case 9 | 10 | 11:
        season = "Осень"
    case _:
        season = "Некорректный месяц"

print(season)

🕰️ Когда старый подход ещё можно встретить

Вложенные условия всё ещё уместны, когда проверки действительно иерархичны: сначала проверяем существование объекта, затем — его свойство, затем — свойство свойства. Например:

if user is not None:
    if user.account is not None:
        if user.account.is_active:
            print("Активный пользователь")

Даже здесь современный стиль часто заменяет такую вложенность цепочкой and или guard clauses, но в legacy-коде вложенность встречается часто. Главное — уметь её распознавать и постепенно упрощать.