Python - OOP tip: set attributes in the constructor


Python Clean Code Tip:

Avoid setting attributes of your objects outside of the constructor. Instead, implement methods that map to real-world concepts.

Why?

To ensure attributes exist and are easily discoverable.

👇

from dataclasses import dataclass
from enum import Enum
from uuid import UUID


class OrderStatus(str, Enum):
    PLACED = "PLACED"
    CANCELED = "CANCELED"
    FULFILLED = "FULFILLED"


# bad
@dataclass
class Order:
    status: OrderStatus


class CancelOrder:
    def __init__(self, order_repository):
        self.order_repository = order_repository

    def execute(self, order_id: UUID):
        order = self.order_repository.get_by_id(order_id)
        order.status = OrderStatus.CANCELED
        self.order_repository.save(order)


# better
class Order:
    def __init__(self, status: OrderStatus):
        self._status = status

    def cancel(self):
        self._status = OrderStatus.CANCELED


class CancelOrder:
    def __init__(self, order_repository):
        self.order_repository = order_repository

    def execute(self, order_id: UUID):
        order = self.order_repository.get_by_id(order_id)
        order.cancel()
        self.order_repository.save(order)