1. OOP & Modules in Python
As your Python programs grow from small scripts into full applications, organizing code becomes your most important job. Object-Oriented Programming (OOP) allows you to model real-world concepts into reusable components, while Modules let you break giant script files into clean, manageable, multi-file projects.
Learning Objectives
- Understand the core principles of Object-Oriented Programming (OOP): Classes and Objects.
- Master the constructor
__init__()method and theselfparameter. - Define custom instance attributes and methods.
- Create, import, and organize custom Python modules using
importsyntax. - Protect executable code using the
if __name__ == "__main__":idiom.
2. Core OOP Concepts: Classes & Objects
At its heart, Object-Oriented Programming is built around two key concepts:
- Class: A blueprint or template for creating objects. It defines what data an object holds (attributes) and what actions it can perform (methods).
- Object (Instance): An individual, concrete instance created from a class blueprint.
Think of a Class like an architectural blueprint for a house. The blueprint itself isn't a physical house, but it defines the structure (number of rooms, doors, color). An Object is the actual physical house built using that blueprint. You can build 50 different houses (objects) from a single blueprint (class)!
3. Anatomy of a Class: __init__ and self
In Python, classes are created using the class keyword. Inside a class, we use a special built-in method named __init__() (the constructor) to initialize an object's starting data when it is created.
The self parameter represents the specific object instance currently being acted upon. Python passes self automatically under the hood whenever you call an instance method.
Python code example:
class Dog:
# Constructor method runs automatically when creating a new object
def __init__(self, name, breed, age):
# Instance attributes
self.name = name
self.breed = breed
self.age = age
# Instance method (action the object can take)
def bark(self):
return f"{self.name} says Woof!"
# Creating instances (objects) of the Dog class
dog1 = Dog("Buddy", "Golden Retriever", 3)
dog2 = Dog("Luna", "Husky", 2)
# Accessing attributes and calling methods
print(f"{dog1.name} is a {dog1.breed}.") # Output: Buddy is a Golden Retriever.
print(dog2.bark()) # Output: Luna says Woof!
4. Working with Python Modules
A Module in Python is simply a single file containing Python code (with a .py extension)—such as functions, classes, and variables. Modules allow you to divide large projects into separate files to keep your codebase clean and scalable.
You can import built-in Python modules (like math, random, or datetime) or create your own custom modules!
Module Import Techniques
| Syntax Pattern | Example | How to Call Functions | Best Practice Recommendation |
|---|---|---|---|
| Full Import | import math |
math.sqrt(16) |
Best for readability; avoids naming conflicts. |
| Specific Import | from math import sqrt |
sqrt(16) |
Great when you only need 1 or 2 specific items. |
| Aliased Import | import random as rnd |
rnd.randint(1, 10) |
Ideal for long module names or common aliases (e.g., pd for pandas). |
5. Creating & Guarding Custom Modules
Suppose you create a file named bank_utils.py containing helper functions and classes. To prevent code inside bank_utils.py from running automatically when imported by another script, wrap test code inside if __name__ == "__main__":.
File 1: bank_utils.py (Custom Module)
class BankAccount:
def __init__(self, owner, balance=0.0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount > 0:
self.balance += amount
return True
return False
# Execution Guard: Runs ONLY when this file is executed directly!
if __name__ == "__main__":
test_acc = BankAccount("Test User", 100)
print("Testing module locally: Account created successfully!")
File 2: main.py (Main Application)
# Importing custom class from our custom module
from bank_utils import BankAccount
account = BankAccount("Alice", 500.0)
account.deposit(250.0)
print(f"{account.owner}'s Balance: ${account.balance:.2f}") # Output: Alice's Balance: $750.00
6. Real World Example: E-Commerce Shopping Cart
Combining classes and objects allows you to easily model complex business logic like shopping carts, products, and checkout operations:
class Product:
def __init__(self, product_id, name, price):
self.product_id = product_id
self.name = name
self.price = price
class ShoppingCart:
def __init__(self, customer_name):
self.customer_name = customer_name
self.items = [] # List holding Product instances
def add_product(self, product):
self.items.append(product)
print(f"Added {product.name} to {self.customer_name}'s cart.")
def calculate_total(self):
return sum(product.price for product in self.items)
# Usage Example
p1 = Product(101, "Wireless Mouse", 29.99)
p2 = Product(102, "Mechanical Keyboard", 89.99)
cart = ShoppingCart("Sarah")
cart.add_product(p1)
cart.add_product(p2)
print(f"Cart Total: ${cart.calculate_total():.2f}") # Output: Cart Total: $119.98
7. Common Beginner Mistakes
⚠️ Watch out for these mistakes:
- Forgetting
selfas the First Parameter: Defining instance methods asdef bark():instead ofdef bark(self):causes aTypeError: bark() takes 0 positional arguments but 1 was givenwhen called. - Forgetting
self.When Assigning Attributes: Writingname = nameinside__init__creates a temporary local variable rather than storing an attribute on the object! Always useself.name = name. - Confusing Class Attributes vs. Instance Attributes: Defining variables directly under the
classblock creates a single variable shared across ALL instances, whereas instance attributes set inside__init__belong uniquely to each instance. - Circular Imports: Importing
moduleAinsidemoduleBwhile simultaneously importingmoduleBinsidemoduleAwill cause anImportError. Keep your module hierarchy linear.
8. Code Examples
Here are standard, production-ready OOP and module patterns in Python:
# 1. Standard Class Definition with Default Values
class User:
def __init__(self, username, email, is_admin=False):
self.username = username
self.email = email
self.is_admin = is_admin
def promote(self):
self.is_admin = True
print(f"User {self.username} was promoted to Admin.")
user1 = User("johndoe", "john@example.com")
user1.promote()
# 2. Importing Built-in Modules with Aliases
import random as rnd
dice_roll = rnd.randint(1, 6)
print(f"You rolled a {dice_roll}!")
Mini Practice: Book Class Builder
Create a class named Book with an __init__() method that accepts title, author, and pages. Add a method named get_summary() that returns a formatted string like: "’Title’ by Author (Pages pages)".
Practice complete!
Awesome job! You've mastered defining classes, initializers, and instance methods in Python.
Test Your Understanding
1. What role does the `self` parameter play in Python class methods?
2. Which special method is automatically invoked when creating a new instance of a class?
3. Why do developers use `if __name__ == "__main__":` inside custom module files?
4. What is a Python Module?
9. Challenge Project
Modular Library Inventory System: Create two Python files in the same directory:
library_item.py: Defines aLibraryItemclass with attributestitle,item_id, andis_checked_out(defaultFalse). Include methodscheck_out()andreturn_item().main.py: Import theLibraryItemclass, create three item instances (e.g. books/DVDs), simulate checking out two items, and print an updated inventory status summary!
10. Key Takeaways
- A Class serves as a blueprint; an Object is a unique instance built from that blueprint.
- Use the
__init__()method to set up initial object attributes. - The
selfkeyword gives instance methods access to the object's own attributes and methods. - Any Python file ending in
.pycan act as an importable Module. - Guard module test code with
if __name__ == "__main__":to prevent accidental code execution upon import.
🚀 Progression
You've mastered Object-Oriented Programming and Modules! Next up, we will learn how to make our applications crash-proof with **Exception Handling in Python**!