linkedin Skip to Main Content
Categories

Guide to Classes and Object-Oriented Programming in Python

Development

Object-oriented programming (OOP) is a popular programming paradigm for writing software. Before the development of object-oriented programming, procedural programming was an efficient way of building or writing software. 

In procedural programming, programs are divided into interdependent functions, which is a straightforward process. However, due to the interdependence of functions, a change in one function can break several other functions. 

Object-oriented programming was developed to solve this problem.

As a software developer, object-oriented programming will give you a deeper understanding of your code by learning what happens line by line and the ideas underlying it.

In this tutorial, we will guide you through:

  • Understanding the concepts of object-oriented programming in Python
  • How to create a class and instantiate objects in Python.
  • The object-oriented programming pillars in Python

Let’s dive in!

What is Object-Oriented Programming (OOP) in Python?

Object-oriented programming is a programming model that provides a method of structuring data using objects and classes. These objects represent real-world situations and events. The goal of object-oriented programming is to combine properties and methods that work together as an individual unit.

For example, think of a car as an object with properties like brand name, model, color, size, etc. A car also has methods such as movement, speed, etc. These properties and methods are structured into an individual object or unit. This process of structuring is known as object-oriented programming.

Python is an object-oriented programming language that enables developers to create applications primarily focusing on code reusability. In Python, everything is an object consisting of methods and properties, making it easy for you to build classes and objects.

The main idea of object-oriented programming in Python is not just for data representation but to determine how the program is organized.

Classes and objects in Python

Simply put, a class is a blueprint or prototype for creating objects. To create an object, we need a class.

A class is a template that defines a collection of attributes and methods that specify the behavior that an object can carry out with its data. For instance, let us use a book as a class. A book has properties that contain the details of a book, such as a title, author, year of publication, etc. The book itself is the object. 

Once we have a defined set of properties, our class becomes an object. It allows the creation of as many objects as required using the same class. Let’s define a class to get a better understanding.

Defining a class in Python

A class is defined using the class keyword, followed by the class name, which is usually a word describing the class.

ℹ️ Class names in Python are in camel case. Each word starts with a capital letter.

In this section, we will define a book class that stores data about a book.

class Book:     …
Code language: Python (python)

In the code, we created a book class using the class keyword. Within this class is where we will define our attributes. Subsequently, we will add a body using custom methods, but before that, the placeholder lets us run this code without throwing an error.

Instantiate an object in Python

While a class is a sketch or blueprint of an object, an object is a set of attributes and functions built on real-world data. The process of creating an object in Python is called instantiation. An object is instantiated by adding the name of the class, Book, followed by an opening and closing bracket.

Here is an example:

>>> Book()
Code language: Python profile (profile)

These book examples are basic and not reflective yet of real-life applications. Before we get into more practical applications, we will first need to understand what dunder methods are and what they do.

Creating classes and objects with dunder methods

Dunder stands for “double underscores.” Methods that begin and end with double underscores are known as dunder methods

Dunder methods provide the functionality of a class when a specific event occurs in a program. Multiple dunder methods are used when working with classes and objects in Python. This article will focus on the init() method.

Init method

The  __init__() method is also known as a constructor. It is a unique Python method that is automatically executed whenever a class is used to instantiate an object. We use the  __init__() method when adding data or attributes to a new class object.

When defining the __init__() method, we are to add some parameters such as self and other parameters like name, title, age, etc., depending on the attributes.

Let us create a class and a set of objects using the  __init__() method. Several common attributes of a book can be added, such as title, author, and year of publication:

class Book:     def __init__(self, title, author, year):         self.title =  title         self.author = author         self.year = year       # instantiating a new object book1 = Book("Americanah", " Chimamanda Adichie", 2013) book2 = Book("Teller of secrets", "Bisi Adjapon", 2021) book3 = Book("Stay with me", "Ayobami Adebayo", 2017) print(book1.title)
Code language: Python (python)

Output

>>> Americanah
Code language: Python profile (profile)

In the code above, we created a Book class with an __init__() function that initializes three parameters: title, author, and year.

Next, we passed three parameters, although there are four arguments in the __init__()method. This is because the self parameter is only required when defining a method. It is not necessary to include it when calling the method.

Also, conventionally, the self parameter must come before other parameters. Python subsequently uses this parameter to create the Book instance.

Lastly, we instantiated a new object by adding values to the object. You can access any of the instance attributes of the Book instance using the dot notation.

ℹ️ Attributes are variables that can be accessed using instances. Example: book1.title .

The self parameter

The self parameter is a representation of the class instance. This parameter allows you to access the attributes in a class. In Python, it is a convention that theself parameter is to be provided first before other parameters in the instance method; otherwise, it will result in an error.

class Book:     def __init__():         print("This is a bookstore") object = Book() print("Welcome")
Code language: Python (python)

Output:

Traceback (most recent call last):   File "/Users/anitaachu/character-encoding/app.py", line 5, in <module>     object = Book() TypeError: __init__() takes 0 positional arguments but 1 was given
Code language: Python profile (profile)

ℹ️ The self parameter is not a Python keyword. Therefore, you can use any other word instead of “self.” However, it is good programming practice to use self.

Modifying and deleting objects

Imagine you had to review the books in your store, and you realized one of the books had the wrong year of publication. You can easily modify the attributes of objects in the Book class.

class Book:     def __init__(self, title, author, year):         self.title =  title         self.author = author         self.year = year         # instantiating a new object book1 = Book("Americanah", " Chimamanda Adichie", 2016) book2 = Book("Teller of secrets", "Bisi Adjapon", 2021) book3 = Book("Stay with me", "Ayobami Adebayo", 2017) # modifying attribute book1.year = 2013 print(book1.year)
Code language: Python (python)

When the code is executed, you will have this result:

>>> 2013
Code language: Python profile (profile)

You can also delete object values or the object itself using the del method.

class Book:     def __init__(self, title, author, year):         self.title =  title         self.author = author         self.year = year         # instantiating a new object book1 = Book("Americanah", " Chimamanda Adichie", 2016) book2 = Book("Teller of secrets", "Bisi Adjapon", 2021) book3 = Book("Stay with me", "Ayobami Adebayo", 2017) # deleting attribute del book2.year print(book2.year) When the code is executed, you will have this result: Traceback (most recent call last):   File "/Users/anitaachu/character-encoding/app.py", line 15, in <module>     print(book2.year) AttributeError: 'Book' object has no attribute 'year' 
Code language: Python (python)

Object-oriented programming principles

The primary object-oriented programming principles include:

  1. Encapsulation
  2. Inheritance
  3. Polymorphism

These principles are referred to as the pillars of object-oriented programming. Each concept is a broad topic and would take several articles to explore thoroughly. However, this article will discuss the basics of these concepts to give you a good understanding of what they are.

Encapsulation

Encapsulation is the process of restricting users’ access to specific class attributes or methods by only allowing the attributes to be available via particular methods.

ℹ️ Encapsulation is often referred to as data hiding.

With encapsulation, you can only share or expose what is needed for the user. The purpose of encapsulation is to prevent unauthorized modification of data.

In encapsulation, object attributes are made private and can only be modified by the object method. These objects’ attributes are known as private attributes.

How encapsulation works

The data contained in an object and the methods that manipulate the data are wrapped together in one unit. This restricts the variables that can be accessed.

For example, imagine you’re working with an organization that has salespeople and admins. The admins have access to all records of sales and finances. In a situation where a salesperson needs access to sales records, they cannot access this data without contacting an admin and requesting access to the sales record. This is encapsulation.

In Python, we use getters and setters to implement encapsulation. The getters and setters are methods that give us access to and modify the values of the private attributes, respectively.

In Python, we use double underscore __ to declare a private attribute. Let’s add a private attribute to the Book class.

class Book:     def __init__(self, title, author, year, price):         # public attributes         self.title =  title         self.author = author         self.year = year         # private attribute         self.__price = price     def __repr__(self):         return f"Book: {self.title}, Author: {self.author}, Year: {self.year}, Price: {self.price}"     # instantiating a new object book1 = Book("Americanah", " Chimamanda Adichie", 2016, 6000) book2 = Book("Teller of secrets", "Bisi Adjapon", 2021, 5000) book3 = Book("Stay with me", "Ayobami Adebayo", 2017, 4000) print(book3.title) print(book3.author) print(book3.year) print(book3.__price)
Code language: Python (python)

Output

Stay with me Ayobami Adebayo 2017 Traceback (most recent call last):   File "/Users/anitaachu/character-encoding/app.py", line 26, in <module>     print(book3.__price) AttributeError: 'Book' object has no attribute '__price'
Code language: Python profile (profile)

In the code above, price is a private attribute. Since it cannot be accessed outside the class, the output prints all the attributes except the price attribute.

However, we can access the private attribute using getter and setter methods:

class Book:     # constructor     def __init__(self, title, author, year, price):         # public data         self.title =  title         self.author = author         self.year = year         # private attribute         self.__price = price     # getter method     def get_price(self):         return self.__price       # setter method     def set_price(self, price):         self.__price = price     def __repr__(self):         return f"Book: {self.title}, Author: {self.author}, Year: {self.year}, Price: {self.get_price()}"     # instantiating a new object book1 = Book("Americanah", " Chimamanda Adichie", 2016, 6000) book2 = Book("Teller of secrets", "Bisi Adjapon", 2021, 5000) book3 = Book("Stay with me", "Ayobami Adebayo", 2017, 4000) # modifying price using setter book2.set_price(4000) print(book2)
Code language: Python (python)

Output

Book: Teller of secrets, Author: Bisi Adjapon, Year: 2021, Price: 4000
Code language: Python profile (profile)

Bravo! We got the private attribute and the modified price of book2.

However, bear in mind that these private attributes are not really protected. For example, we can access the price attribute using book1._Book__price.

class Book:     # constructor     def __init__(self, title, author, year, price):         # public data         self.title =  title         self.author = author     def __repr__(self):         return f"Book: {self.title}, Author: {self.author}, Year: {self.year}, Price: {self.get_price()}"     # instantiating a new object book1 = Book("Americanah", " Chimamanda Adichie", 2016, 6000) book2 = Book("Teller of secrets", "Bisi Adjapon", 2021, 5000) book3 = Book("Stay with me", "Ayobami Adebayo", 2017, 4000) # modifying price using setter book1._Book__price         self.year = year         # private attribute         self.__price = price     # getter method     def get_price(self):         return self.__price       # setter method     def set_price(self, price):         self.__price = price
Code language: Python (python)

Output

Book: Teller of secrets, Author: Bisi Adjapon, Year: 2021, Price: 4000
Code language: Python profile (profile)

Inheritance

Inheritance is considered the most fundamental principle of object-oriented programming. Inheritance refers to the ability of one class to derive its methods and attributes from another class. 

In this case, the class that derives the attribute is known as the child class, while the class from which the child class derives its attributes is known as the parent class. The primary purpose of inheritance is to aid the reusability of code. 

The child class inherits all the attributes and functions of the parent class. Therefore, we do not have to write the same lines of code repeatedly. We can also add more features without changing the class.

How inheritance works

To demonstrate, we’ll use our book example. A book is a class with common attributes like title, author, price, and year of publication. This holds true for both fiction and nonfiction books — which means that both types of books will inherit those particular attributes.

Using the bookstore example, we can add a Fiction and a Nonfiction class, which will inherit the title, author, year, and price attributes.

class Book:     def __init__(self, title, author, year, price):         # public data         self.title =  title         self.author = author         self.year = year         # private attribute         self.__price = price     # getter method     def get_price(self):         return self.__price       # setter method     def set_price(self, price):         self.__price = price     def __repr__(self):         return f"Book: {self.title}, Author: {self.author}, Year: {self.year}, Price: {self.get_price()}"     # child class class Fiction(Book):     def __init__(self, title, author, year, price):         super().__init__(title, author, year, price) # child class class Non_fiction(Book):     def __init__(self, title, author, year, price):         super().__init__(title, author, year, price) # instantiating a new object fiction1 = Fiction("Stay with me", "Ayobami Adebayo", 2017, 4000) non_fiction1 = Non_fiction("There Was a Country", "Chinua Achebe", 2012, 6000) print(fiction1)
Code language: Python (python)

When you run your terminal, you should get the following output:

Book: Stay with me, Author: Ayobami Adebayo, Year: 2017, Price: 4000
Code language: Python profile (profile)

Polymorphism

Polymorphism is another fundamental concept in Python programming. In literal terms, polymorphism refers to the occurrence of a similar thing in various forms. Polymorphism in Python refers to the ability of an object, class, or method to take different forms at different instances. A subclass, also known as a child class, can adopt a method of its parent class through polymorphism.

How polymorphism works

In polymorphism, classes can implement inherited methods in different ways. This enables us to define methods in a subclass with the same name as in its parent class. In some situations, the subclass may modify its parent class’s method where the parent class’s method does not fit. In this case, the method must be reimplemented in the child class.

For a better understanding, let us work with the bookstore example again:

class Book:     def __init__(self, title, author, year, price):         # public data         self.title =  title         self.author = author         self.year = year         # private attribute         self.__price = price     # getter method     def get_price(self):         return self.__price       # setter method     def set_price(self, price):         self.__price = price     def __repr__(self):         return f"Book: {self.title}, Author: {self.author}, Year: {self.year}, Price: {self.get_price()}"     # child class class Fiction(Book):     def __init__(self, title, author, year, price):         super().__init__(title, author, year, price)     def __repr__(self):         return f"Book: {self.title}, Author: {self.author}, Year:  {self.year}, Price: {self.get_price()}" # instantiating a new object  fiction1 = Fiction("Stay with me", "Ayobami Adebayo", 2017, 4000) print(fiction1)
Code language: Python (python)

Output

Book: Stay with me, Author: Ayobami Adebayo, Year: 2017, Price: 4000
Code language: Python profile (profile)

In the code above, the parent class, Book, contains the repr method, which returns the string representation of an object. The Fiction subclass also uses this method; it is invoked whenever an object is printed.

In addition, when the child class inherits a method from the parent class, polymorphism allows us to modify the method in the child class to fit its needs. This process of modification is known as the overriding method.

Here is an example:

class MobileDevice:     def __init__(self, name, color, price):         self.name = name         self.color = color         self.price = price     def details(self):         print(f"Details: {self.name}, Color: {self.color}, Price: {self.price}")     def battery(self):         print("Mobile device has one battery")     def camera(self):         print("Mobile phones have dual camera") class Iphone(Mobile_device):     def details(self):         print(f"Details: {self.name}, Color: {self.color}, Price: {self.price}")     def battery(self):         print("Mobile device has one battery")     def camera(self):         print("Mobile device has three cameras")     mobile_device = Mobile_device('Pixel 6','Gold', 50000 ) mobile_device.details() mobile_device.battery() mobile_device.camera() ios = Iphone('iPhone 13 Pro','Green', 65000) ios.details() ios.battery() ios.camera()
Code language: Python (python)

Output

Details: Pixel 6, Color: Gold, Price: 50000 Mobile device has one battery Mobile phones have dual camera Details: iPhone 13 Pro, Color: Green, Price: 65000 Mobile device has one battery Mobile device has three cameras
Code language: Python (python)

As a result of polymorphism, the child class (Iphone) overrides the camera() method inherited from its parent class.

Wrapping up

In this tutorial, we introduced the concept of objects and classes in Python and the fundamental principles of object-oriented programming.

These concepts do not only apply to Python. Object-oriented programming applies to most programming languages, such as Java, C#, C++, JavaScript, etc. However, their implementation differs according to the language.

I hope this tutorial was of help to you.

Happy Coding! 🙂

Anita Achu is a software developer and technical writer passionate about creating technical content to aid developers to learn about software development tools and how to use these tools in building and providing solutions to problems.