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.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
