8 of 20 topics completed
Python Object-Oriented Programming (OOP)
Object-Oriented Programming (OOP) is a powerful paradigm that helps you create organized, reusable, and modular code. In this tutorial, you'll learn how to use classes and objects in Python to model real-world concepts and build more maintainable programs.
💡 Real-World Relevance
OOP is essential in large-scale software development. Almost all modern frameworks and libraries (like Django, Flask, PyQt, etc.) are built using OOP principles. Understanding OOP will help you build more complex applications and better understand existing codebases.
What is Object-Oriented Programming?
OOP is a programming paradigm based on the concept of "objects," which can contain:
- Data (attributes or properties)
- Functions (methods) that operate on that data
Think of objects as digital representations of real-world entities. For example, a "Student" object might have:

Attributes (Data)
- Name
- Age
- Grade
- Courses
Methods (Functions)
- enroll_in_course()
- calculate_gpa()
- print_schedule()
- graduate()
Classes and Objects in Python
In Python, a class is a blueprint for creating objects. An objectis an instance of a class. Let's look at a simple example:
1# Define a class2class Dog:3 # Class attribute (shared by all instances)4 species = "Canis familiaris"56 # Initialize method (constructor)7 def __init__(self, name, age):8 # Instance attributes (unique to each instance)9 self.name = name10 self.age = age1112 # Instance method13 def bark(self):14 return f"{self.name} says Woof!"1516 # Another instance method17 def get_info(self):18 return f"{self.name} is {self.age} years old"1920# Create objects (instances of the Dog class)21buddy = Dog("Buddy", 5)22max = Dog("Max", 3)2324# Access attributes25print(buddy.name) # Output: Buddy26print(max.age) # Output: 327print(buddy.species) # Output: Canis familiaris2829# Call methods30print(buddy.bark()) # Output: Buddy says Woof!31print(max.get_info()) # Output: Max is 3 years old
Key Components
__init__
method: Constructor that initializes new objectsself
parameter: Reference to the current instance- Instance attributes: Unique to each object (e.g.,
name
,age
) - Class attributes: Shared by all instances (e.g.,
species
) - Methods: Functions defined in the class
The 'self' Parameter
The self
parameter refers to the instance of the class. It:
- Must be the first parameter of any instance method
- Allows access to the instance's attributes and methods
- Is automatically passed when you call a method on an object
- Works like "this" in other programming languages
Inheritance: Building on Existing Classes
Inheritance allows you to create a new class that is a modified version of an existing class. The new class (subclass) inherits attributes and methods from the existing class (superclass).
1# Parent class2class Animal:3 def __init__(self, name, species):4 self.name = name5 self.species = species67 def make_sound(self):8 return "Some generic animal sound"910 def get_info(self):11 return f"{self.name} is a {self.species}"1213# Child class (inherits from Animal)14class Cat(Animal):15 def __init__(self, name, breed, toy):16 # Call the parent class's __init__ method17 super().__init__(name, species="Cat")18 self.breed = breed19 self.toy = toy2021 # Override the parent's method22 def make_sound(self):23 return "Meow!"2425 # Add a new method26 def play(self):27 return f"{self.name} plays with {self.toy}"2829# Create an instance of the Cat class30whiskers = Cat("Whiskers", "Siamese", "String")3132# Use inherited methods and attributes33print(whiskers.name) # Output: Whiskers34print(whiskers.species) # Output: Cat35print(whiskers.get_info()) # Output: Whiskers is a Cat3637# Use overridden and new methods38print(whiskers.make_sound()) # Output: Meow!39print(whiskers.play()) # Output: Whiskers plays with String

Key Inheritance Concepts:
- Parent class/Superclass: The class being inherited from
- Child class/Subclass: The class that inherits from the parent
- super(): Used to call methods from the parent class
- Method overriding: Redefining a method in a subclass
- IS-A relationship: A Cat is an Animal
Encapsulation: Controlling Access to Data
Encapsulation is the concept of bundling data and methods that work on that data within a single unit (the class) and restricting access to some of the object's components.
Python uses conventions rather than strict access control:
1class BankAccount:2 def __init__(self, owner, balance=0):3 self.owner = owner # Public attribute4 self._balance = balance # Protected attribute (convention)5 self.__account_num = "12345" # Private attribute67 # Public method8 def deposit(self, amount):9 if amount > 0:10 self._balance += amount11 return True12 return False1314 # Public method15 def withdraw(self, amount):16 if 0 < amount <= self._balance:17 self._balance -= amount18 return True19 return False2021 # Public method to access protected attribute22 def get_balance(self):23 return self._balance2425 # Private method26 def __generate_statement(self):27 return f"Statement for {'{'} self.owner {'}'}: Balance: { self._balance {'}'}"2829 # Public method that uses private method30 def print_statement(self):31 statement = self.__generate_statement()32 print(statement)3334# Create an account35account = BankAccount("Alice", 1000)3637# Access public members38print(account.owner) # Output: Alice39account.deposit(500)40print(account.get_balance()) # Output: 15004142# Access protected member (possible, but not recommended)43print(account._balance) # Output: 15004445# Try to access private member (name mangling occurs)46# print(account.__account_num) # AttributeError47print(account._BankAccount__account_num) # Output: 12345 (name mangling)
Access Level | Naming Convention | Accessibility |
---|---|---|
Public | name | Accessible from anywhere |
Protected | _name | Convention indicating "internal use" (still accessible) |
Private | __name | Name mangling occurs, harder to access from outside |
⚠️ Python's Approach
Python follows the principle of "we're all consenting adults here" - encapsulation is more of a guideline than a strict rule. Private attributes can still be accessed using name mangling (_ClassName__attribute
), but it's considered bad practice to do so.
Polymorphism: One Interface, Multiple Forms
Polymorphism allows objects of different classes to be treated as objects of a common superclass. It means you can use the same interface (method or function) for different data types.
1# Different classes with the same method2class Dog:3 def speak(self):4 return "Woof!"56class Cat:7 def speak(self):8 return "Meow!"910class Duck:11 def speak(self):12 return "Quack!"1314# Function that can work with any of these objects15def animal_sound(animal):16 return animal.speak()1718# Create instances19dog = Dog()20cat = Cat()21duck = Duck()2223# Call the function with different objects24print(animal_sound(dog)) # Output: Woof!25print(animal_sound(cat)) # Output: Meow!26print(animal_sound(duck)) # Output: Quack!2728# Using polymorphism with a list29animals = [Dog(), Cat(), Duck()]30for animal in animals:31 print(animal.speak())
Python's "duck typing" is a form of polymorphism: "If it walks like a duck and quacks like a duck, then it probably is a duck." This means Python cares about behavior (methods and properties), not the actual type of an object.
Special (Magic/Dunder) Methods
Python has special methods surrounded by double underscores (Dunder = Double UNDERscore) that allow you to define how objects of your class behave with built-in functions and operators.
1class Point:2 def __init__(self, x, y):3 self.x = x4 self.y = y56 # String representation for developers (debugging)7 def __repr__(self):8 return f"Point({self.x}, {self.y})"910 # String representation for users11 def __str__(self):12 return f"Point at coordinates ({self.x}, {self.y})"1314 # Addition operator (+)15 def __add__(self, other):16 return Point(self.x + other.x, self.y + other.y)1718 # Equality operator (==)19 def __eq__(self, other):20 return self.x == other.x and self.y == other.y2122 # Less than operator (<)23 def __lt__(self, other):24 return (self.x**2 + self.y**2) < (other.x**2 + other.y**2)2526 # Length function (len())27 def __len__(self):28 # Distance from origin, rounded to nearest integer29 return int((self.x**2 + self.y**2)**0.5)3031# Create points32p1 = Point(3, 4)33p2 = Point(1, 2)3435# Use our special methods36print(p1) # Output: Point at coordinates (3, 4)37print(repr(p1)) # Output: Point(3, 4)38p3 = p1 + p2 # Using __add__39print(p3) # Output: Point at coordinates (4, 6)40print(p1 == Point(3, 4)) # Output: True (using __eq__)41print(p1 < p2) # Output: False (using __lt__)42print(len(p1)) # Output: 5 (using __len__)
Special Method | Purpose | Example Usage |
---|---|---|
__init__(self, ...) | Constructor | x = MyClass() |
__str__(self) | String representation | print(obj) , str(obj) |
__repr__(self) | Developer representation | repr(obj) |
__len__(self) | Length | len(obj) |
__add__(self, other) | Addition | obj1 + obj2 |
__eq__(self, other) | Equality | obj1 == obj2 |
Practical Example: Building a Student Management System
Let's apply OOP principles to build a simple student management system:
1class Person:2 """Base class for all persons in the system."""3 def __init__(self, name, age):4 self.name = name5 self.age = age67 def get_info(self):8 return f"{self.name}, {self.age} years old"91011class Student(Person):12 """A student in the system."""13 def __init__(self, name, age, student_id):14 super().__init__(name, age)15 self.student_id = student_id16 self.courses = []17 self.grades = {}1819 def enroll(self, course):20 if course not in self.courses:21 self.courses.append(course)22 self.grades[course] = None23 return True24 return False2526 def assign_grade(self, course, grade):27 if course in self.courses:28 self.grades[course] = grade29 return True30 return False3132 def get_gpa(self):33 grades = [g for g in self.grades.values() if g is not None]34 if not grades:35 return 036 return sum(grades) / len(grades)3738 def get_info(self):39 base_info = super().get_info()40 return f"{base_info}, ID: {self.student_id}, GPA: {self.get_gpa():.2f}"414243class Teacher(Person):44 """A teacher in the system."""45 def __init__(self, name, age, employee_id, subject):46 super().__init__(name, age)47 self.employee_id = employee_id48 self.subject = subject49 self.students = []5051 def assign_student(self, student):52 if student not in self.students:53 self.students.append(student)54 student.enroll(self.subject)55 return True56 return False5758 def grade_student(self, student, grade):59 if student in self.students:60 return student.assign_grade(self.subject, grade)61 return False6263 def get_class_average(self):64 grades = [s.grades.get(self.subject, 0) for s in self.students65 if s.grades.get(self.subject) is not None]66 if not grades:67 return 068 return sum(grades) / len(grades)6970 def get_info(self):71 base_info = super().get_info()72 return f"{base_info}, ID: {self.employee_id}, Subject: {self.subject}"737475class School:76 """A school containing students and teachers."""77 def __init__(self, name):78 self.name = name79 self.students = []80 self.teachers = []8182 def add_student(self, student):83 if student not in self.students:84 self.students.append(student)85 return True86 return False8788 def add_teacher(self, teacher):89 if teacher not in self.teachers:90 self.teachers.append(teacher)91 return True92 return False9394 def get_student_by_id(self, student_id):95 for student in self.students:96 if student.student_id == student_id:97 return student98 return None99100 def get_teacher_by_subject(self, subject):101 return [t for t in self.teachers if t.subject == subject]102103 def __str__(self):104 return f"{self.name} School with {len(self.students)} students and {len(self.teachers)} teachers"105106107# Example usage108def main():109 # Create a school110 school = School("Springfield Elementary")111112 # Create teachers113 math_teacher = Teacher("Mrs. Adams", 45, "T001", "Mathematics")114 science_teacher = Teacher("Mr. Smith", 38, "T002", "Science")115116 # Add teachers to school117 school.add_teacher(math_teacher)118 school.add_teacher(science_teacher)119120 # Create students121 alice = Student("Alice Johnson", 12, "S001")122 bob = Student("Bob Williams", 11, "S002")123 charlie = Student("Charlie Brown", 12, "S003")124125 # Add students to school126 school.add_student(alice)127 school.add_student(bob)128 school.add_student(charlie)129130 # Assign students to teachers131 math_teacher.assign_student(alice)132 math_teacher.assign_student(bob)133 math_teacher.assign_student(charlie)134135 science_teacher.assign_student(alice)136 science_teacher.assign_student(charlie)137138 # Assign grades139 math_teacher.grade_student(alice, 95)140 math_teacher.grade_student(bob, 88)141 math_teacher.grade_student(charlie, 75)142143 science_teacher.grade_student(alice, 92)144 science_teacher.grade_student(charlie, 85)145146 # Print information147 print(school)148 print(f"Math class average: {math_teacher.get_class_average():.2f}")149 print(f"Science class average: {science_teacher.get_class_average():.2f}")150151 print("152Student Information:")153 for student in school.students:154 print(student.get_info())155156 print("157Teacher Information:")158 for teacher in school.teachers:159 print(teacher.get_info())160161# Run the program162main()
Output of the above program:
1Springfield Elementary School with 3 students and 2 teachers2Math class average: 86.003Science class average: 88.5045Student Information:6Alice Johnson, 12 years old, ID: S001, GPA: 93.507Bob Williams, 11 years old, ID: S002, GPA: 88.008Charlie Brown, 12 years old, ID: S003, GPA: 80.00910Teacher Information:11Mrs. Adams, 45 years old, ID: T001, Subject: Mathematics12Mr. Smith, 38 years old, ID: T002, Subject: Science
🎯 Try it yourself!
Extend the Student Management System with these features:
- Add a
Course
class with properties like name, code, and credits - Implement attendance tracking for students
- Add a method to generate a report card for each student
- Create an
Administrator
class that can manage both students and teachers
Best Practices for OOP in Python
- Follow naming conventions
- Class names should use CamelCase:
MyClass
- Method and attribute names should use snake_case:
my_method
- Constants should be UPPERCASE:
MAX_STUDENTS
- Class names should use CamelCase:
- Use docstrings to document your classes and methods
- Keep classes focused on a single responsibility (Single Responsibility Principle)
- Use inheritance wisely - prefer composition over inheritance when appropriate
- Don't expose internal details - use properties and methods to control access
- Implement special methods when they make sense for your class
Summary
In this tutorial, you've learned:
- The core concepts of Object-Oriented Programming
- How to create classes and objects in Python
- Inheritance and how to create class hierarchies
- Encapsulation and data hiding techniques
- Polymorphism and duck typing
- Special methods to integrate with Python's built-in functions
- How to apply OOP principles to a real-world example
Object-Oriented Programming is a powerful paradigm that helps you organize and structure your code in a way that models real-world relationships. As you continue your Python journey, you'll find these principles invaluable for creating maintainable, reusable, and scalable code.
Related Tutorials
Master creating and using functions in Python.
Learn moreLearn how to handle errors and exceptions in Python.
Learn moreOrganize your code into reusable modules and packages.
Learn more