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 codeInstance 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 codeInheritance
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 codeDataclasses
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.__name → self._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)