Introduction to Classes and Objects

Daniel Sarney
Python Intermediate

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 self parameter
  • 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:

  1. Circle Class: Create a Circle class with radius. Add methods to calculate area and circumference.

  2. Bank Account: Extend the bank account example with methods to transfer money between accounts and apply interest.

  3. Library System: Create Book and Library classes. The library should track books and allow borrowing/returning.

  4. Student Gradebook: Create a Student class that tracks multiple subjects and calculates overall average.

  5. Temperature Converter: Create a Temperature class 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.

Video Tutorial Coming Soon

The video tutorial for this lesson will be available soon. Check back later!

Continue Learning

12 lessons
Python For Beginners

Start your learning journey with Python For Beginners. This course includes comprehensive lessons covering everything you need to know.