Зарегистрируйтесь, чтобы продолжить обучение

Сборщики (Builders) Python: Объектно-ориентированный дизайн

Работа с данными в программировании является неотъемлемой частью процесса. Однако данные, которые мы получаем от пользователей или внешних систем, зачастую недостаточно «чистые». Например, они могут содержать ошибки или некорректные значения. Здесь на помощь приходят инструменты валидации — проверка данных на корректность по заданным условиям.

Валидация данных

Самый простой подход к валидации данных в Python — использовать базовые операторы языка и стандартные функции:

errors = []

if data['email'] == '':
    errors.append('Email is empty')

# Гипотетическая функция проверки формата
if not has_email_format(data['email']):
    errors.append('Email has incorrect format')

Правда такой код станет неприглядным и сложным при работе с большими формами и множеством правил валидации.

У этого подхода есть и другие недостатки. Например, он не поддерживает простое переиспользование правил для различных форм и проектов. Также многие проверки придется реализовывать вручную или использовать сторонние библиотеки. Это касается таких вещей, как проверка корректности URL-адресов, физических адресов и прочего.

Для более сложных случаев валидации и для большей структурированности кода используется паттерн проектирования Builder. Этот паттерн помогает разбить сложный процесс на более простые и управляемые части.

Builder

Builder (Строитель) — паттерн проектирования, который предлагает решение для проблемы создания сложных объектов. Он предлагает разделить процесс построения сложного объекта на различные части, каждая из которых отвечает за определенный аспект построения объекта. Так построение объекта становится более структурированным, гибким и понятным.

В объектно-ориентированных языках этот паттерн обычно реализуется с помощью fluent interface. В этом случае каждый метод возвращает ссылку на сам объект, что позволяет вызывать методы последовательно в одной цепочке.

Рассмотрим пример использования этого паттерна:

class DataValidator:
    def __init__(self, data):
        self.data = data
        self.errors = []

    def validate_email(self):
        if '@' not in self.data.get('email', ''):
            self.errors.append('Invalid email')
        return self

    def validate_password(self):
        if len(self.data.get('password', '')) < 8:
            self.errors.append('Password is too short')
        return self

    def get_errors(self):
        return self.errors

data = {"email": "test", "password": "short"}
validator = DataValidator(data)
errors = validator.validate_email().validate_password().get_errors()

if errors:
    print(errors)

Здесь мы создаем экземпляр класса DataValidator, передавая ему данные для валидации. Далее с помощью методов validate_email и validate_password проверяем данные на валидность. Если данные не проходят валидацию, соответствующие ошибки добавляются в список errors.

Такой подход позволяет последовательно применять различные проверки к данным и получать список всех ошибок в конце. Это делает код более чистым и упрощает процесс валидации данных.

В Python также существуют и готовые инструменты. Они могут значительно упростить процесс валидации и сделать код более чистым и структурированным. Один из таких инструментов — библиотека Pydantic.

Pydantic

Библиотека Pydantic предоставляет набор инструментов для валидации данных с использованием python-типов:

class User(BaseModel):
    name: str
    email: EmailStr

try:
    User(name='Tom', email='not a valid email')
except ValidationError as e:
    print(e)

Здесь мы определяем модель User, которая содержит два поля: name и email. Затем мы передаем некорректный email, чем пытаемся создать экземпляр User.

Так как EmailStr проверяет, что значение действительно является корректным адресом электронной почты, в этом случае будет выброшено исключение ValidationError.

Pydantic позволяет с помощью объявления типов поля в модели определять правила валидации. Например, мы можем определить, что возраст пользователя должен быть положительным числом:

class User(BaseModel):
    name: str
    email: EmailStr
    age: PositiveInt

try:
    User(name='Tom', email='tom@example.com', age=-1)
except ValidationError as e:
    print(e)

В этом примере PositiveInt гарантирует, что значение age является положительным целым числом. Так попытка создать пользователя с отрицательным возрастом вызывает ошибку валидации.

Однако валидация данных — это не единственная область, где может быть полезен паттерн Builder. Этот паттерн также широко используется для создания сложных запросов к базам данных.

Query Builder

Query Builder — паттерн проектирования, который позволяет собирать сложные запросы по частям. Чаще всего он встречается при работе с базами данных для сбора SQL либо для коллекций.

В Python одним из наиболее известных примеров использования этого паттерна является Django ORM. Это фреймворк, который позволяет строить запросы к базе данных с помощью fluent interface.

Вместо написания «сырых» SQL-запросов, мы используем методы Django ORM для построения запросов по частям. Это упрощает чтение и поддержку кода.

Рассмотрим пример:

# Запрос выборки для модели User с условиями и сортировкой
users = (
    User.objects.filter(name='Tom')
    .exclude(is_active=False)
    .order_by('-last_login')
)

for user in users:
    print(user.username)

В этом примере мы создаем запрос выборки (filter) для модели User, исключаем не активных пользователей (exclude) и сортируем результат по дате последнего входа в систему (order_by). Всё это происходит без написания SQL-запросов.

Также паттерн Builder в Django ORM позволяет легко изменить запрос с помощью добавления дополнительных условий, изменения порядка сортировки и прочего. Это делает код более гибким и поддерживаемым.

Выводы

Паттерн Builder позволяет упростить и структурировать процесс создания сложных объектов. Валидация данных и построение SQL-запросов являются отличными примерами использования этого паттерна. Они часто включают в себя сложные и многопараметричные проверки и действия.

Паттерн Builder предлагает эффективный способ упрощения и структурирования процессов создания сложных объектов в программировании. Он делает код более гибким и понятным. Это позволяет легко изменять и расширять функциональность кода.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
Программирование на Python, Разработка веб-приложений и сервисов используя Django, проектирование и реализация REST API
10 месяцев
с нуля
Старт 26 декабря

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»