Classes & OOP Basics
Understand objects, why Python is “object-oriented”, and how classes help you model the real world.
Introduction
Python is an object-oriented language. Everything in Python is an object: numbers, strings, lists and also your own custom objects. Object-oriented programming (OOP) lets you create classes that model elements that relates to your business, current use cases and logical concepts, and lets you organize behavior and data together.
What is Object-Oriented Programming (OOP)?
Object-oriented programming (OOP) is a way of structuring code to model real-world “things”, especially things related to your business or current problem, using objects. Each object contains both data (attributes) and behavior (methods). OOP helps you organize complex programs, allows code reuse, and makes your code easier to reason about.
The Four Pillars of OOP
- Encapsulation – Bundles data and methods that operate on that data within objects, hiding internal implementation details. This keeps data safe and makes objects easier to use.
- Abstraction – Hides complex reality by exposing only the necessary parts of objects through simple interfaces, letting you work with ideas at a higher level.
- Inheritance – Lets you create new classes based on existing ones, forming hierarchies where subclasses inherit (and customize) behaviors and attributes from parent classes.
- Polymorphism – Allows different classes to be used interchangeably if they implement the same interface or methods, enabling flexible code that works with many types of objects.
Why the "Four Pillars" Matter
- They help you structure code around real-world objects, not just logic or data.
- Your code becomes more modular (split into components), reusable (extend existing code), and maintainable (easier to update and fix).
- The four principles make it clear how to organize complex programs by modeling both the data and the behaviors that matter in your application.
- OOP isn't just for big projects, it helps even small scripts become cleaner and more robust!
Encapsulation, Inheritance, and Polymorphism are not what define object-oriented programming (OOP) itself. Rather, they are features provided by many programming languages to help you implement OO principles in real code.
The core of OOP is modeling your program around objects, entities that combine data (attributes) and behavior (methods) relevant to your domain. And the way objects interact via messages (method calls), where:
- The sender of the message (the code calling a method) neither knows nor cares how the receiver (the object) reacts.
- Different objects can implement how they respond to the same message (method name) in their own way, this is polymorphism.
"The purpose of object-oriented programming is not to make code easy to write, but to make it easy to change."
Uncle Bob, a legendary software engineer, stresses that OOP isn't mainly about syntax or convenience, it's about structuring code so it stays flexible, adaptable, and easy to improve as requirements evolve.
What is a Class? What is an Object?
A class is a blueprint for creating objects (instances). An object represents a specific thing with its own data and behavior.
# Define a simple class
class Dog:
pass # Empty class, does nothing (for now)
my_dog = Dog() # Create an instance (object)
print(type(my_dog)) # <class '__main__.Dog'>Instance Attributes & Initializer (__init__)
Use the __init__ method to set up object data when it’s created. This method runs automatically when you call ClassName().
class Dog:
def __init__(self, name, age):
self.name = name # instance attribute
self.age = age # instance attribute
fido = Dog("Fido", 3)
print(fido.name) # "Fido"
print(fido.age) # 3
self always refers to the current instance.Methods (Behavior)
Methods are functions defined inside a class, they describe what objects of that class can do.
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(f"{self.name} says woof!")
fido = Dog("Fido")
fido.bark() # Fido says woof!
self as the first parameter of methods.More Examples: Custom Objects
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
import math
return math.pi * self.radius ** 2
c = Circle(5)
print("Area:", c.area())
Class Methods and Static Methods
Python classes can have class methods and static methods in addition to regular instance methods.
- Instance methods (just
selfas first arg) work on individual objects. - Class methods (with
@classmethod, first argcls) work with the class itself. - Static methods (with
@staticmethod) are related utilities, they don’t implicitly getselforcls.
class Cat:
species = "Felis catus" # class attribute
def __init__(self, name):
self.name = name
@classmethod
def common_species(cls):
return f"Common species is {cls.species}"
@staticmethod
def speak():
return "Meow!"
whiskers = Cat("Whiskers")
print(whiskers.common_species()) # Common species is Felis catus
print(Cat.speak()) # Meow!
Class methods are great for factory methods or acting on class-level data; static methods are for related helper functions.
Abstract Classes: Enforcing Structure
An abstract class is a blueprint that cannot be instantiated directly. It defines a contract that subclasses must follow by implementing specific methods. This ensures all subclasses provide certain behaviors.
They help you enforce consistency across related classes. If you have multiple classes that should all implement the same methods (like
save(), load(), or calculate()), an abstract base class ensures nobody forgets to implement them.Python provides the abc module (Abstract Base Classes) to create abstract classes. Use @abstractmethod decorator to mark methods that must be implemented by subclasses.
from abc import ABC, abstractmethod
class Animal(ABC): # Inherit from ABC to make it abstract
@abstractmethod
def make_sound(self):
"""Every animal must implement this method"""
pass
@abstractmethod
def move(self):
"""Every animal must implement how it moves"""
pass
def breathe(self):
"""Concrete method - all animals breathe the same way"""
print("Breathing...")
# This will raise an error - can't instantiate abstract class
# animal = Animal() # TypeError: Can't instantiate abstract class
class Dog(Animal):
def make_sound(self):
return "Woof!"
def move(self):
return "Running on four legs"
class Bird(Animal):
def make_sound(self):
return "Chirp!"
def move(self):
return "Flying in the sky"
# Now we can create instances
dog = Dog()
bird = Bird()
print(dog.make_sound()) # Woof!
print(bird.move()) # Flying in the sky
dog.breathe() # Breathing...Real-World Example: Payment Processing
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
"""Abstract base class for payment processors"""
@abstractmethod
def process_payment(self, amount):
"""Process a payment of given amount"""
pass
@abstractmethod
def refund(self, transaction_id, amount):
"""Refund a transaction"""
pass
def log_transaction(self, message):
"""Concrete method shared by all processors"""
print(f"[LOG] {message}")
class StripeProcessor(PaymentProcessor):
def process_payment(self, amount):
self.log_transaction(f"Processing {amount} via Stripe")
# Stripe-specific implementation
return {"status": "success", "provider": "stripe"}
def refund(self, transaction_id, amount):
self.log_transaction(f"Refunding {amount} for {transaction_id}")
return {"status": "refunded"}
class PayPalProcessor(PaymentProcessor):
def process_payment(self, amount):
self.log_transaction(f"Processing {amount} via PayPal")
# PayPal-specific implementation
return {"status": "success", "provider": "paypal"}
def refund(self, transaction_id, amount):
self.log_transaction(f"Refunding {amount} for {transaction_id}")
return {"status": "refunded"}
# Using polymorphism with abstract classes
def checkout(processor: PaymentProcessor, amount):
result = processor.process_payment(amount)
print(f"Payment result: {result}")
stripe = StripeProcessor()
paypal = PayPalProcessor()
checkout(stripe, 99.99) # Works with any PaymentProcessor
checkout(paypal, 49.99)@abstractmethod you see here is called a decorator. Decorators are a powerful Python feature that modify or enhance functions and methods. We'll explore decorators in detail in a later lesson, but for now, just know that @abstractmethod tells Python "this method must be implemented by subclasses."Key Takeaways
- Class: a blueprint for objects
- Instance: a specific object created from a class
__init__: initialization method for setting up data- self: refers to the present object (instance)
- Attributes hold data; methods define behavior
- @classmethod and @staticmethod provide alternative method types
- Abstract classes enforce that subclasses implement specific methods
- Use
abc.ABCand@abstractmethodto create contracts for subclasses
What's Next?
Now that you understand the basics of classes and objects, you're ready to dive deeper into the four pillars of object-oriented programming.
- Encapsulation - Learn how to protect your data and control access using private attributes and properties
- Inheritance - Discover how to build class hierarchies and reuse code through parent-child relationships
- Polymorphism - Master the art of writing flexible code that works with different object types seamlessly