So far, you've been writing procedural code—functions that operate on data. Object-oriented programming (OOP) introduces a different way of thinking: bundling data and functions together into objects. This paradigm helps you model real-world entities and organize code more effectively.
In this lesson, you'll learn the fundamentals of OOP: what classes and objects are, how to define classes, create objects, and work with instance variables and methods. Understanding OOP is crucial for working with Python libraries and frameworks, and it's a fundamental programming paradigm used across many languages.
What You'll Learn
- Understanding OOP concepts
- Defining classes and creating objects
- Instance variables and methods
- The
selfparameter - Constructor methods (init)
- Modeling real-world entities
What are Classes and Objects?
A class is a blueprint for creating objects. An object is an instance of a class—a concrete realization of that blueprint. Think of a class as a cookie cutter and objects as the cookies:
# Class definition (the blueprint)
class Dog:
pass
# Creating objects (instances)
my_dog = Dog()
your_dog = Dog()
print(type(my_dog)) # <class '__main__.Dog'>
print(my_dog) # <__main__.Dog object at 0x...>
Each object is independent—changing one doesn't affect others.
Defining Your First Class
Let's create a simple class to represent a bank account:
class BankAccount:
"""A simple bank account class."""
def __init__(self, owner, balance=0):
"""Initialize account with owner and balance."""
self.owner = owner
self.balance = balance
def deposit(self, amount):
"""Add money to the account."""
self.balance += amount
print(f"Deposited ${amount}. New balance: ${self.balance}")
def withdraw(self, amount):
"""Remove money from the account."""
if amount <= self.balance:
self.balance -= amount
print(f"Withdrew ${amount}. New balance: ${self.balance}")
else:
print("Insufficient funds!")
def get_balance(self):
"""Return the current balance."""
return self.balance
# Creating objects
account1 = BankAccount("Alice", 1000)
account2 = BankAccount("Bob", 500)
# Using the objects
account1.deposit(200) # Deposited $200. New balance: $1200
account1.withdraw(100) # Withdrew $100. New balance: $1100
account2.deposit(300) # Deposited $300. New balance: $800
Understanding init and self
The __init__ method is called automatically when you create an object. It's the constructor that initializes the object:
class Person:
def __init__(self, name, age):
"""Initialize person with name and age."""
self.name = name
self.age = age
print(f"Created person: {name}")
# When you create an object, __init__ is called automatically
person = Person("Alice", 25) # Created person: Alice
The self parameter refers to the instance being created. It's automatically passed when you call methods:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
"""Calculate area using self to access instance variables."""
return self.width * self.height
def perimeter(self):
"""Calculate perimeter."""
return 2 * (self.width + self.height)
rect = Rectangle(5, 3)
print(rect.area()) # 15
print(rect.perimeter()) # 16
Instance Variables
Instance variables store data unique to each object:
class Student:
def __init__(self, name, student_id):
self.name = name
self.student_id = student_id
self.grades = [] # Each student has their own grades list
def add_grade(self, grade):
"""Add a grade to the student's record."""
self.grades.append(grade)
def get_average(self):
"""Calculate average grade."""
if len(self.grades) == 0:
return 0
return sum(self.grades) / len(self.grades)
# Each student has independent data
alice = Student("Alice", "S001")
bob = Student("Bob", "S002")
alice.add_grade(85)
alice.add_grade(90)
bob.add_grade(78)
print(f"{alice.name}'s average: {alice.get_average()}") # 87.5
print(f"{bob.name}'s average: {bob.get_average()}") # 78.0
Instance Methods
Methods are functions defined inside a class. They always take self as the first parameter:
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.mileage = 0
self.is_running = False
def start(self):
"""Start the car."""
if not self.is_running:
self.is_running = True
print(f"{self.make} {self.model} started!")
else:
print("Car is already running!")
def stop(self):
"""Stop the car."""
if self.is_running:
self.is_running = False
print(f"{self.make} {self.model} stopped.")
else:
print("Car is already stopped!")
def drive(self, miles):
"""Drive the car a certain distance."""
if self.is_running:
self.mileage += miles
print(f"Drove {miles} miles. Total mileage: {self.mileage}")
else:
print("Start the car first!")
# Using the Car class
my_car = Car("Toyota", "Camry", 2020)
my_car.start() # Toyota Camry started!
my_car.drive(50) # Drove 50 miles. Total mileage: 50
my_car.drive(30) # Drove 30 miles. Total mileage: 80
my_car.stop() # Toyota Camry stopped.
Practical Examples
Here are more real-world class examples:
# Example 1: Book class
class Book:
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.is_borrowed = False
def borrow(self):
"""Mark book as borrowed."""
if self.is_borrowed:
print(f"{self.title} is already borrowed!")
else:
self.is_borrowed = True
print(f"{self.title} has been borrowed.")
def return_book(self):
"""Mark book as returned."""
if self.is_borrowed:
self.is_borrowed = False
print(f"{self.title} has been returned.")
else:
print(f"{self.title} is not currently borrowed.")
book1 = Book("Python Basics", "John Doe", "123-456")
book1.borrow() # Python Basics has been borrowed.
book1.return_book() # Python Basics has been returned.
# Example 2: Shopping cart
class ShoppingCart:
def __init__(self):
self.items = {}
def add_item(self, item, quantity=1):
"""Add item to cart."""
if item in self.items:
self.items[item] += quantity
else:
self.items[item] = quantity
print(f"Added {quantity} {item}(s) to cart.")
def remove_item(self, item, quantity=1):
"""Remove item from cart."""
if item in self.items:
self.items[item] -= quantity
if self.items[item] <= 0:
del self.items[item]
print(f"Removed {quantity} {item}(s) from cart.")
else:
print(f"{item} not in cart.")
def get_total_items(self):
"""Get total number of items."""
return sum(self.items.values())
def view_cart(self):
"""Display cart contents."""
if not self.items:
print("Cart is empty!")
else:
for item, quantity in self.items.items():
print(f"{item}: {quantity}")
cart = ShoppingCart()
cart.add_item("apple", 3)
cart.add_item("banana", 2)
cart.view_cart() # apple: 3, banana: 2
print(f"Total items: {cart.get_total_items()}") # 5
Try It Yourself
Practice creating classes:
-
Circle Class: Create a
Circleclass with radius. Add methods to calculate area and circumference. -
Bank Account: Extend the bank account example with methods to transfer money between accounts and apply interest.
-
Library System: Create
BookandLibraryclasses. The library should track books and allow borrowing/returning. -
Student Gradebook: Create a
Studentclass that tracks multiple subjects and calculates overall average. -
Temperature Converter: Create a
Temperatureclass that stores temperature and can convert between Celsius and Fahrenheit.
Summary
You've learned the fundamentals of object-oriented programming in Python. Classes are blueprints for creating objects, and objects are instances with their own data (instance variables) and behavior (methods). The __init__ method initializes objects, and self refers to the instance.
OOP helps you model real-world entities and organize code more effectively. As you continue learning, you'll discover more powerful OOP features like inheritance and polymorphism that make code even more reusable and maintainable.
What's Next?
In the next lesson, we'll explore class attributes and different types of methods. You'll learn about class variables, class methods, and static methods. These concepts will help you understand when to use shared data versus instance-specific data.