Object‑oriented programming organises code around classes (blueprints) and the objects built from them. Data lives in attributes, actions live in methods.
class Dog:
species = "Canis lupus" # one value shared by all dogs
def __init__(self, name): # runs when a dog is created
self.name = name # unique to each dog
def speak(self):
return f"{self.name} says Woof!"
Dog("Fido")
makes a new dog. Its name is just for Fido, while species
lives once in the class. Every instance method needs self
as the first argument.
fido = Dog("Fido")
fido.species = "Mutant" # affects only this object
print(Dog.species) # still "Canis lupus"
An attribute set on one object stays on that object. A value written in the class body is shared by all objects.
__str__
and __repr__
class Car:
def __init__(self, make, year):
self.make, self.year = make, year
def __str__(self): # friendly text for print()
return f"{self.year} {self.make}"
def __repr__(self): # precise text for debugging
return f"Car({self.make!r}, {self.year})"
__str__
supplies the readable string shown by print
. __repr__
supplies an unambiguous string shown in interactive sessions and logs.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError
class Cat(Animal):
def speak(self):
return "Meow!"
A child class re‑uses code from its parent and changes only what is different. If the parent’s constructor also needs to run, call it with super().__init__(...)
.
class Engine:
def __init__(self, hp):
self.hp = hp
class Vehicle:
def __init__(self, engine):
self.engine = engine # Vehicle owns an Engine
Composition stores one object inside another. Swapping the owned part (for example, a stronger engine) does not require rewriting the outer class.
class BankAccount:
def __init__(self, balance):
self.__balance = balance
def deposit(self, amount):
self.__balance += amount
Two underscores change __balance
into a longer internal name, so outside code won't touch it by mistake.
property
for Controlled Accessclass Celsius:
def __init__(self, deg):
self._deg = deg
@property
def deg(self): # getter
return self._deg
@deg.setter
def deg(self, value): # setter
if value < -273.15:
raise ValueError("Below absolute zero")
self._deg = value
The @property
decorator lets you read temp.deg
like a normal attribute which we called it getter, while the paired setter runs validation whenever you assign to it.
class Circle:
pi = 3.14159 # stored once in the class
def __init__(self, r):
self.r = r # radius belongs to one circle
@classmethod
def unit(cls): # alternative constructor
return cls(1)
@staticmethod
def area(r): # helper that needs no object
return Circle.pi * r * r
pi
is a class constant. The unit
method receives the class (cls
) so it can create Circle
objects and still work for subclasses. The area
method is labelled @staticmethod
because it relies on neither self
nor cls
; it is simply grouped with the class for convenience and is called as Circle.area(5)
.
class Rectangle:
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
class Circle:
def __init__(self, r):
self.r = r
def area(self):
return 3.14 * self.r ** 2
shapes = [Rectangle(3, 4), Circle(2)]
areas = [s.area() for s in shapes] # same call, different maths
Different classes can answer the same method name (area
). You can loop over mixed objects without checking their types.
class Vector2D:
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(self, other): # enables v + w
return Vector2D(self.x + other.x, self.y + other.y)
def __len__(self): # enables len(v)
return 2
Writing special double‑underscore methods teaches Python's built‑in operators how to work with your objects, making them feel like native types.
Task | Method examples |
---|---|
Text | __str__ , __repr__ |
Math | __add__ , __sub__ , __mul__ , … |
Compare | __lt__ , __eq__ , __hash__ |
Sequence | __len__ , __getitem__ , __iter__ |
__init__
, that initializes a new object's state when it is created.__del__
, that is called when an object is about to be destroyed, used for cleanup.__init__
, __str__
) that enables built-in behaviors._data
).@classmethod
decorator, and takes the class as its first parameter.