1. Фундамент чистого кода: PEP 8, аннотации типов и принципы SOLID
Фундамент чистого кода: PEP 8, аннотации типов и принципы SOLID
Добро пожаловать на курс «Паттерны проектирования и чистый код на Python». Мы начинаем наше путешествие не с самих паттернов, а с фундамента, на котором строится любое качественное приложение. Паттерны — это архитектурные решения, но даже самая гениальная архитектура рухнет, если кирпичи, из которых она сложена, будут кривыми и хрупкими.
В этой статье мы разберем три кита профессиональной разработки на Python: стандарт оформления кода PEP 8, систему аннотации типов и принципы объектно-ориентированного проектирования SOLID.
> Любой дурак может написать код, который поймет компьютер. Хорошие программисты пишут код, который поймут люди. — Мартин Фаулер Refactoring: Improving the Design of Existing Code
PEP 8: Конституция Python-разработчика
Python славится своей читаемостью. Во многом это заслуга PEP 8 — документа, описывающего соглашения о том, как писать код на Python. Это не просто рекомендации, это стандарт индустрии. Если вы пишете код «как вам удобно», игнорируя PEP 8, ваш код будет чужеродным для любого другого Python-разработчика.
Основные правила именования
Именование переменных и функций — это самая частая проблема новичков. В Python приняты следующие конвенции:
Пример правильного именования:
Форматирование и структура
Чистота кода также зависит от визуального восприятия:
* Отступы: Используйте 4 пробела на уровень отступа. Никогда не смешивайте табуляцию и пробелы. * Длина строки: Ограничивайте длину строки до 79 символов. Это позволяет открывать несколько файлов рядом в редакторе. * Импорты: Импорты всегда должны быть в начале файла. Сначала стандартные библиотеки, затем сторонние, затем локальные модули проекта.
Соблюдать эти правила вручную сложно. Поэтому в профессиональной среде используют линтеры и форматтеры, такие как flake8, black или ruff. Они автоматически проверяют и исправляют ваш код.
Аннотации типов: от динамики к надежности
Python — язык с динамической типизацией. Это значит, что переменная может хранить сначала число, а потом строку. Это удобно для скриптов, но в больших проектах это источник ошибок. Начиная с версии 3.5, Python поддерживает Type Hints (подсказки типов).
Аннотации типов не влияют на выполнение кода (интерпретатор их игнорирует), но они критически важны для:
mypy может найти ошибки типов до запуска программы.Примеры использования
Рассмотрим функцию без аннотаций:
Что будет, если передать в name число? Программа упадет с ошибкой во время выполнения. Теперь добавим типы:
Теперь мы явно сказали: name должно быть строкой, и функция вернет строку. Для более сложных структур используется модуль typing (или встроенные типы в новых версиях Python).
Использование аннотаций типов — это стандарт современного Python-кода, особенно при работе с паттернами проектирования, где важны интерфейсы и контракты взаимодействия.
Принципы SOLID
SOLID — это акроним пяти принципов объектно-ориентированного программирования, сформулированных Робертом Мартином. Эти принципы помогают создавать гибкие и поддерживаемые системы.
!Пять столпов принципов SOLID, удерживающих архитектуру приложения.
Разберем каждый принцип на примерах Python.
S — Single Responsibility Principle (Принцип единственной ответственности)
Класс должен иметь только одну причину для изменения.
Это значит, что класс должен делать только одну вещь. Если класс UserHandler и сохраняет пользователя в базу данных, и отправляет ему приветственное письмо, и валидирует данные — это нарушение SRP.
Плохо:
Хорошо:
Теперь, если изменится логика отправки почты, мы не трогаем класс User или UserRepository.
O — Open/Closed Principle (Принцип открытости/закрытости)
Программные сущности должны быть открыты для расширения, но закрыты для модификации.
Вы должны иметь возможность добавлять новый функционал, не переписывая старый работающий код.
Представьте, что у нас есть класс, рассчитывающий площади фигур. Если для добавления новой фигуры (например, треугольника) вам нужно лезть в метод calculate_area и добавлять туда новый if/elif, вы нарушаете OCP.
Решение: Использовать полиморфизм. Создать абстрактный базовый класс Shape с методом area, и наследовать от него конкретные фигуры.
L — Liskov Substitution Principle (Принцип подстановки Барбары Лисков)
Объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы.
Если класс B наследуется от класса A, то мы должны иметь возможность использовать B везде, где используется A, и код не должен ломаться.
Классический пример нарушения: Квадрат, наследуемый от Прямоугольника. В геометрии квадрат — это прямоугольник. В программировании — нет. Если код ожидает, что у прямоугольника можно менять ширину и высоту независимо, то подстановка квадрата (у которого изменение ширины меняет и высоту) сломает логику.
Совет: Если вам нужно проверять тип объекта (isinstance), чтобы код работал правильно, вы, скорее всего, нарушаете LSP.
I — Interface Segregation Principle (Принцип разделения интерфейса)
Клиенты не должны зависеть от методов, которые они не используют.
Лучше создать много узкоспециализированных интерфейсов, чем один «божественный» интерфейс общего назначения.
Представьте интерфейс SmartDevice, у которого есть методы print(), scan() и fax(). Если мы создаем класс SimplePrinter, который умеет только печатать, нам придется реализовать методы scan и fax (например, выбрасывая ошибки), что плохо.
Решение: Разбить на Printer, Scanner, FaxMachine. SimplePrinter будет наследовать только Printer.
D — Dependency Inversion Principle (Принцип инверсии зависимостей)
Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те, и другие должны зависеть от абстракций.
Это ключевой принцип для создания слабосвязанной архитектуры. Ваш бизнес-код (высокий уровень) не должен знать, какую именно базу данных (низкий уровень) вы используете (PostgreSQL, MySQL или файл).
Плохо:
Хорошо:
Теперь наш выключатель может работать с любым устройством, реализующим интерфейс Switchable.
Заключение
Соблюдение PEP 8 делает ваш код читаемым. Аннотации типов делают его надежным и предсказуемым. Принципы SOLID делают его гибким и расширяемым. Это база, без которой изучение паттернов проектирования превратится в простое заучивание схем без понимания их сути.
В следующей статье мы перейдем к порождающим паттернам и разберем, как правильно создавать объекты в сложных системах.