Skip to content
Badr Academy Education
العربية
Badr Academy Education

Browse by topic

Programming

Object-oriented programming in Python, simply: classes and objects

Classes, objects, methods, encapsulation and inheritance with everyday examples – and when OOP helps and when simple functions are enough.

  • 9 min read
Object-oriented programming in Python, simply: classes and objects

As your programs grow, you will notice that the data and the functions that work on it begin to tangle. You have a dictionary for each student, functions that calculate their average, others that add a mark, and a third set that prints their report – all scattered across the file. Object-oriented programming is a way of organising code that groups data and the functions that belong to it into one unit called an object. The term may sound complicated, but the idea is very close to how we think about the world around us. In this article we explain it simply, with everyday examples, and show when it genuinely helps and when ordinary functions are enough.

What you will learn

  • The difference between a class and an object, with an everyday example.
  • How to define a class in Python: __init__, attributes and methods.
  • The core ideas: encapsulation, inheritance and polymorphism.
  • When to use object-oriented programming and when you do not need it.

Class and object: the template and the copy

Think of the academy’s registration form. The blank form sets out the required fields: name, age and course. That form is the class: a template describing the general shape. Each form filled in for a real student – Mariam or Youssef – is an object: a specific copy of the template with its own values. From one class you can create any number of objects, each with its own independent data.

Every object has two things: attributes that describe its state, such as the student’s name and marks, and methods that describe what it can do or what can be done with it, such as adding a mark or calculating the average.

Your first class in Python

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.scores = []

    def add_score(self, score):
        self.scores.append(score)

    def average(self):
        if not self.scores:
            return 0
        return sum(self.scores) / len(self.scores)

mariam = Student("Mariam", 14)
mariam.add_score(95)
mariam.add_score(88)
print(mariam.name, mariam.average())

What is happening here?

  • class Student: we define a new class. By convention, class names start with a capital letter.
  • __init__: a special method that runs automatically when a new object is created and sets up its first attributes. It is sometimes called the “constructor”.
  • self: refers to the object itself. When you write self.name = name, you store the name inside this particular object, not in a global variable.
  • Student("Mariam", 14): we create an object from the class. Python calls __init__ and passes the values.
  • mariam.add_score(95): we call one of the object’s methods using the dot.

If we create another object, youssef = Student("Youssef", 15), it will have a list of marks entirely separate from Mariam’s. That is the core idea: every object carries its own data.

In the following video Corey Schafer explains classes and instances step by step; it is the first part of a complete series on the subject:

Video: “Python OOP Tutorial 1: Classes and Instances” – Corey Schafer on YouTube (in English).

Let the object describe itself: the __str__ method

Try writing print(mariam) and you will see a cryptic message with the class name and a memory address. To show useful information, add a special method called __str__ to the class that returns a string describing the object, such as the student’s name and average. print will then show that text automatically. These methods that begin and end with double underscores are called “magic methods”, and they let your objects behave like Python’s built-in types: be printed, compared and added together.

The three core ideas

1EncapsulationData and its methods in one unit, withdetails hidden2InheritanceA new class inherits from an existingone and adds to it3PolymorphismThe same method, behaving differentlyby object type1EncapsulationData and its methods in one unit,with details hidden2InheritanceA new class inherits from an existingone and adds to it3PolymorphismThe same method, behaving differentlyby object type
Three core ideas in object-oriented programming

1. Encapsulation

Encapsulation means an object carries its data and the methods that work on it, and controls how that data is changed. For example, instead of letting any part of the program add a mark directly to the list, we make additions go through add_score, and put a check there that rejects marks below zero or above a hundred. That protects the data from wrong values in one place. In Python the convention is that an attribute whose name starts with an underscore, such as _scores, is meant for internal use.

2. Inheritance

Inheritance lets you create a new class that builds on an existing one. Suppose we have a Person class with a name, an age and a method for introducing oneself. We can create a Student class that inherits all of that and adds marks, and a Teacher class that inherits the same and adds the subject they teach. That avoids repeating shared code:

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

    def introduce(self):
        return f"I am {self.name}"

class Teacher(Person):
    def __init__(self, name, subject):
        super().__init__(name)
        self.subject = subject

    def introduce(self):
        return f"I am {self.name}, and I teach {self.subject}"

3. Polymorphism

Notice in the example above that Teacher redefined the introduce method. If we have a list of people and teachers and call introduce() on each item, every object behaves according to its class. The program does not need to ask “is this a teacher or a student?” before each call. That makes code flexible and easy to extend: if you add a new class such as Parent, you will not need to change the loop.

A quick comparison

Situation Functions and dictionaries are enough Classes fit better
Program size A short script for one job An application that grows over time
Kind of data Simple data passing through steps Things with state and behaviour: a student, a course, an account
Repetition Few similar kinds of thing Related kinds that share attributes and methods
Teamwork One programmer A team that needs clear boundaries between parts of the code

When do you not need object-oriented programming?

A common mistake is for an enthusiastic beginner to turn everything into classes, even a program that converts a temperature. Classes are an organising tool, not a goal in themselves. If your program is simple and made of consecutive steps, clear functions are enough and easier to read. Start with functions, as we explained in functions in Python, and when you notice you are passing the same group of data to many functions, that is a sign a class might help.

A design exercise: how do you think before you write?

Before writing any class, try this simple design method. Write a short description of the system in plain language, such as: “At the academy, students enrol in courses; each course has an instructor and a set of lessons, and a student gets a mark in each test.” Then underline the nouns: student, course, instructor, lesson, test. These are candidates for classes. Double-underline the verbs: enrol, get a mark. These are candidates for methods. Next, ask of each class: what data does it hold? What can it do? Who deals with it? Draw the classes as boxes on paper, with arrows between related ones. Ten minutes of thinking in advance saves hours of rewriting code later, and shows you early which similar parts could share one parent class through inheritance.

Common mistakes

  • Forgetting self: every method inside a class needs self as its first parameter, or you will get an error when you call it.
  • Confusing the class with the object: Student is the template and mariam is the object. You usually call methods on the object.
  • Using a list as a default parameter value: such as def __init__(self, scores=[]), which makes every object share the same list without your meaning to. Create the list inside the method, as in our example.
  • Long inheritance chains: inheriting across more than two or three levels makes code hard to follow.

Exercises to practise

  1. Create a Book class with a title, an author and a page count, and a method that returns a description of the book.
  2. Create a BankAccount class with a balance and two methods, deposit and withdraw, that refuses a withdrawal when the balance is too low.
  3. Create a Course class holding a list of Student objects, with a method that returns the whole class’s average.

In a Python and SQLite project we use these ideas in a real application that saves its data. In the Python course at Badr Academy Education we build complete projects with classes, with review from the instructor. For further resources visit the learning library, and try the Find your path tool to plan your next steps.

The takeaway

A class is a template, and an object is a copy of it that carries its own data and methods. Encapsulation protects the data, inheritance prevents repetition, and polymorphism makes code flexible. Use classes when your program grows and contains things with state and behaviour, and stay with functions for simple programs.

© 2026 Badr Academy Education – this content is exclusive to Badr Academy Education. Short quotations are welcome with the source and a link to this page.

Share this article

Comments (0)

You can comment without an account; your comment appears after review, and the academy may edit it before publishing.

Add a comment

Your e-mail will not be published. Required fields are marked *

No comments yet – be the first to join in.