@dataclass

from dataclasses import dataclass, field

@dataclass
class Drone:
    id: str
    battery: float = 100.0 # set default 
    capabilities: list[str] = field(init=False) # don't accept this as a constructor argument
    
def __post_init__(self) -> None:
    # runs automatically after __init__
    self.capabilities = CAPABILITIES[self.type] + COMMON_CAPABILITIES

Usage:

drone = Drone(id="scanner_8001_a3f2", type=DroneType.SCANNER)
drone.battery       # 100.0 — default
drone.capabilities  # set by __post_init__

Pydantic

from pydantic import BaseModel, Field

class ScanRequest(BaseModel):
		# ge=1 means greater or equal to 1. 
		# le=10 means less or equal to 10.
    radius: int = Field(default=3, ge=1, le=10)
class Position(BaseModel):
    x: int
    y: int
    z: int

# create from dict
pos = Position(**{"x": 3, "y": 2, "z": 0})
pos.x     # 3

# serialize back to dict
pos.model_dump()   # {"x": 3, "y": 2, "z": 0}

Enum

from enum import Enum

# str, Enum means each value IS a string 
class DroneStatus(str, Enum):
    IDLE = "idle"
    MOVING = "moving"
    CHARGING = "charging"