A
AiTechWorlds
AiTechWorlds
Classes, inheritance, magic methods, properties, dataclasses, ABCs, and common design patterns in Python.
class Animal:
# Class variable β shared across all instances
kingdom = "Animalia"
def __init__(self, name: str, age: int):
# Instance variables β unique to each object
self.name = name
self.age = age
self._health = 100 # convention: protected (single underscore)
self.__id = id(self) # private (name-mangled to _Animal__id)
def speak(self) -> str:
return f"{self.name} makes a sound"
def __repr__(self) -> str:
return f"Animal(name={self.name!r}, age={self.age})"
def __str__(self) -> str:
return f"{self.name} (age {self.age})"
def __eq__(self, other) -> bool:
return isinstance(other, Animal) and self.name == other.name
dog = Animal("Rex", 3)
print(dog) # Rex (age 3)
print(repr(dog)) # Animal(name='Rex', age=3)class Dog(Animal):
def __init__(self, name: str, age: int, breed: str):
super().__init__(name, age) # call parent __init__
self.breed = breed
def speak(self) -> str:
return f"{self.name} barks" # override parent method
def fetch(self, item: str) -> str:
return f"{self.name} fetches {item}"
class ServiceDog(Dog):
def __init__(self, name: str, age: int, breed: str, role: str):
super().__init__(name, age, breed)
self.role = role
def speak(self) -> str:
return f"{self.name} (service: {self.role}) barks quietly"
# MRO β Method Resolution Order
print(ServiceDog.__mro__)
# (ServiceDog, Dog, Animal, object)class Temperature:
def __init__(self, celsius: float):
self.celsius = celsius
def to_fahrenheit(self) -> float:
"""Instance method β has access to self"""
return self.celsius * 9/5 + 32
@classmethod
def from_fahrenheit(cls, f: float) -> "Temperature":
"""Class method β has access to cls, used as factory"""
return cls((f - 32) * 5/9)
@staticmethod
def is_valid(c: float) -> bool:
"""Static method β no self or cls, just a utility"""
return c >= -273.15
t = Temperature(100)
t2 = Temperature.from_fahrenheit(212)
Temperature.is_valid(-300) # Falseclass Circle:
def __init__(self, radius: float):
self._radius = radius
@property
def radius(self) -> float:
return self._radius
@radius.setter
def radius(self, value: float):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@property
def area(self) -> float:
import math
return math.pi * self._radius ** 2
c = Circle(5)
c.radius = 10 # calls setter
print(c.area) # calls getter β 314.15...from dataclasses import dataclass, field
@dataclass
class Point:
x: float
y: float
z: float = 0.0 # default value
tags: list = field(default_factory=list) # mutable default
def distance_to_origin(self) -> float:
return (self.x**2 + self.y**2 + self.z**2) ** 0.5
p = Point(1.0, 2.0)
print(p) # Point(x=1.0, y=2.0, z=0.0, tags=[])
p == Point(1.0, 2.0) # True β __eq__ auto-generatedfrom abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
@abstractmethod
def perimeter(self) -> float: ...
def describe(self) -> str:
return f"Area: {self.area():.2f}, Perimeter: {self.perimeter():.2f}"
class Rectangle(Shape):
def __init__(self, w: float, h: float):
self.w, self.h = w, h
def area(self) -> float:
return self.w * self.h
def perimeter(self) -> float:
return 2 * (self.w + self.h)
# Shape() β TypeError: Can't instantiate abstract class| Method | Triggered By |
|---|---|
__init__ | obj = Class() |
__repr__ | repr(obj), debugging |
__str__ | str(obj), print(obj) |
__eq__ | obj1 == obj2 |
__lt__, __gt__ | <, > comparisons |
__len__ | len(obj) |
__getitem__ | obj[key] |
__setitem__ | obj[key] = value |
__contains__ | item in obj |
__iter__, __next__ | for x in obj |
__enter__, __exit__ | with obj: |
__call__ | obj() |
__add__ | obj1 + obj2 |
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instanceclass ShapeFactory:
@staticmethod
def create(shape_type: str, **kwargs) -> Shape:
shapes = {"rectangle": Rectangle, "circle": Circle}
cls = shapes.get(shape_type)
if cls is None:
raise ValueError(f"Unknown shape: {shape_type}")
return cls(**kwargs)class EventEmitter:
def __init__(self):
self._listeners: dict[str, list] = {}
def on(self, event: str, callback):
self._listeners.setdefault(event, []).append(callback)
def emit(self, event: str, *args, **kwargs):
for cb in self._listeners.get(event, []):
cb(*args, **kwargs)def __init__(self, items=[])) β shared across all instances, causes subtle bugssuper().__init__() in subclass __init__ β parent state never initialized__repr__ β makes debugging and logging nearly useless__private attributes from outside the class β breaks encapsulation and won't work as expected (name mangling)Download Python OOP: Classes & Design Patterns
Get this note + 100s more free on Telegram
Get more notes like this daily on Telegram!
Free study notes, cheat sheets & AI tips
Join AiTechWorlds on Telegram and get daily AI tips, prompt engineering templates, coding resources, and exclusive content β 100% free!
No spam. Leave anytime.