Python Object Oriented Programming

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 29

A Beginner’s Guide to Python

Object-Oriented Programming
(OOP)

Downloaded on: 03 October 2023


Ship and manage your
web projects faster
Deploy your projects on Google Cloud Platform's top tier
infrastructure. You'll get 25+ data centers to choose
from, 24/7/365 expert support, and advanced security
with DDoS protection.

Try for free

Programming is an art. And as in art, selecting the proper brushes and paints is essential to
produce the best works. Python Object-Oriented Programming is one such skill.

Choosing the right programming language is a crucial part of any project, and it can lead
either to a fluid and enjoyable development or a complete nightmare. Hence, it would be best
if you used the best-fit language for your use case.

That’s the primary reason to learn object-oriented programming in Python, which is also one
of the most popular programming languages.

Let’s learn!

An Example Python Program


Before digging into the matter, let us pose a question: have you ever written a Python
program like the one below?
secret_number = 20

while True:
number = input('Guess the number: ')

try:
number = int(number)
except:
print('Sorry that is not a number')
continue

if number != secret_number:
if number > secret_number:
print(number, 'is greater than the secret number')

elif number < secret_number:


print(number, 'is less than the secret number')
else:
print('You guessed the number:', secret_number)
break

This code is a simple number guesser. Try to copy it in a Python file and run it in your system.
It perfectly accomplishes its purpose.

But here comes a huge problem: what if we asked you to implement a new feature? It could
be something simple — for instance:

“If the input is a multiple of the secret number, give the user a hint.”

The program would quickly grow complex and heavy as you increase the number of features
and, therefore, the total number of nested conditionals.

That’s precisely the problem object-oriented programming tries to solve.


Requirements to Learn Python OOP
Before heading into object-oriented programming, we strongly recommend you have a firm
grasp of Python basics.

Classifying topics considered “basic” can be difficult. Because of this, we’ve designed a cheat
sheet with all the main concepts needed to learn Object-Oriented programming in Python.

Variable: Symbolic name that points to a specific object (we’ll see what objects mean
through the article).

Arithmetic operators: Addition (+), subtraction (-), multiplication (*), division (/), integer
division (//), modulo (%).

Built-in data types: Numeric (integers, floats, complex), Sequences (strings, lists,
tuples), Boolean (True, False), Dictionaries, and Sets.

Boolean expressions: Expressions in which the result is True or False.

Conditional: Evaluates a boolean expression and does some process depending on


the result. Handled by if/else statements.

Loop: Repeated execution of code blocks. It can be for or while loops.

Functions: Block of organized and reusable code. You create them with the keyword
def.

Arguments: Objects passed to a function. For instance: sum([1, 2, 4])

Run a Python script: Open a terminal or command line and type “python <name of the
file>.”

Open a Python Shell: Open a terminal and type python or python3 depending on
your system.

Now you have these concepts crystal clear, you can move forward with understanding object-
oriented programming.
What Is Object-Oriented Programming in Python?
Object-Oriented Programming (OOP) is a programming paradigm in which we can think about
complex problems as objects.

A paradigm is a theory that supplies the base for solving problems.

So when we’re talking about OOP, we’re referring to a set of concepts and patterns we use to
solve problems with objects.

An object in Python is a single collection of data (attributes) and behavior (methods). You can
think of objects as real things around you. For example, consider calculators:

— A calculator can be an object.

As you may notice, the data (attributes) are always nouns, while the behaviors (method) are
always verbs.
This compartmentalization is the central concept of Object-Oriented Programming. You build
objects that store data and contain specific kinds of functionality.

Why Do We Use Object-Oriented Programming in Python?


OOP allows you to create secure and reliable software. Many Python frameworks and
libraries use this paradigm to build their codebase. Some examples are Django, Kivy, pandas,
NumPy, and TensorFlow.

Let’s see the main advantages of using OOP in Python.

Advantages of Python OOP

The following reasons will make you opt for using object-oriented programming in Python.

All Modern Programming Languages Use OOP

This paradigm is language-independent. If you learn OOP in Python, you’ll be able to use it in
the following:

Java
PHP (make sure to read the comparison between PHP and Python)
Ruby
Javascript
C#
Kotlin

All of these languages are either natively object-oriented or include options for object-oriented
functionality. If you want to learn any of them after Python, it’ll be easier — you’ll find many
similarities between languages working with objects.
OOP Allows You to Code Faster

Coding faster doesn’t mean writing fewer lines of code. It means you can implement more
features in less time without compromising the stability of a project.

Object-Oriented programming allows you to reuse code by implementing abstraction. This


principle makes your code more concise and legible.

As you may know, programmers spend much more time reading code than writing it. It’s the
reason legibility is always more important than getting features out as quickly as possible.

— Productivity decreases with not legible code

You’ll see more about the abstraction principle later.

OOP Helps You Avoid Spaghetti Code

Do you remember the number guesser program at the start of this article?
If you keep adding features, you’ll have many nested if statements in the future. This tangle of
endless lines of code is called spaghetti code, and you should avoid it as much as possible.

OOP gives us the possibility of compressing all the logic in objects, therefore avoiding long
pieces of nested if’s.

OOP Improves Your Analysis of Any Situation

Once you get some experience with OOP, you’ll be able to think of problems as small and
specific objects.

This understanding leads to a rapid project initialization.

Structured Programming vs Object-Oriented Programming

Structured programming is the most-used paradigm by beginners because it is the simplest


way to build a small program.

It involves running a Python program sequentially. That means you’re giving the computer a
list of tasks and then executing them from top to bottom.

Let’s see an example of structured programming with a coffee shop program.

small = 2
regular = 5
big = 6

user_budget = input('What is your budget? ')

try:
user_budget = int(user_budget)
except:
print('Please enter a number')
exit()

if user_budget > 0:
if user_budget >= big:
print('You can afford the big coffee')
if user_budget == big:
print('It\'s complete')
else:
print('Your change is', user_budget - big)
elif user_budget == regular:
print('You can afford the regular coffee')
print('It\'s complete')
elif user_budget >= small:
print('You can buy the small coffee')
if user_budget == small:
print('It\'s complete')
else:
print('Your change is', user_budget - small)

The code above acts as a coffee shop vendor. It’ll ask you for a budget, then “sell” you the
biggest coffee you’re capable of buying.

Try to run it in the terminal. It’ll execute step by step, depending on your input.

This code works perfectly, but we have three problems:

1. It has a lot of repeated logic.


2. It uses many nested if conditionals.
3. It’ll be hard to read and modify.

OOP was invented as a solution to all of these problems.

Let’s see the above program implemented with OOP. Don’t worry if you don’t understand it
yet. It’s only for comparing structured programming and object-oriented programming.
class Coffee:
# Constructor
def __init__(self, name, price):
self.name = name
self.price = float(price)
def check_budget(self, budget):
# Check if the budget is valid
if not isinstance(budget, (int, float)):
print('Enter float or int')
exit()
if budget < 0:
print('Sorry you don\'t have money')
exit()
def get_change(self, budget):
return budget - self.price

def sell(self, budget):


self.check_budget(budget)
if budget >= self.price:
print(f'You can buy the {self.name} coffee')
if budget == self.price:
print('It\'s complete')
else:
print(f'Here is your change {self.get_chan

exit('Thanks for your transaction')

Note: All the following concepts will be explained deeper through the article.

The above code represents a class named “Coffee.” It has two attributes — “name” and
“price” — and they’re both used in the methods. The primary method is “sell,” which
processes all the logic needed to complete the selling process.

If you try to run that class, you won’t get any output. It primarily occurs because we’re just
declaring the “template” for the coffees, not the coffees themselves.
Let’s implement that class with the following code:

small = Coffee('Small', 2)
regular = Coffee('Regular', 5)
big = Coffee('Big', 6)

try:
user_budget = float(input('What is your budget? '))
except ValueError:
exit('Please enter a number')

for coffee in [big, regular, small]:


coffee.sell(user_budget)

Here we’re making instances, or coffee objects, of the class “Coffee,” then calling the “sell”
method of each coffee until the user can afford any option.

We’ll get the same output with both approaches, but we can extend the program functionality
far better with OOP.

Below is a table comparing object-oriented programming and structured programming:

OOP Structured Programming


Easier to maintain Hard to maintain
Don’t Repeat Yourself (DRY) approach Repeated code in many places
Little pieces of code reused in many places A large amount of code in few places
Object approach Block code approach
Easier to debug Harder to debug
Big learning curve Simpler learning curve
Used in large projects Optimized to simple programs

To conclude the paradigm comparison:


Neither paradigm is perfect (OOP can be overwhelming to use in simple projects).
These are just two ways of solving a problem; there are others out there.
OOP is used in large codebases, while structured programming is mainly for simple
projects.

Let’s move on to built-in objects in Python.

Everything Is an Object in Python


We’ll tell you a secret: you’ve been using OOP all the time without noticing it.

Even when using other paradigms in Python, you still use objects to do almost everything.

That’s because, in Python, everything is an object.

Remember the definition of object: An object in Python is a single collection of data


(attributes) and behavior (methods).

That matches any data type in Python.

A string is a collection of data (characters) and behaviors (upper(), lower(), etc..). The same
applies to integers, floats, booleans, lists, and dictionaries.

Before continuing, let’s review the meaning of attributes and methods.

Attributes and Methods

Attributes are internal variables inside objects, while methods are functions that produce
some behavior.

Let’s do a simple exercise in the Python shell. You can open it by typing python or python3
in your terminal.
— Python shell

Now, let’s work with the Python shell to discover methods and types.

>>> kinsta = 'Kinsta, Premium Application, Database, and Managed WordPress


>>> kinsta.upper()
'KINSTA, PREMIUM APPLICATION, DATABASE, AND MANAGED WORDPRESS HOSTING'

In the second line, we’re calling a string method, upper(). It returns the content of the string
all in uppercase. However, it doesn’t change the original variable.

>>> kinsta
'Kinsta, Premium Application, Database, and Managed WordPress hosting'

Let’s delve into valuable functions when working with objects.

The type() function allows you to get the type of an object. The “type” is the class to which the
object belongs.
>>> type(kinsta)
# class 'str'

The dir() function returns all the attributes and methods of an object. Let’s test it out with the
kinsta variable.

>>> dir(kinsta)
['__add__', '__class__', ........... 'upper', 'zfill']

Now, try to print some of the hidden attributes of this object.

>>> kinsta.__class__ # class ‘str’ e>

This will output the class the object kinsta belongs to. So we can say the only thing the type
function returns is the __class__ attribute of an object.

You can experiment with all the data types, discovering all of their attributes and methods
directly on the terminal. You can learn more about the built-in data types in the official
documentation.
Your First Object in Python
A class is like a template. It allows you to create custom objects based on the attributes and
methods you define.

You can think of it as a cookie-cutter that you modify to bake the perfect cookies (objects,
not tracking cookies), with defined characteristics: Shape, Size, and more.

On the other hand, we have instances. An instance is an individual object of a class, which
has a unique memory address.

— Instances in Python

Now that you know what classes and instances are, let’s define some!

To define a class in Python, you use the class keyword, followed by its name. In this case,
you’ll create a class named Cookie.

Note: In Python, we use the camel case name convention to name classes.
class Cookie:
pass

Open your Python shell and type the code above. To create an instance of a class, just type
its name and parenthesis after it. It’s the same process as invoking a function.

cookie1 = Cookie()

Congratulations — you’ve just created your first object in Python! You can check its id and
type with the following code:

id(cookie1)
140130610977040 # Unique identifier of the object

type(cookie1)
<class '__main__.Cookie'>

As you can see, this cookie has a unique identifier in memory, and its type is Cookie.

You can also check if an object is an instance of a class with the isinstance() function.
isinstance(cookie1, Cookie)
# True
isinstance(cookie1, int)
# False
isinstance('a string', Cookie)
# False

Constructor Method

The __init__() method is also named “constructor.” It’s called Python each time we instantiate
an object.

The constructor creates the object’s initial state with the minimum set of parameters it needs
to exist. Let’s modify the Cookie class, so it accepts parameters in its constructor.

class Cookie:
# Constructor
def __init__(self, name, shape, chips='Chocolate'):
# Instance attributes
self.name = name
self.shape = shape
self.chips = chips

In the Cookie class, every cookie must have a name, shape, and chips. We’ve defined the
last one as “Chocolate.”

On the other hand, self refers to the instance of the class (the object itself).

Try to paste the class in the shell and create an instance of the cookie as usual.
cookie2 = Cookie()
# TypeError

You’ll get an error. That’s because you must provide the minimal set of data the object needs
to live — in this case, name and shape since we’ve already set chips to “Chocolate.”

cookie2 = Cookie('Awesome cookie', 'Star')

To access the attributes of an instance, you must use the dot notation.

cookie2.name
# 'Awesome cookie'
cookie2.shape
# 'Star'
cookie2.chips
# 'Chocolate'

For now, the Cookie class doesn’t have anything too juicy. Let’s add a sample method bake()
to make things more interesting.
class Cookie:
# Constructor
def __init__(self, name, shape, chips='Chocolate'):
# Instance attributes
self.name = name
self.shape = shape
self.chips = chips

# The object is passing itself as a parameter


def bake(self):
print(f'This {self.name}, is being baked with the shape {self.shape} and c
print('Enjoy your cookie!')

To call a method, use the dot notation and invoke it as a function.

cookie3 = Cookie('Baked cookie', 'Tree')


cookie3.bake()
# This Baked cookie, is being baked with the shape Tree and chips of Choco
Enjoy your cookie!

The 4 Pillars of OOP in Python


Object-Oriented Programming includes four main pillars:

1. Abstraction

Abstraction hides the internal functionality of an application from the user. The user could be
either the end client or other developers.
We can find abstraction in our daily lives. For example, you know how to use your phone,
but you probably don’t know exactly what’s happening inside it each time you open an app.

Another example is Python itself. You know how to use it to build functional software, and you
can do it even if you don’t understand Python’s inner workings.

Applying the same to code allows you to collect all the objects in a problem and abstract
standard functionality into classes.

2. Inheritance

Inheritance allows us to define multiple subclasses from an already defined class.

The primary purpose of it is to follow the DRY principle. You’ll be able to reuse a lot of code
by implementing all the sharing components into superclasses.

You can think of it as the real-life concept of genetic inheritance. Children (subclass) are the
result of inheritance between two parents (superclasses). They inherit all the physical
characteristics (attributes) and some common behaviors (methods).

3. Polymorphism

Polymorphism lets us slightly modify methods and attributes of the subclasses previously
defined in the superclass.

The literal meaning is “many forms.” That’s because we build methods with the same name
but different functionality.

Going back to the previous idea, children are also a perfect example of polymorphism. They
can inherit a defined behavior get_hungry() but in a slightly different way, for instance,
getting hungry every 4 hours instead of every 6.

4. Encapsulation

Encapsulation is the process in which we protect the internal integrity of data in a class.
Although there isn’t a private statement in Python, you can apply encapsulation by using
mangling in Python. There are special methods named getters and setters that allow us to
access unique attributes and methods.

Let’s imagine a Human class that has a unique attribute named _height. You can modify this
attribute only within certain constraints (it’s nearly impossible to be higher than 3 meters).

Build an Area Shape Resolver Calculator


One of the best things about Python is that it lets us create a wide variety of software, from a
CLI (command-line interface) program to a complex web app.

Now that you’ve learned the pillar concepts of OOP, it’s time to apply them to an actual
project.

Note: All of the following code will be available inside this GitHub repository. A code revision
tool that helps us to manage code versions with Git.

Your task is to create an area calculator of the following shapes:

Square
Rectangle
Triangle
Circle
Hexagon

Shape Base Class

Firstly, create a file calculator.py and open it. Since we already have the objects to work
with, it’ll be easy to abstract them in a class.

You can analyze the common characteristics and find out that all of these are 2D shapes.
Therefore, the best option is to create a class Shape with a method get_area() from which
each shape will inherit.
Note: All the methods should be verbs. That’s because this method is named get_area() and
not area().

class Shape:
def __init__(self):
pass

def get_area(self):
pass

The code above defines the class; however, there isn’t anything interesting in it yet.

Let’s implement the standard functionality of most of these shapes.

class Shape:
def __init__(self, side1, side2):
self.side1 = side1
self.side2 = side2

def get_area(self):
return self.side1 * self.side2

def __str__(self):
return f'The area of this {self.__class__.__name__} is: {self.get_area()}'

Let’s break down what we’re doing with this code:

In the __init__ method, we’re requesting two parameters, side1 and side2. These will
remain as instance attributes.
The get_area() function returns the area of the shape. In this case, it’s using the formula
of area of a rectangle since it’ll be easier to implement with other shapes.
The __str__() method is a “magic method” just as __init__(). It allows you to modify the
way an instance will print.
The self.__class__.__name__ hidden attribute refers to the name of the class. If you
were working with a Triangle class, that attribute would be “Triangle.”

Rectangle Class

Since we implemented the formula of area of the Rectangle, we could create a simple
Rectangle class that does nothing but inherit from the Shape class.

To apply inheritance in Python, you’ll create a class as usual and surround the superclass
you want to inherit from by parenthesis.

# Folded base class


class Shape: ...

class Rectangle(Shape): # Superclass in Parenthesis


pass

Square Class

We can take an excellent approach to polymorphism with the Square class.

Remember that a square is just a rectangle whose four sides are all equal. That means we
can use the same formula to get the area.

We can do this by modifying the init method, accepting only a side as a parameter, and
passing that side value to the constructor of the Rectangle class.
# Folded classes
class Shape: ...
class Rectangle(Shape): ...

class Square(Rectangle):
def __init__(self, side):
super().__init__(side, side)

As you can see, the super function passes the side parameter twice to the superclass. In
other words, it’s passing side both as side1 and side2 to the previously defined constructor.

Triangle Class

A triangle is half as big as the rectangle that surrounds it.

— Relation between triangles and rectangles


(Image source: Varsity tutors).

Therefore, we can inherit from the Rectangle class and modify the get_area method to
match the triangle area formula, which is one-half of the base multiplied by the height.
# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...

class Triangle(Rectangle):
def __init__(self, base, height):
super().__init__(base, height)

def get_area(self):
area = super().get_area()
return area / 2

Another use case of the super() function is to call a method defined in the superclass and
store the result as a variable. That’s what’s happening inside the get_area() method.

Circle Class

You can find the circle area with the formula ?r², where r is the circle’s radius. That means we
have to modify the get_area() method to implement that formula.

Note: We can import the approximate value of ? from the math module

# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...
class Triangle(Rectangle): …

# At the start of the file


from math import pi

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

def get_area(self):
return pi * (self.radius ** 2)

The code above defines the Circle class, which uses a different constructor and get_area()
methods.

Although Circle inherits from the Shape class, you can redefine every single method and
attribute it to your liking.

Regular Hexagon Class

We only need the length of a side of a regular hexagon to calculate its area. It’s similar to the
Square class, where we only pass an argument to the constructor.

— Hexagon area formula (Image source:


BYJU’S)
However, the formula is quite different, and it implies the use of a square root. That’s why
you’ll use the sqrt() function from the math module.

# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...
class Triangle(Rectangle): …
class Circle(Shape): …

# Import square root


from math import sqrt

class Hexagon(Rectangle):

def get_area(self):
return (3 * sqrt(3) * self.side1 ** 2) / 2

Testing Out Our Classes

You can enter an interactive mode when running a Python file using a debugger. The simplest
way to do this is by using the built-in breakpoint function.

Note: This function is only available in Python 3.7 or newer.

from math import pi, sqrt


# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...
class Triangle(Rectangle): …
class Circle(Shape): …
class Hexagon(Rectangle): …

breakpoint()

Now, run the Python file and play around with the classes you created.

$ python calculator.py

(Pdb) rec = Rectangle(1, 2)(Pdb) print(rec)


The area of this Rectangle is: 2
(Pdb) sqr = Square(4)
(Pdb) print(sqr)
The area of this Square is: 16
(Pdb) tri = Triangle(2, 3)
(Pdb) print(tri)
The area of this Triangle is: 3.0
(Pdb) cir = Circle(4)
(Pdb) print(cir)
The area of this Circle is: 50.26548245743669
(Pdb) hex = Hexagon(3)
(Pdb) print(hex)
The area of this Hexagon is: 23.382685902179844

Challenge

Create a class with a method run where the user can choose a shape and calculate its area.

When you’ve completed the challenge, you can send a pull request to the GitHub repo or
publish your solution in the comment section.
Summary
Object-oriented programming is a paradigm in which we solve problems by thinking of them
as objects. If you understand Python OOP, you can also apply it easily in languages like
Java, PHP, Javascript, and C#.

In this article, you’ve learned about:

The concept of object-oriented in Python


Advantages of object-oriented over structured programming
Basics of object-oriented programming in Python
Concept of classes and how to use them in Python
The constructor of a class in Python
Methods and attributes in Python
The four pillars of OOP
Implementing abstraction, inheritance, and polymorphism in a project

Now it’s over to you!

If you liked this guide, check out our post on Python Tutorials.

Let us know your solution to the challenge below in the comments! And don’t forget to check
out our comparison guide between Python and PHP.

You might also like