Skip to main content

Python Classes and Objects

Introduction

Object-Oriented Programming (OOP) is a programming paradigm that uses "objects" to structure code. Python, being a multi-paradigm language, has excellent support for OOP concepts. Two fundamental concepts in OOP are classes and objects.

A class is like a blueprint or template that defines the structure and behavior of objects. An object is an instance of a class, representing a specific entity with its own characteristics based on the class definition.

In this tutorial, we'll explore how to create and use classes and objects in Python, providing you with a solid foundation for object-oriented programming.

Understanding Classes and Objects

What is a Class?

A class in Python is defined using the class keyword. It encapsulates data (attributes) and functions (methods) that operate on that data.

python
class Dog:
# Class attributes
species = "Canis familiaris"

# Initializer / Constructor
def __init__(self, name, age):
# Instance attributes
self.name = name
self.age = age

# Instance method
def description(self):
return f"{self.name} is {self.age} years old"

# Another instance method
def speak(self, sound):
return f"{self.name} says {sound}"

What is an Object?

An object is an instance of a class. When you create an object, you're creating a specific entity based on the class blueprint.

python
# Creating objects from the Dog class
buddy = Dog("Buddy", 9)
miles = Dog("Miles", 4)

# Accessing attributes
print(buddy.name) # Output: Buddy
print(miles.age) # Output: 4

# Calling methods
print(buddy.description()) # Output: Buddy is 9 years old
print(miles.speak("Woof!")) # Output: Miles says Woof!

Creating and Using Classes

Class Definition

Let's break down how to define a class:

python
class ClassName:
# Class attributes
class_attribute = value

# Constructor
def __init__(self, param1, param2):
# Instance attributes
self.param1 = param1
self.param2 = param2

# Instance methods
def method_name(self, parameters):
# Method body
pass

The __init__ Method

The __init__ method is a special method that Python calls when you create a new instance of a class. It's also known as a constructor.

python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

# Creating a Person object
person1 = Person("Alice", 30)
print(f"{person1.name} is {person1.age} years old")
# Output: Alice is 30 years old

The self Parameter

The self parameter is a reference to the current instance of the class, and is used to access variables and methods associated with the class.

python
class Circle:
def __init__(self, radius):
self.radius = radius

def area(self):
import math
return math.pi * (self.radius ** 2)

def perimeter(self):
import math
return 2 * math.pi * self.radius

# Creating a Circle object
circle1 = Circle(5)
print(f"Area: {circle1.area():.2f}")
# Output: Area: 78.54
print(f"Perimeter: {circle1.perimeter():.2f}")
# Output: Perimeter: 31.42

Class Attributes vs Instance Attributes

Class Attributes

Class attributes are defined at the class level and are shared by all instances of the class.

python
class Student:
# Class attribute
school = "Python Academy"

def __init__(self, name, grade):
# Instance attributes
self.name = name
self.grade = grade

# Creating Student objects
student1 = Student("Bob", "A")
student2 = Student("Alice", "B")

print(student1.school) # Output: Python Academy
print(student2.school) # Output: Python Academy

# Changing the class attribute
Student.school = "Code Academy"
print(student1.school) # Output: Code Academy
print(student2.school) # Output: Code Academy

Instance Attributes

Instance attributes are unique to each instance of the class and are defined in the __init__ method.

python
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer = 0 # Default value

def drive(self, miles):
self.odometer += miles
return f"The car has been driven for {self.odometer} miles in total"

# Creating Car objects
car1 = Car("Toyota", "Corolla", 2020)
car2 = Car("Honda", "Civic", 2021)

print(car1.make) # Output: Toyota
print(car2.model) # Output: Civic

print(car1.drive(100)) # Output: The car has been driven for 100 miles in total
print(car1.drive(50)) # Output: The car has been driven for 150 miles in total
print(car2.drive(75)) # Output: The car has been driven for 75 miles in total

Methods in Classes

Instance Methods

Instance methods operate on instance attributes and can access and modify the object's state.

python
class BankAccount:
def __init__(self, account_holder, balance=0):
self.account_holder = account_holder
self.balance = balance

def deposit(self, amount):
self.balance += amount
return f"Deposited ${amount}. New balance: ${self.balance}"

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"Current balance: ${self.balance}"

# Creating a BankAccount object
account = BankAccount("John Doe", 1000)

print(account.get_balance()) # Output: Current balance: $1000
print(account.deposit(500)) # Output: Deposited $500. New balance: $1500
print(account.withdraw(200)) # Output: Withdrew $200. New balance: $1300
print(account.withdraw(2000)) # Output: Insufficient funds

Class Methods

Class methods are methods that are bound to the class rather than its instances. They can't access instance attributes directly. They are defined using the @classmethod decorator.

python
class Employee:
# Class attribute
company = "Tech Corp"
employee_count = 0

def __init__(self, name, position):
self.name = name
self.position = position
Employee.employee_count += 1

@classmethod
def get_employee_count(cls):
return f"Total employees: {cls.employee_count}"

@classmethod
def change_company(cls, new_company):
cls.company = new_company
return f"Company changed to {cls.company}"

# Creating Employee objects
employee1 = Employee("Alice", "Developer")
employee2 = Employee("Bob", "Designer")

print(Employee.get_employee_count()) # Output: Total employees: 2
print(Employee.change_company("New Tech")) # Output: Company changed to New Tech
print(employee1.company) # Output: New Tech

Static Methods

Static methods don't operate on either class or instance attributes. They are defined using the @staticmethod decorator.

python
class MathOperations:
@staticmethod
def add(x, y):
return x + y

@staticmethod
def subtract(x, y):
return x - y

@staticmethod
def multiply(x, y):
return x * y

@staticmethod
def divide(x, y):
if y == 0:
return "Cannot divide by zero"
return x / y

# Using static methods without creating an instance
print(MathOperations.add(5, 3)) # Output: 8
print(MathOperations.subtract(10, 4)) # Output: 6
print(MathOperations.multiply(2, 5)) # Output: 10
print(MathOperations.divide(15, 3)) # Output: 5.0
print(MathOperations.divide(10, 0)) # Output: Cannot divide by zero

Real-World Example: Building a Library System

Let's create a simple library management system using classes and objects:

python
class Book:
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.available = True

def __str__(self):
status = "Available" if self.available else "Not Available"
return f"{self.title} by {self.author} (ISBN: {self.isbn}) - {status}"


class Library:
def __init__(self, name):
self.name = name
self.books = []

def add_book(self, book):
self.books.append(book)
return f"{book.title} added to {self.name}"

def display_books(self):
if not self.books:
return "No books in the library"

book_list = "\n".join([str(book) for book in self.books])
return f"Books in {self.name}:\n{book_list}"

def search_book(self, search_term):
results = []
for book in self.books:
if (search_term.lower() in book.title.lower() or
search_term.lower() in book.author.lower() or
search_term == book.isbn):
results.append(book)

if not results:
return "No matching books found"

result_list = "\n".join([str(book) for book in results])
return f"Search results:\n{result_list}"

def borrow_book(self, isbn):
for book in self.books:
if book.isbn == isbn:
if book.available:
book.available = False
return f"{book.title} has been borrowed"
else:
return f"{book.title} is not available for borrowing"
return "Book not found in the library"

def return_book(self, isbn):
for book in self.books:
if book.isbn == isbn:
if not book.available:
book.available = True
return f"{book.title} has been returned"
else:
return f"{book.title} was not borrowed"
return "Book not found in the library"


# Using the library system
city_library = Library("City Public Library")

# Adding books
book1 = Book("Python Programming", "John Smith", "978-1-123456-78-9")
book2 = Book("Data Science Basics", "Jane Doe", "978-2-987654-32-1")
book3 = Book("Python for Data Analysis", "Alice Johnson", "978-3-456789-01-2")

city_library.add_book(book1)
city_library.add_book(book2)
city_library.add_book(book3)

# Displaying all books
print(city_library.display_books())
# Output:
# Books in City Public Library:
# Python Programming by John Smith (ISBN: 978-1-123456-78-9) - Available
# Data Science Basics by Jane Doe (ISBN: 978-2-987654-32-1) - Available
# Python for Data Analysis by Alice Johnson (ISBN: 978-3-456789-01-2) - Available

# Searching for books
print(city_library.search_book("Python"))
# Output:
# Search results:
# Python Programming by John Smith (ISBN: 978-1-123456-78-9) - Available
# Python for Data Analysis by Alice Johnson (ISBN: 978-3-456789-01-2) - Available

# Borrowing a book
print(city_library.borrow_book("978-1-123456-78-9"))
# Output: Python Programming has been borrowed

# Displaying books after borrowing
print(city_library.display_books())
# Output:
# Books in City Public Library:
# Python Programming by John Smith (ISBN: 978-1-123456-78-9) - Not Available
# Data Science Basics by Jane Doe (ISBN: 978-2-987654-32-1) - Available
# Python for Data Analysis by Alice Johnson (ISBN: 978-3-456789-01-2) - Available

# Returning a book
print(city_library.return_book("978-1-123456-78-9"))
# Output: Python Programming has been returned

This library system demonstrates how classes and objects can be used to model real-world entities and their interactions. The Book class represents individual books with their properties, while the Library class manages a collection of books and provides operations to work with them.

Summary

In this tutorial, we've covered the fundamentals of classes and objects in Python:

  1. Classes are blueprints for creating objects with specific attributes and behaviors
  2. Objects are instances of classes with their own unique data
  3. Attributes can be at the class level (shared by all instances) or instance level (unique to each object)
  4. Methods define the behavior of objects and can access/modify their state
  5. Special methods like __init__ are used for initialization and other purposes

Understanding classes and objects is crucial for implementing object-oriented programming in Python. They allow you to structure your code in a more modular, reusable, and maintainable way, particularly for complex applications.

Practice Exercises

  1. Create a Rectangle class with attributes for width and height. Include methods to calculate area and perimeter.

  2. Implement a Student class with attributes for name, age, and grades (a list). Add methods to add grades, get the average grade, and display student information.

  3. Design a simple ShoppingCart class that allows adding items, removing items, calculating the total price, and displaying the cart contents.

  4. Create a Timer class that can be used to track elapsed time between starting and stopping.

  5. Implement a Temperature class that can convert between Celsius, Fahrenheit, and Kelvin.

Additional Resources

Happy coding!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)