OOP (Object-Oriented Programming) is a way of organizing code around “things” instead of loose variables and functions. A class is the blueprint, and an object is something built from it. Think abot it like a cookie cutter and cookies.
Here’s the smallest class you need to understand before the four ideas:
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(f"{self.name} says Woof!")
rex = Dog("Rex")
rex.bark() # Rex says Woof!
-
__init__runs automatically when you create a dog. It sets up the starting data. -
selfmeans “this particular dog.” That’s why it prints Rex’s name.
Now the four big ideas.
1. Encapsulation: keep data and actions together, and protect it
Put the data and the actions that use it in one place, and control how people change it.
A bank account is a good example. Nobody should be able to set their balance to a million. They have to go through deposit(), which has a rule built in.
class BankAccount:
def __init__(self, balance):
self._balance = balance
def deposit(self, amount):
if amount > 0:
self._balance += amount
def get_balance(self):
return self._balance
acc = BankAccount(1000)
acc.deposit(500)
print(acc.get_balance()) # The print statement prints 1500
The single underscore in _balance is a Python habit that means “internal, please use the methods instead of touching this directly.” It’s a signal to other programmers, not a lock, but it’s how most Python code does it.
2. Inheritance: reuse code instead of repeating it
A new class can borrow everything from an existing one and add only what’s different.
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} is eating")
class Dog(Animal):
def bark(self):
print(f"{self.name} says Woof!")
rex = Dog("Rex")
rex.eat() # Rex is eating (came from Animal)
rex.bark() # Rex says Woof! (Dog's own)
Dog(Animal) means “a Dog is an Animal.” It never wrote eat() or name, but it gets both for free.
3. Polymorphism: same method name, different behavior
Different classes can have the same method name, and each one does its own thing. This builds directly on inheritance.
class Animal:
def speak(self):
print("Some sound")
class Dog(Animal):
def speak(self):
print("Woof!")
class Cat(Animal):
def speak(self):
print("Meow!")
for animal in [Dog(), Cat()]:
animal.speak()
#Output for this code will be:
#woof!
#Meow!
The loop doesn’t care what kind of animal it has. It just calls speak(), and each animal responds in its own way.
4. Abstraction: hide the messy details
Show people a simple way to use something, and keep the complicated parts out of sight. When you start a car, you turn the key. You don’t think about fuel pumps and spark plugs.
class Car:
def start(self):
self._check_fuel()
self._ignite_engine()
print("Vroom! Car started")
def _check_fuel(self):
pass # messy details live here
def _ignite_engine(self):
pass # and here
my_car = Car()
my_car.start() # Vroom! Car started
Whoever uses Car only needs to know about start(). How it works inside can change later and nobody outside has to care.
Quick recap
| Idea | In one line |
|---|---|
| Encapsulation | Keep data and actions together, control access |
| Inheritance | Reuse code from a parent class |
| Polymorphism | Same method name, different behavior |
| Abstraction | Hide the details, show a simple way to use it |
Final thought
After learning and using OOP I can confirm that a developer does not need to memorize these. Remember that OOP is about keeping related data and actions together, and these four ideas are tools for doing it well. While starting build a class or two, and the rest will make sense as you go.
In future blogs I will talk about Abstract classes (ABC) and name mangling in OOP.
Top comments (0)