Classes

Classes are blueprints for creating objects. They bundle data (attributes) and behavior (methods) into reusable, self-contained units.

Defining a Class

class Dog:
    species = "Canis familiaris"  # class attribute

    def __init__(self, name, age):
        self.name = name          # instance attribute
        self.age = age

    def speak(self):
        return f"{self.name} says Woof!"

Python Playground
Output
Click "Run" to execute your code

Instance vs Class Attributes

class Counter:
    total = 0               # shared across all instances

    def __init__(self):
        Counter.total += 1
        self.id = Counter.total  # unique per instance

a = Counter()   # total = 1, a.id = 1
b = Counter()   # total = 2, b.id = 2
Type Defined Shared Access
Class attribute In class body Yes, all instances ClassName.attr or self.attr
Instance attribute In __init__ No, per instance self.attr

Methods

class MyClass:
    def instance_method(self):
        return f"instance: {self}"

    @classmethod
    def class_method(cls):
        return f"class: {cls}"

    @staticmethod
    def static_method():
        return "static: no access to cls or self"
Type Decorator First Arg Can Access
Instance method None self Instance and class data
Class method @classmethod cls Class data only
Static method @staticmethod None Neither (utility function)

Properties

Properties let you use methods like attributes, with controlled access:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("Radius cannot be negative")
        self._radius = value

    @property
    def area(self):
        return 3.14159 * self._radius ** 2

Python Playground
Output
Click "Run" to execute your code

Inheritance

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        raise NotImplementedError

class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"
Feature Syntax Description
Single inheritance class Child(Parent) Inherit from one class
Multiple inheritance class Child(A, B) Inherit from multiple classes
Call parent method super().method() Access overridden parent method
Check type isinstance(obj, Class) True if obj is instance of Class
Check subclass issubclass(Child, Parent) True if Child inherits from Parent

Using super()

class Animal:
    def __init__(self, name, sound):
        self.name = name
        self.sound = sound

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name, "Woof")
        self.breed = breed

rex = Dog("Rex", "Labrador")
# rex.name = "Rex", rex.sound = "Woof", rex.breed = "Labrador"

Special (Dunder) Methods

These methods let your classes work with Python's built-in operations:

Representation

Method Triggered By Purpose
__repr__(self) repr(obj) Developer-friendly string
__str__(self) str(obj), print(obj) User-friendly string
__format__(self, spec) format(obj, spec) Custom formatting

Comparison

Method Operator Example
__eq__(self, other) == a == b
__ne__(self, other) != a != b
__lt__(self, other) < a < b
__le__(self, other) <= a <= b
__gt__(self, other) > a > b
__ge__(self, other) >= a >= b

Arithmetic

Method Operator Example
__add__(self, other) + a + b
__sub__(self, other) - a - b
__mul__(self, other) * a * b
__truediv__(self, other) / a / b
__floordiv__(self, other) // a // b
__mod__(self, other) % a % b
__pow__(self, other) ** a ** b

Container

Method Triggered By Example
__len__(self) len(obj) len(my_list)
__getitem__(self, key) obj[key] my_list[0]
__setitem__(self, key, val) obj[key] = val my_list[0] = 1
__contains__(self, item) item in obj 3 in my_list
__iter__(self) for x in obj Iteration

Python Playground
Output
Click "Run" to execute your code

Dataclasses

The dataclasses module reduces boilerplate for classes that mainly store data:

from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float
    label: str = "origin"   # default value

# Auto-generates __init__, __repr__, __eq__
p = Point(1.0, 2.0)
print(p)   # Point(x=1.0, y=2.0, label='origin')
Parameter Effect Example
@dataclass Generate __init__, __repr__, __eq__ Default behavior
frozen=True Make instances immutable @dataclass(frozen=True)
order=True Generate comparison methods @dataclass(order=True)
slots=True Use __slots__ for memory efficiency @dataclass(slots=True)

Access Control Conventions

Python has no true private members, but uses naming conventions:

Prefix Convention Example
name Public self.name
_name Internal / protected self._name — use within class or subclasses
__name Name-mangled self.__nameself._ClassName__name

Class Composition

Favor composition over inheritance when classes aren't related by "is-a":

class Engine:
    def __init__(self, horsepower):
        self.horsepower = horsepower

    def start(self):
        return "Engine running"

class Car:
    def __init__(self, model, hp):
        self.model = model
        self.engine = Engine(hp)   # Car HAS an Engine

    def start(self):
        return f"{self.model}: {self.engine.start()}"

Abstract Base Classes

Define interfaces that subclasses must implement:

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

    @abstractmethod
    def perimeter(self):
        pass

class Rectangle(Shape):
    def __init__(self, w, h):
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h

    def perimeter(self):
        return 2 * (self.w + self.h)

# Shape() would raise TypeError
r = Rectangle(3, 4)