Python Object Oriented Programming
Python Object Oriented Programming
Object-Oriented Programming
(OOP)
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!
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')
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.
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.
Functions: Block of organized and reusable code. You create them with the keyword
def.
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.
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:
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.
The following reasons will make you opt for using object-oriented programming in Python.
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.
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.
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.
Once you get some experience with OOP, you’ll be able to think of problems as small and
specific objects.
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.
small = 2
regular = 5
big = 6
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.
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
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')
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.
Even when using other paradigms in Python, you still use objects to do almost everything.
A string is a collection of data (characters) and behaviors (upper(), lower(), etc..). The same
applies to integers, floats, booleans, lists, and dictionaries.
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.
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'
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']
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.”
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
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
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).
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.
Square
Rectangle
Triangle
Circle
Hexagon
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.
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()}'
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.
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
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): …
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.
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.
# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...
class Triangle(Rectangle): …
class Circle(Shape): …
class Hexagon(Rectangle):
def get_area(self):
return (3 * sqrt(3) * self.side1 ** 2) / 2
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.
breakpoint()
Now, run the Python file and play around with the classes you created.
$ python calculator.py
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#.
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.