← View series: python tutorials
~/blog
Introduction to Object-Oriented Programming
Introduction
In this tutorial, you'll learn about Object-Oriented Programming (OOP) - a powerful paradigm for structuring your code. OOP organizes code into "objects" that contain both data (attributes) and behavior (methods). This makes your code more modular, reusable, and easier to maintain.
What You'll Learn
- What is OOP and why use it
- Classes and objects
- Creating classes and instantiating objects
- The init method (constructor)
- Instance attributes and methods
- Class attributes
- The self parameter
What is OOP?
Object-Oriented Programming is a way of writing code that models real-world things as "objects". Each object has:
- Attributes (data) - What the object is or has
- Methods (behavior) - What the object does
OOP vs Procedural
| Procedural | Object-Oriented |
|---|---|
| Data and functions separate | Data and functions together |
| Top-down approach | Bottom-up approach |
| Harder to maintain | Easier to maintain |
| Harder to reuse | Code is more reusable |
Real-World Examples
| Object | Attributes | Methods |
|---|---|---|
| Person | name, age, height | walk(), speak(), eat() |
| Bank Account | balance, account_number | deposit(), withdraw() |
| Car | color, make, speed | accelerate(), brake() |
Creating Classes
A class is a blueprint for creating objects:
# Define a class (capitalize the name)
class Person:
"""A class to represent a person"""
# Class attribute (shared by all instances)
species = "Human"
# The __init__ method (constructor)
def __init__(self, name, age):
# Instance attributes (unique to each instance)
self.name = name
self.age = age
# Instance method
def greet(self):
return f"Hello, my name is {self.name}!"
def birthday(self):
self.age += 1
return f"Happy birthday! I am now {self.age}."Creating Objects (Instances)
# Create instances of the Person class
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
# Access attributes
print(person1.name) # Alice
print(person2.age) # 30
# Access class attribute
print(person1.species) # Human
print(person2.species) # Human
# Call methods
print(person1.greet()) # Hello, my name is Alice!
print(person2.birthday()) # Happy birthday! I am now 31.The init Method
The __init__ method is called automatically when you create an object. It's used to initialize the object's attributes:
class Dog:
def __init__(self, name, breed):
self.name = name # Initialize name
self.breed = breed # Initialize breed
self.energy = 100 # Default value
def bark(self):
return f"{self.name} says Woof!"
def play(self):
self.energy -= 20
return f"{self.name} is playing! Energy: {self.energy}"
# Create a Dog object
my_dog = Dog("Buddy", "Golden Retriever")
print(my_dog.name) # Buddy
print(my_dog.bark()) # Buddy says Woof!
print(my_dog.play()) # Buddy is playing! Energy: 80The self Parameter
self refers to the current instance of the class. It allows you to access the object's attributes and methods:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
def describe(self):
return f"Rectangle: {self.width}x{self.height}"
rect = Rectangle(5, 3)
print(rect.area()) # 15
print(rect.perimeter()) # 16
print(rect.describe()) # Rectangle: 5x3Class vs Instance Attributes
Instance Attributes
Unique to each object:
class Car:
def __init__(self, make, model):
self.make = make # Instance attribute
self.model = model # Instance attribute
car1 = Car("Toyota", "Camry")
car2 = Car("Honda", "Civic")
car1.color = "Red" # Only affects car1
print(car1.color) # Red
print(car2.color) # Error! car2 has no colorClass Attributes
Shared by all instances:
class Car:
wheels = 4 # Class attribute - same for all cars
def __init__(self, make, model):
self.make = make
self.model = model
car1 = Car("Toyota", "Camry")
car2 = Car("Honda", "Civic")
print(car1.wheels) # 4
print(car2.wheels) # 4
print(Car.wheels) # 4Practical Examples
Example 1: Bank Account
class BankAccount:
def __init__(self, account_number, initial_balance=0):
self.account_number = account_number
self.balance = initial_balance
def deposit(self, amount):
if amount > 0:
self.balance += amount
return f"Deposited ${amount}. New balance: ${self.balance}"
return "Invalid amount"
def withdraw(self, amount):
if amount > self.balance:
return "Insufficient funds!"
self.balance -= amount
return f"Withdrew ${amount}. New balance: ${self.balance}"
def get_balance(self):
return f"Account {self.account_number}: ${self.balance}"
# Create account
account = BankAccount("123456789", 1000)
# Perform operations
print(account.get_balance()) # Account 123456789: $1000
print(account.deposit(500)) # Deposited $500. New balance: $1500
print(account.withdraw(200)) # Withdrew $200. New balance: $1300
print(account.withdraw(2000)) # Insufficient funds!Example 2: Student Class
class Student:
def __init__(self, name, student_id):
self.name = name
self.student_id = student_id
self.grades = []
def add_grade(self, grade):
if 0 <= grade <= 100:
self.grades.append(grade)
return f"Added grade: {grade}"
return "Invalid grade (must be 0-100)"
def get_average(self):
if not self.grades:
return 0
return sum(self.grades) / len(self.grades)
def get_letter_grade(self):
avg = self.get_average()
if avg >= 90: return "A"
elif avg >= 80: return "B"
elif avg >= 70: return "C"
elif avg >= 60: return "D"
else: return "F"
def display_info(self):
print(f"Student: {self.name} (ID: {self.student_id})")
print(f"Grades: {self.grades}")
print(f"Average: {self.get_average():.2f}")
print(f"Letter Grade: {self.get_letter_grade()}")
# Create student
student = Student("Alice", "S12345")
student.add_grade(85)
student.add_grade(90)
student.add_grade(78)
student.display_info()Output:
Student: Alice (ID: S12345)
Grades: [85, 90, 78]
Average: 84.33
Letter Grade: B
Modifying Attributes
You can modify attributes directly or through methods:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# Setter method
def set_age(self, age):
if age > 0:
self.age = age
else:
print("Age must be positive!")
person = Person("Alice", 25)
person.age = 30 # Direct modification
person.set_age(26) # Through methodSummary
In this tutorial, you learned:
- ✅ What Object-Oriented Programming is
- ✅ How to create classes
- ✅ The init constructor method
- ✅ Instance attributes and methods
- ✅ Class attributes
- ✅ The self parameter
🧑💻 Practice Exercise
Create a Book class that:
- Has attributes: title, author, year, pages
- Has a method
get_info()that returns a formatted string - Has a method
is_long()that returns True if pages > 300 - Has a class attribute
cover_type(default: "Hardcover") - Create 2 book instances and test all methods
Click to see solution
class Book:
# Class attribute
cover_type = "Hardcover"
def __init__(self, title, author, year, pages):
self.title = title
self.author = author
self.year = year
self.pages = pages
def get_info(self):
return f'"{self.title}" by {self.author} ({self.year})'
def is_long(self):
return self.pages > 300
def __str__(self):
return self.get_info()
# Create book instances
book1 = Book("1984", "George Orwell", 1949, 328)
book2 = Book("The Great Gatsby", "F. Scott Fitzgerald", 1925, 180)
# Test methods
print("=== Book 1 ===")
print(book1.get_info())
print(f"Pages: {book1.pages}")
print(f"Is long: {book1.is_long()}")
print(f"Cover: {book1.cover_type}")
print("\n=== Book 2 ===")
print(book2.get_info())
print(f"Pages: {book2.pages}")
print(f"Is long: {book2.is_long()}")
print(f"Cover: {book2.cover_type}")
print("\n=== Using __str__ ===")
print(book1)
print(book2)Output:
=== Book 1 ===
"1984" by George Orwell (1949)
Pages: 328
Is long: True
Cover: Hardcover
=== Book 2 ===
"The Great Gatsby" by F. Scott Fitzgerald (1925)
Pages: 180
Is long: False
Cover: Hardcover
=== Using __str__ ===
"1984" by George Orwell (1949)
"The Great Gatsby" by F. Scott Fitzgerald (1925)
What's Next
In the next tutorial, we'll learn about OOP - Inheritance & Polymorphism - how to extend classes and use inheritance.