Long Parameter List

Given following class Order:

class Order:
   _id: str
   _customer_id: str
   _customer_address: str
   _has_priority: bool
   _product_ids: list[str]

   def __init__(
      self,
      id: str,
      customer_id: str,
      customer_address: str,
      product_ids: list[str],
      is_premium_customer: bool,
   ) -> None:
      self._id = id
      self._customer_id = customer_id
      self._customer_address = customer_address
      self._product_ids = product_ids.copy()
      self._has_priority = is_premium_customer

   def get_product_ids(self):
      return self._product_ids

   def get_customer_id(self) -> str:
      return self._customer_id

Issues

Make id parameter optional

This would require moving the parameter to the end breaking all client code.

Knowing too much

Initializer receives a set of arguments which characterize customer. This introduces strong coupling between customer details and order. What if we need to add another customer attribute?

This would break all client code.

Parameter order

Because the list of parameters is more than 2-3, it is very likely the client code to pass parameters in wrong order.

Solution 1

One possible approach is to make all parameters keyword parameters, by specifying asterisk ‘*’ after the self parameter. This will force the client code to always pass keyword arguments.

Further to address the knowledge about customer we create a Customer class and replace all customer-related parameters with a single parameter customer.

 1from dataclasses import dataclass
 2from uuid import uuid4
 3
 4@dataclass
 5class Customer:
 6   id: str
 7   address: str
 8   has_premium_subscription: bool = False
 9
10class Order:
11   _id: str
12   _customer: Customer
13   _product_ids: list[str]
14
15   def __init__(
16      self,
17      *,
18      customer: Customer,
19      product_ids: list[str],
20      id: str = None
21   ) -> None:
22      self._id = id | uuid4()
23      self._customer = customer
24      self._product_ids = product_ids.copy()
25
26   def get_product_ids(self):
27      return self._product_ids
28
29   def get_customer_id(self) -> str:
30      return self._customer_id