Как избавиться от устаревших шаблонов проектирования в Python и начать писать чистый код

20 июня 2025 г.

Вступление

Когда я впервые начал изучать Python, я был уверен, что овладение шаблонами проектирования — это ключ к написанию "профессионального" кода. Я следовал всем учебникам и туториалам, которые нашел, и пытался втиснуть в Python шаблоны, придуманные для других языков. Но оказалось, что это только усложняет код и делает его менее читаемым. В этой статье мы разберем, почему это так и как писать код по-питонски.

Их много, как листьев в лесу,
Шаблоны проектирования — как ветер в саду,
Чистота кода — ветер на ветвях.

Проблема и её актуальность

Многие разработчики, пришедшие в Python из других языков программирования, пытаются применить шаблоны проектирования, которые они знают, такие как Singleton и Builder. Однако, Python, с его динамической типизацией и множеством встроенных возможностей, не нуждается в таких шаблонах. Их использование в Python часто приводит к избыточному коду и снижению его читаемости.

Пересказ Reddit поста своими словами

Когда я только начинал учить Python, я думал, что овладение шаблонами проектирования — это путь к написанию профессионального кода. Я перерыл интернет в поисках туториалов и следовал всем рекомендациям, как в "Банде четырёх". Я создавал синглет, билдер и другие шаблоны, чувствуя себя настоящим программистом. Но вскоре понял, что это было ошибкой.

Многие из этих шаблонов были придуманы для языков с другими ограничениями, например, Java или C++. Python же не имеет таких проблем, и попытки применить эти шаблоны в нем только усложняют код и делают его менее читаемым.

В своей статье я собрался рассказать, какие шаблоны проектирования стоит забыть, начиная с Singleton и Builder. Я не просто скажу "используй модули" или "используй параметры по умолчанию" в одном предложении. Мы рассмотрим реальные примеры из GitHub, увидим, как эти шаблоны применяются на практике, и как их можно переписать по-питонски.

Сущность проблемы, основные тенденции

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

Детальный разбор проблемы

Singleton

Singleton — это шаблон, который гарантирует, что у класса будет только один экземпляр и предоставляет глобальную точку доступа к этому экземпляру. В Python это можно реализовать с помощью модулей или замыканий, но это приводит к глобальным переменным, что является антишаблоном.

Альтернативой может быть использование регистра на уровне класса, где параметры (или их хэш) используются в качестве ключей. Это более гибкое и "питонское" решение.

Builder Pattern

Шаблон Builder используется для создания сложных объектов пошагово. В Python чаще всего используется именованные параметры для этого. Однако, в некоторых случаях, например, при создании запросов или строк, шаблон Builder может быть полезен.

Важно понимать, что использование Builder Pattern в Python должно быть обосновано и не приводить к избыточности кода.

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

Singleton в Python


# Пример использования Singleton с модулем
# Модуль автоматически создает один экземпляр класса

# singleton_module.py
class Singleton:
    def __init__(self):
        self.value = "I am a singleton"

singleton_instance = Singleton()
print(singleton_instance.value)  # I am a singleton

В этом примере модуль автоматически создает один экземпляр класса Singleton, что делает его Singleton.

Builder Pattern в Python


# Пример использования Builder Pattern для создания сложного объекта

class Car:
    def __init__(self, model, year, color, engine):
        self.model = model
        self.year = year
        self.color = color
        self.engine = engine

class CarBuilder:
    def __init__(self):
        self.model = None
        self.year = None
        self.color = None
        self.engine = None

    def set_model(self, model):
        self.model = model
        return self

    def set_year(self, year):
        self.year = year
        return self

    def set_color(self, color):
        self.color = color
        return self

    def set_engine(self, engine):
        self.engine = engine
        return self

    def build(self):
        return Car(self.model, self.year, self.color, self.engine)

# Использование Builder Pattern
car_builder = CarBuilder()
car = car_builder.set_model("Tesla").set_year(2023).set_color("Red").set_engine("Electric").build()
print(f"Car: {car.model}, {car.year}, {car.color}, {car.engine}")

В этом примере используется Builder Pattern для создания объекта Car пошагово.

Экспертные мнения из комментариев

Автор комментария divad1196 критикует подход автора статьи, утверждая, что Python не нуждается в шаблонах проектирования, придуманных для других языков. Он также предлагает использовать регистр на уровне класса для реализации Singleton.

While it's true that python doesn't have the same needs has other languages, you went completely wrong on your article.

Автор комментария Worth_His_Salt согласен с автором статьи, отмечая, что шаблоны проектирования часто неверно используются в Python и что знание других языков помогает быстрее освоить Python, но лучшие практики сильно отличаются.

Good post. Full content seems to be in depth and not just another surface-level slopfest like often pollutes this sub.

Автор комментария DrumAndBass90 отмечает, что стиль написания статьи ему понравился, и что он не понимает, почему другие авторы неудовлетворены.

Personally I liked the style of writing, I’m not sure where this sentiment is coming from. Good job!

Автор комментария Upset-Macaron-4078 выражает скептицизм по поводу статьи, утверждая, что она написана с помощью искусственного интеллекта и что интернет стал мертвым.

It’s so clearly AI written… i don’t like this new dead internet

Возможные решения и рекомендации

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

  • Использовать встроенные возможности Python, такие как модули и параметры по умолчанию.
  • Избегать глобальных переменных и предпочитать локальные переменные и функции.
  • Использовать регистр на уровне класса для реализации Singleton.
  • Обоснованно применять шаблоны проектирования, учитывая специфику задачи.

Заключение с прогнозом развития

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

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

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


# Пример использования регистра на уровне класса для реализации Singleton

class Singleton:
    _instances = {}

    def __new__(cls, *args, **kwargs):
        if cls not in cls._instances:
            instance = super(Singleton, cls).__new__(cls)
            cls._instances[cls] = instance
            instance._initialized = False
        return cls._instances[cls]

    def __init__(self, value):
        if self._initialized:
            return
        self.value = value
        self._initialized = True

    def __str__(self):
        return f"Singleton value: {self.value}"

# Использование Singleton
singleton1 = Singleton(10)
singleton2 = Singleton(20)

print(singleton1)  # Singleton value: 10
print(singleton2)  # Singleton value: 10

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


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE