Python OOP: Classes, Inheritance, Dunder Methods, and Dataclasses Explained

Python OOP: Classes, Inheritance, Dunder Methods, and Dataclasses Explained

Python OOP is more powerful than most developers realize — and most developers have never needed to use __slots__, __getattr__, or abstract base classes. But when you need private state, custom operators, property validation, or enforcing interface contracts, these features are exactly what you reach for.

TL;DR: __init__ for initialization. @property for computed attributes with validation. @classmethod for alternative constructors. @staticmethod for utility methods. super() for safe inheritance. ABC for interface contracts. Dunder methods for operator overloading.

Classes, properties, and descriptors

class BankAccount:
  def __init__(self, owner: str, balance: float = 0):
    self._owner = owner
    self._balance = float(balance)

  @property
  def balance(self) -> float:   # Getter
    return self._balance

  @balance.setter
  def balance(self, value: float):  # Setter with validation
    if value < 0:
      raise ValueError(f'Balance cannot be negative: {value}')
    self._balance = float(value)

  @classmethod
  def from_dict(cls, data: dict) -> 'BankAccount':  # Alt constructor
    return cls(data['owner'], data.get('balance', 0))

  @staticmethod
  def validate_currency(code: str) -> bool:  # Utility, no self/cls
    return code.upper() in {'USD','EUR','GBP'}

Inheritance and super()

class SavingsAccount(BankAccount):
  def __init__(self, owner, balance=0, interest_rate=0.05):
    super().__init__(owner, balance)  # ALWAYS call super().__init__
    self._rate = interest_rate

  def apply_interest(self):
    self.balance += self.balance * self._rate  # Uses property validation

  @property
  def balance(self):
    return super().balance  # Can override properties

# Multiple inheritance: MRO (Method Resolution Order)
class A: def method(self): return 'A'
class B(A): def method(self): return 'B'+super().method()
class C(A): def method(self): return 'C'+super().method()
class D(B,C): pass
D().method() # 'BCА' — follows C3 linearization MRO

Dunder methods — operator overloading

class Vector:
  def __init__(self, x, y): self.x,self.y = x,y

  def __repr__(self): return f'Vector({self.x},{self.y})'
  def __str__(self):  return f'({self.x},{self.y})'
  def __len__(self):  return 2
  def __add__(self, other): return Vector(self.x+other.x,self.y+other.y)
  def __mul__(self, scalar): return Vector(self.x*scalar,self.y*scalar)
  def __eq__(self, other): return self.x==other.x and self.y==other.y
  def __hash__(self): return hash((self.x,self.y))  # Needed for sets/dicts
  def __iter__(self): yield self.x; yield self.y
  def __getitem__(self,i): return (self.x,self.y)[i]

v1,v2 = Vector(1,2),Vector(3,4)
v1+v2  # Vector(4,6)
v1*3   # Vector(3,6)
list(v1) # [1,2]

Abstract base classes

from abc import ABC, abstractmethod

class Shape(ABC):
  @abstractmethod
  def area(self) -> float: ...   # Must implement

  @abstractmethod
  def perimeter(self) -> float: ...

  def describe(self) -> str:     # Concrete — shared by all
    return f'{type(self).__name__}: area={self.area():.2f}'

class Circle(Shape):
  def __init__(self, r): self.r = r
  def area(self): import math; return math.pi*self.r**2
  def perimeter(self): import math; return 2*math.pi*self.r

# Shape()  # TypeError: Can't instantiate abstract class
Circle(5).describe()  # 'Circle: area=78.54'
  • ✅ @property for attribute validation without breaking interface
  • ✅ super().__init__() always in subclass init
  • ✅ __repr__ for debugging, __str__ for display
  • ✅ __hash__ required when you define __eq__
  • ✅ ABC for enforcing interface contracts
  • ❌ Never use name mangling (__attr) unless truly private
  • ❌ Never inherit from multiple classes with conflicting __init__

External reference: Python data model documentation.

Recommended Reading

Designing Data-Intensive Applications — The bible of distributed systems and production engineering at scale.

The Pragmatic Programmer — Timeless engineering wisdom every senior developer needs.

Affiliate links. We earn a small commission at no extra cost to you.

Free Weekly Newsletter

🚀 Join 2,000+ Senior Developers

Get expert-level JavaScript, Python, AWS, system design and AI secrets every week. Zero fluff, pure signal.

✓ No spam✓ Unsubscribe anytime✓ Expert-level only

Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply