Python Classes and Objects
Master object-oriented programming in Python - from basic concepts to advanced techniques
🏗️ What are Classes and Objects?
In Python, everything is an object. Classes are blueprints for creating objects, providing a means of bundling data and functionality together. Think of a class as a cookie cutter and objects as the actual cookies made with it.
# Creating a simple class and object
class Car:
def __init__(self, brand):
self.brand = brand
# Creating an object from the class
my_car = Car("Toyota")
print(my_car.brand) # Output: Toyota
Creating Your First Class
Let's start with the simplest possible class to understand the basic syntax:
# Step 1: Define a simple class
class MyClass:
x = 5 # Class attribute
# Step 2: Create an object (instance)
my_object = MyClass()
# Step 3: Access the attribute
print(my_object.x) # Output: 5
print(type(my_object)) # Output:
The __init__() Constructor
The
__init__()
method is called automatically when creating an object. It's used to initialize the object's attributes:
class Person:
def __init__(self, name, age):
self.name = name # Instance attribute
self.age = age # Instance attribute
def introduce(self):
return f"Hi, I'm {self.name} and I'm {self.age} years old"
# Create objects with different data
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
print(person1.introduce()) # Hi, I'm Alice and I'm 25 years old
print(person2.introduce()) # Hi, I'm Bob and I'm 30 years old
Object Methods
Methods are functions that belong to objects. They can access and modify the object's data:
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = 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 > 0 and amount <= self.balance:
self.balance -= amount
return f"Withdrew ${amount}. New balance: ${self.balance}"
return "Insufficient funds or invalid amount"
def get_balance(self):
return f"Current balance: ${self.balance}"
# Using the class
account = BankAccount("John", 100)
print(account.get_balance()) # Current balance: $100
print(account.deposit(50)) # Deposited $50. New balance: $150
print(account.withdraw(30)) # Withdrew $30. New balance: $120
Understanding the 'self' Parameter
The
self
parameter refers to the current instance of the class. It's not a keyword but a convention:
class Car:
def __init__(myself, brand, model): # 'myself' instead of 'self'
myself.brand = brand
myself.model = model
myself.speed = 0
def accelerate(this_car, increase): # 'this_car' instead of 'self'
this_car.speed += increase
return f"{this_car.brand} {this_car.model} is now going {this_car.speed} mph"
# The first parameter name doesn't matter, but 'self' is the convention
car = Car("Toyota", "Camry")
print(car.accelerate(30)) # Toyota Camry is now going 30 mph
# You can also call methods this way (not recommended):
print(Car.accelerate(car, 20)) # Toyota Camry is now going 50 mph
Modifying and Deleting Object Properties
You can modify, add, or delete object properties dynamically:
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
student = Student("Emma", "A")
print(f"Original: {student.name}, Grade: {student.grade}")
# Modify existing property
student.grade = "A+"
print(f"Modified grade: {student.grade}")
# Add new property
student.age = 20
print(f"Added age: {student.age}")
# Delete property
del student.age
# print(student.age) # This would raise AttributeError
# Delete entire object
# del student
# print(student) # This would raise NameError
Real-World Example: Library Management
Let's create a more complex example that demonstrates multiple concepts:
class Book:
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.is_available = True
self.borrowed_by = None
def borrow(self, borrower_name):
if self.is_available:
self.is_available = False
self.borrowed_by = borrower_name
return f"'{self.title}' borrowed by {borrower_name}"
return f"'{self.title}' is not available"
def return_book(self):
if not self.is_available:
borrower = self.borrowed_by
self.is_available = True
self.borrowed_by = None
return f"'{self.title}' returned by {borrower}"
return f"'{self.title}' was not borrowed"
def get_info(self):
status = "Available" if self.is_available else f"Borrowed by {self.borrowed_by}"
return f"'{self.title}' by {self.author} - {status}"
class Library:
def __init__(self, name):
self.name = name
self.books = []
def add_book(self, book):
self.books.append(book)
return f"Added '{book.title}' to {self.name}"
def find_book(self, title):
for book in self.books:
if book.title.lower() == title.lower():
return book
return None
def list_available_books(self):
available = [book for book in self.books if book.is_available]
if available:
return [book.get_info() for book in available]
return ["No books available"]
# Using the library system
library = Library("City Library")
# Create books
book1 = Book("Python Programming", "John Smith", "123456789")
book2 = Book("Data Science Basics", "Jane Doe", "987654321")
# Add books to library
print(library.add_book(book1))
print(library.add_book(book2))
# Borrow a book
print(book1.borrow("Alice"))
# Check available books
print("\nAvailable books:")
for info in library.list_available_books():
print(f"- {info}")
# Return the book
print(f"\n{book1.return_book()}")
# Check available books again
print("\nAvailable books after return:")
for info in library.list_available_books():
print(f"- {info}")
The pass Statement
Use
pass
when you need a class definition but haven't implemented it yet:
# Empty class placeholder
class FutureFeature:
pass # TODO: Implement later
# You can still create objects
placeholder = FutureFeature()
print(type(placeholder)) #
# Add attributes dynamically
placeholder.name = "Test"
placeholder.value = 42
print(f"Name: {placeholder.name}, Value: {placeholder.value}")