Classes
Classes are blueprints for creating objects. They bundle data (attributes) and behavior (methods) into reusable, self-contained units.
Defining a Class
python
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
python
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
python
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:
python
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
python
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()
python
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:
python
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":
python
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:
python
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)