← Назад к вопросам

Как уменьшишь количество аргументов в __init__?

2.0 Middle🔥 111 комментариев
#Python Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы уменьшить количество аргументов в init

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

1. Использование DataClass или Pydantic

Вместо множества примитивных параметров создавай объект конфигурации:

# ❌ Плохо
class User:
    def __init__(self, first_name, last_name, email, phone, address, city, country):
        self.first_name = first_name
        self.last_name = last_name
        # ... 5 еще атрибутов

# ✅ Хорошо
from dataclasses import dataclass

@dataclass
class Address:
    street: str
    city: str
    country: str

@dataclass
class UserConfig:
    first_name: str
    last_name: str
    email: str
    phone: str
    address: Address

class User:
    def __init__(self, config: UserConfig):
        self.config = config

2. Builder Pattern

Строитель позволяет конфигурировать объект пошагово:

class DatabaseConfig:
    def __init__(self):
        self.host = "localhost"
        self.port = 5432
        self.username = "user"
        self.password = "pass"
        self.ssl = False

    def with_host(self, host: str):
        self.host = host
        return self

    def with_ssl(self, ssl: bool):
        self.ssl = ssl
        return self

    def build(self):
        return Database(self)

db = DatabaseConfig() \
    .with_host("prod.db.com") \
    .with_ssl(True) \
    .build()

3. Значения по умолчанию и **kwargs

class APIClient:
    def __init__(self, base_url: str, **options):
        self.base_url = base_url
        self.timeout = options.get("timeout", 30)
        self.retries = options.get("retries", 3)
        self.verify_ssl = options.get("verify_ssl", True)
        self.headers = options.get("headers", {})

client = APIClient(
    "https://api.example.com",
    timeout=60,
    verify_ssl=False
)

4. Factory Method Pattern

Отделяй создание от инициализации:

class DatabaseConnection:
    def __init__(self, connection_string: str):
        self.connection_string = connection_string

    @classmethod
    def from_config(cls, config_path: str):
        # Парсим конфиг из файла
        connection_string = parse_config(config_path)
        return cls(connection_string)

    @classmethod
    def from_env(cls):
        # Берем из переменных окружения
        return cls(os.getenv("DATABASE_URL"))

# Использование
db = DatabaseConnection.from_env()

5. Логическая группировка параметров

Объедини связанные параметры в отдельные объекты:

# ❌ Много параметров
class WebServer:
    def __init__(self, host, port, workers, timeout, max_connections, ssl_cert, ssl_key):
        pass

# ✅ Организовано
from dataclasses import dataclass

@dataclass
class ServerConfig:
    host: str
    port: int
    workers: int

@dataclass
class SSLConfig:
    cert_path: str
    key_path: str

@dataclass
class TimeoutConfig:
    request: int
    connection: int
    max_connections: int

class WebServer:
    def __init__(self, server: ServerConfig, ssl: SSLConfig, timeout: TimeoutConfig):
        self.server = server
        self.ssl = ssl
        self.timeout = timeout

6. Наследование и комбинирование

Если параметры относятся к разным аспектам, раздели на подклассы:

class BaseRepository:
    def __init__(self, db_connection):
        self.db = db_connection

class UserRepository(BaseRepository):
    def __init__(self, db_connection, cache=None, logger=None):
        super().__init__(db_connection)
        self.cache = cache
        self.logger = logger

Правило большого пальца

Если в __init__ более 3-4 параметров — это признак того, что нужен рефакторинг. Используй:

  • DataClass или Pydantic для конфигурации
  • Builder для пошагового построения
  • Factory методы для создания
  • Dependency Injection контейнеры

Это делает код чище, тестируемее и более поддерживаемым.

Как уменьшишь количество аргументов в __init__? | PrepBro