Python Object-Oriented Programming

Master Python OOP including classes, objects, inheritance, and polymorphism with detailed examples and exercises.

OOP: Classes & Objects

Learn the fundamentals of Object-Oriented Programming in Python

What is Object-Oriented Programming?

Object-Oriented Programming (OOP) is a programming paradigm that uses "objects" to design applications and computer programs. It utilizes several techniques including encapsulation, polymorphism, and inheritance.

Classes and Objects

A class is a blueprint for creating objects. An object is an instance of a class.

# Defining a class
class Dog:
    # Class attribute
    species = "Canis familiaris"
    
    # Initializer / Instance attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    # Instance method
    def description(self):
        return f"{self.name} is {self.age} years old"
    
    # Another instance method
    def speak(self, sound):
        return f"{self.name} says {sound}"

# Creating objects (instances of the Dog class)
dog1 = Dog("Buddy", 5)
dog2 = Dog("Milo", 3)

# Accessing attributes and methods
print(dog1.name)           # Buddy
print(dog2.age)            # 3
print(dog1.description())  # Buddy is 5 years old
print(dog2.speak("Woof"))  # Milo says Woof

The __init__ Method

The __init__ method is a special method that is automatically called when a new object is created. It's used to initialize the object's attributes.

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0  # Default value
    
    def get_descriptive_name(self):
        return f"{self.year} {self.make} {self.model}"
    
    def read_odometer(self):
        return f"This car has {self.odometer_reading} miles on it"

# Create a car object
my_car = Car("Toyota", "Camry", 2020)
print(my_car.get_descriptive_name())  # 2020 Toyota Camry
print(my_car.read_odometer())         # This car has 0 miles on it

Upgrade Your Learning Experience!

Get access to premium content, exercises, and projects with OjoTech Pro

Learn More

Modifying Attributes

You can modify an attribute's value directly or through a method:

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
    
    def update_odometer(self, mileage):
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")
    
    def increment_odometer(self, miles):
        self.odometer_reading += miles

my_car = Car("Toyota", "Camry", 2020)

# Modify attribute directly
my_car.odometer_reading = 23
print(my_car.odometer_reading)  # 23

# Modify through a method
my_car.update_odometer(50)
print(my_car.odometer_reading)  # 50

my_car.increment_odometer(100)
print(my_car.odometer_reading)  # 150

Inheritance

Inheritance allows you to define a class that inherits all the methods and properties from another class.

# Parent class
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        raise NotImplementedError("Subclass must implement this method")

# Child class
class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

# Child class
class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

# Create objects
dog = Dog("Buddy")
cat = Cat("Whiskers")

print(dog.speak())  # Buddy says Woof!
print(cat.speak())  # Whiskers says Meow!

Practice Exercise

Create a BankAccount class that:

  1. Has attributes for account number, owner name, and balance
  2. Has methods to deposit, withdraw, and display balance
  3. Prevents withdrawals if insufficient funds
  4. Create a SavingsAccount class that inherits from BankAccount and adds interest calculation

Polymorphism

Polymorphism allows methods to do different things based on the object it is acting upon.

class Bird:
    def fly(self):
        return "Most birds can fly"

class Penguin(Bird):
    def fly(self):
        return "Penguins can't fly"

class Sparrow(Bird):
    def fly(self):
        return "Sparrows can fly very fast"

# Function that uses polymorphism
def bird_flying_test(bird):
    print(bird.fly())

# Create objects
generic_bird = Bird()
penguin = Penguin()
sparrow = Sparrow()

# Test polymorphism
bird_flying_test(generic_bird)  # Most birds can fly
bird_flying_test(penguin)       # Penguins can't fly
bird_flying_test(sparrow)       # Sparrows can fly very fast

Take Your Python Skills to the Next Level

OjoTech Pro offers advanced courses, real-world projects, and mentorship to help you become a Python expert

Advanced Projects

Build portfolio-worthy applications with guided projects

Expert Mentorship

Get personalized feedback and guidance from industry experts

Certification

Earn a certificate to showcase your Python programming skills

Join OjoTech Pro Today

Encapsulation

Encapsulation is the bundling of data with the methods that operate on that data. In Python, we use naming conventions to indicate protected and private attributes.

class BankAccount:
    def __init__(self, account_number, owner_name, balance=0):
        self.account_number = account_number  # Public attribute
        self.owner_name = owner_name          # Public attribute
        self._balance = balance               # Protected attribute (convention)
    
    # Public method to access protected attribute
    def get_balance(self):
        return self._balance
    
    # Public method to modify protected attribute with validation
    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
            return True
        return False
    
    def withdraw(self, amount):
        if 0 < amount <= self._balance:
            self._balance -= amount
            return True
        return False

account = BankAccount("123456", "John Doe", 1000)
print(account.get_balance())  # 1000
account.deposit(500)
print(account.get_balance())  # 1500
account.withdraw(200)
print(account.get_balance())  # 1300

Special Methods

Python has special methods that begin and end with double underscores. They are also known as "magic methods".

class Book:
    def __init__(self, title, author, pages):
        self.title = title
        self.author = author
        self.pages = pages
    
    # String representation of the object
    def __str__(self):
        return f"'{self.title}' by {self.author}"
    
    # Length of the object
    def __len__(self):
        return self.pages
    
    # What happens when object is deleted
    def __del__(self):
        print(f"A book object '{self.title}' has been deleted")

# Create a book object
book = Book("Python Basics", "John Smith", 200)

print(str(book))   # 'Python Basics' by John Smith
print(len(book))   # 200
del book           # A book object 'Python Basics' has been deleted

Class Methods and Static Methods

Class methods work with the class rather than instances. Static methods are utility functions that don't work with class or instance data.

class MyClass:
    class_attribute = "I'm a class attribute"
    
    def __init__(self, value):
        self.instance_attribute = value
    
    # Instance method
    def instance_method(self):
        return f"Instance method called with {self.instance_attribute}"
    
    # Class method
    @classmethod
    def class_method(cls):
        return f"Class method called with {cls.class_attribute}"
    
    # Static method
    @staticmethod
    def static_method():
        return "Static method called"

# Using instance method
obj = MyClass("test")
print(obj.instance_method())  # Instance method called with test

# Using class method
print(MyClass.class_method())  # Class method called with I'm a class attribute

# Using static method
print(MyClass.static_method())  # Static method called

OOP Principles Summary

Principle Description Python Example
Encapsulation Bundling data and methods that work on that data within one unit Using classes with attributes and methods
Inheritance Creating a new class from an existing class class ChildClass(ParentClass):
Polymorphism Using a single type entity to represent different types in different scenarios Method overriding in child classes
Abstraction Hiding the implementation details and showing only functionality Using abstract base classes (ABC module)