After this lesson, you will be able to: Write Python classes with inheritance, dunder methods, properties, and dataclasses.
Python is multi-paradigm; you don't need OOP for everything. But when modeling real domains, classes + dataclasses are the cleanest path.
Dataclasses cut 80% of boilerplate.
from dataclasses import dataclass, fieldfrom typing import Optional@dataclassclass User:name: stremail: strage: int = 0tags: list[str] = field(default_factory=list) # mutable default trickdef adult(self) -> bool:return self.age >= 18print(u) # auto __repr__ via @dataclass# Frozen (immutable)@dataclass(frozen=True)class Point:x: floaty: float
__init__: constructor. __repr__: debug str. __str__: human str. __eq__: equality. __hash__: for set/dict keys. __len__: enables `len(obj)`. __iter__/__next__: iteration. __enter__/__exit__: context manager (`with obj:`). __call__: makes instance callable.
Use properties for computed values; inheritance sparingly.
class Animal:def __init__(self, name: str): self._name = name@propertydef name(self) -> str: return self._name@name.setterdef name(self, value: str):if not value.strip(): raise ValueError("empty")self._name = valuedef speak(self) -> str: return "..."class Dog(Animal):def speak(self) -> str: return "Woof"class Cat(Animal):def speak(self) -> str: return "Meow"# Polymorphismfor pet in [Dog("Rex"), Cat("Mimi")]:print(f"{pet.name}: {pet.speak()}")
Reaching for inheritance when composition would do. 'Has-a' beats 'is-a' more often than not. Skipping @dataclass. Hand-writing __init__ + __repr__ + __eq__ is yesterday's pattern. Storing _private attributes without good reason. Python has no real privacy; convention only. Forgetting `field(default_factory=list)` for mutable dataclass defaults.
Pick the cleanest answer.
Sign in and purchase access to unlock this lesson.