Introduction to OOP
Object-Oriented Programming, or OOP, is a way of structuring code around objects — bundles that hold both data (attributes) and the behavior that operates on that data (methods). Instead of writing functions that reach into loose variables scattered around your program, you group related data and the logic that makes sense of it into a single unit. Python has supported this style since its very first release, and once you start writing anything beyond short scripts, OOP becomes the natural way to keep code organized.
Procedural code vs. object-oriented code
In purely procedural code, data and behavior live apart. You might have a dictionary representing a user and a handful of standalone functions that take that dictionary as an argument to do things with it. This works fine for small programs, but as a codebase grows, it becomes easy to lose track of which functions are allowed to touch which data, and duplicate, inconsistent logic tends to creep in.
# Procedural style: data and behavior are separate
user = {"name": "Aisha", "balance": 100}
def deposit(account, amount):
account["balance"] += amount
def withdraw(account, amount):
if amount > account["balance"]:
print("Insufficient funds")
else:
account["balance"] -= amount
deposit(user, 50)
withdraw(user, 30)
print(user["balance"])# Object-oriented style: data and behavior travel together
class Account:
def __init__(self, name, balance=0):
self.name = name
self.balance = balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
if amount > self.balance:
print("Insufficient funds")
else:
self.balance -= amount
user = Account("Aisha", 100)
user.deposit(50)
user.withdraw(30)
print(user.balance)Both snippets do the same thing, but in the second one, the balance and the operations that are allowed to change it are defined in one place: the Account class. There is no way to accidentally call a function meant for a different kind of data on a bank account, because the methods belong to the class itself. As programs grow to dozens of files and thousands of lines, this kind of grouping is what keeps everything manageable.
The four pillars of OOP
Object-oriented programming is usually described in terms of four core ideas. You will meet each one in far more depth on its own page later in this tutorial — for now, here is a quick map of the territory.
Pillar | One-line description |
|---|---|
Encapsulation | Bundling data and the methods that operate on it together, and controlling what outside code can access directly. |
Inheritance | Letting one class reuse and extend the attributes and behavior of another, avoiding repeated code. |
Polymorphism | Allowing different classes to be used through the same interface, so the same code can work with many types. |
Abstraction | Hiding complex implementation details behind a simple, well-defined interface. |
Classes vs. objects: the blueprint analogy
The two words you will see constantly in OOP are class and object, and it helps to have a concrete picture for the difference. A class is like an architect's blueprint for a house. The blueprint describes what every house built from it will have — how many bedrooms, where the doors go, what the wiring looks like — but the blueprint itself is not a house you can live in. It's a plan, defined once.
An object (also called an instance) is an actual house built from that blueprint. You can build many houses from the same blueprint, and while they all share the same structure, each one is a separate physical building — painting the front door of one house red does not repaint the others. In the same way, a Python class is defined once, but you can create as many independent objects from it as you like, and changing the state of one object never affects the others.
class House:
def __init__(self, color):
self.color = color
# Two separate houses built from the same blueprint
house1 = House("red")
house2 = House("blue")
house1.color = "green"
print(house1.color)
print(house2.color)class House— the blueprint, written once in your source code.house1andhouse2— two independent objects (instances) built from that blueprint.Changing
house1.colorhas no effect onhouse2.color, because each object keeps its own separate state.
Python already runs on objects
Here's the part that surprises a lot of newcomers: even if you never write a single class keyword, you are already using OOP every time you write Python. One of Python's core design philosophies is that everything is an object — every integer, every string, every list, every function, even every class itself. Each of these has a type, carries attributes, and exposes methods you can call, exactly like the custom objects you will soon build yourself.
x = 42
print(type(x))
print(x.bit_length())
s = "hello"
print(type(s))
print(s.upper())
def greet():
return "hi"
print(type(greet))
print(greet.__name__)bit_length(), upper(), and __name__ are all methods or attributes attached to objects — an int object, a string object, and a function object, respectively. This is why understanding OOP matters even if you think you only write "simple" Python: the moment you call .upper() on a string, you are already using the exact mechanism — an object responding to a method call — that you will soon be defining yourself with custom classes.
What's next
The next page dives into the mechanics: the class keyword itself, how to create instances, and how self lets each object keep track of its own data.