Принцип DRY в Python: как избегать повторений в коде

Принцип DRY в Python: как избегать повторений в коде


Принцип DRY в Python: как избегать повторений в коде

Принцип DRY (Don’t Repeat Yourself — «Не повторяйся») — одно из ключевых правил разработки программного обеспечения. Он направлен на минимизацию дублирования кода, что упрощает поддержку, уменьшает вероятность ошибок и повышает читаемость. В этой статье мы разберем, как применять DRY в Python, и покажем практические примеры.


Что такое DRY?

DRY — принцип, сформулированный в книге «The Pragmatic Programmer». Его суть:

«Каждое знание должно иметь единственное, однозначное представление в системе».

На практике это означает:

  • Избегайте копирования блоков кода.
  • Выносите повторяющуюся логику в функции, классы или модули.
  • Используйте абстракции для управления изменениями.

Почему DRY важен?

  1. Упрощение изменений: Исправления вносятся в одном месте.
  2. Снижение ошибок: Меньше копий → меньше шансов забыть обновить дубликат.
  3. Читаемость: Код становится компактным и структурированным.

Примеры нарушений DRY и их исправление

1. Повторяющиеся вычисления

Проблема:

# Расчет НДС для трех товаров
price1 = 100
vat1 = price1 * 0.20  # НДС 20%

price2 = 200
vat2 = price2 * 0.20

price3 = 150
vat3 = price3 * 0.20

Решение через DRY:

def calculate_vat(price):
    return price * 0.20

prices = [100, 200, 150]
vats = [calculate_vat(price) for price in prices]

2. Дублирование условий

Проблема:

if user_role == "admin":
    print("Доступ разрешен")
    log_action("Администратор вошел в систему")
elif user_role == "editor":
    print("Доступ разрешен")
    log_action("Редактор вошел в систему")
elif user_role == "guest":
    print("Доступ запрещен")

Решение через DRY:

access_rules = {
    "admin": ("Доступ разрешен", "Администратор вошел в систему"),
    "editor": ("Доступ разрешен", "Редактор вошел в систему"),
    "guest": ("Доступ запрещен", "")
}

if user_role in access_rules:
    message, log_message = access_rules[user_role]
    print(message)
    if log_message:
        log_action(log_message)

3. Повторяющиеся функции

Проблема:

def send_email_user(user_email, message):
    # Код отправки email
    ...

def send_email_admin(admin_email, message):
    # Тот же код, но для админа
    ...

Решение через DRY:

def send_email(recipient, message):
    # Общая логика отправки
    ...

send_email(user_email, "Привет!")
send_email(admin_email, "Отчет готов")

Техники применения DRY в Python

1. Функции и классы

Выносите повторяющиеся операции в функции или методы классов:

# Вместо этого:
area1 = 3.14 * radius1 ** 2
area2 = 3.14 * radius2 ** 2

# Используйте функцию:
def circle_area(radius):
    return 3.14 * radius ** 2

2. Циклы и генераторы

Заменяйте повторяющиеся строки циклами:

# Плохо:
print("Строка 1")
print("Строка 2")
print("Строка 3")

# Хорошо:
for i in range(1, 4):
    print(f"Строка {i}")

3. Декораторы

Для повторяющейся логики (например, логирования или проверки прав):

def log_time(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"Время выполнения: {time.time() - start:.2f} сек")
        return result
    return wrapper

@log_time
def process_data(data):
    # Логика обработки
    ...

4. Наследование

Если классы имеют общую функциональность:

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        raise NotImplementedError

class Dog(Animal):
    def speak(self):
        return "Гав!"

class Cat(Animal):
    def speak(self):
        return "Мяу!"

5. Использование библиотек

Не изобретайте велосипеды. Например, для работы с датами используйте datetime:

from datetime import datetime

now = datetime.now()  # Вместо ручного парсинка времени

Когда DRY не стоит применять?

  1. Избыточная абстракция: Не нужно объединять код, который лишь кажется похожим, но имеет разную природу.
  2. Микроменеджмент: Иногда дублирование пары строк лучше, чем усложнение архитектуры.
  3. Прототипирование: На ранних этапах можно нарушать DRY ради скорости.

Практические кейсы применения

  1. Валидация данных: Создайте единую функцию для проверки входных параметров.
  2. Шаблоны сообщений: Используйте f-strings или шаблонизаторы (например, Jinja2) для генерации текста.
  3. Конфигурация: Храните настройки в отдельном файле (config.py или .env).

Заключение

Принцип DRY в Python помогает писать чистый, поддерживаемый и масштабируемый код. Главное — находить баланс: устранять вредное дублирование, но не создавать избыточных абстракций. Используйте функции, классы, декораторы и стандартные библиотеки, чтобы код оставался «сухим» (в хорошем смысле!).

Совет: Перед тем как скопировать код, спросите себя:
«Можно ли это вынести в отдельный модуль?». Часто ответ будет «да».