AMAN UL HAQ
Object Oriented Programming in Python:
Introduction
Object-Oriented Programming (OOP) is a programming paradigm
where different components of a computer program are modelled
after real-world objects. An object is anything that has some
characteristics and can perform a function.
Consider a scenario where you have to develop a Formula 1 car
racing game using the object-oriented programming approach. The
first thing you need to do is to identify real-world objects in the
actual Formula 1 race. What are the entities in a Formula 1 race that
have some characteristics and can perform any function? One of the
obvious answers to this question is the car. A car can have
characteristics like engine capacity, make, model, manufacturer, and
so on. Similarly, a car can be started, stopped, accelerated and so on.
A driver can be another object in a Formula 1 race. A driver has a
nationality, age, gender, and so on, and he can perform
functionalities like driving the car, moving the steering or changing
the transmission.
Just like in this example, in object-oriented programming we will
create objects for the corresponding real-world entity.
It is important to mention here that object-oriented programming is
not a language-dependent concept. It is a general programming
concept and most of the modern languages, such as Java, C#, C++,
and Python, support object-oriented programming. In this article, we
will see a detailed introduction to Object-Oriented Programming in
Python, but before that, we will see some of the advantages and
disadvantages of object-oriented programming.
AMAN UL HAQ
Pros and Cons of OOP
Following are some of the advantages of object-oriented
programming:
Object-oriented programming fosters reusability. A computer
program is written in the form of objects and classes, which can
be reused in other projects as well.
The modular approach used in object-oriented programming
results in highly maintainable code.
In object-oriented programming, every class has a specific task.
If an error occurs in one part of the code, you can rectify it
locally without having to affect other parts of the code.
Data encapsulation (which we will study later in the article)
adds an extra layer of security to the program developed using
the object-oriented approach.
Though object-oriented programming has several advantages as
discussed, it has some downsides as well, some of which have been
enlisted below:
Detailed domain knowledge of the software being developed is
needed in order to create objects. Not every entity in software
is a candidate for being implemented as an object. It can be
hard for newbies to identify this fine line.
As you add more and more classes to the code, the size and
complexity of the program grows exponentially.
In the next section, we will see some of the most important concepts
of object-oriented programming.
As the name suggests, object-oriented programming is all about
objects. However, before an object can be created we need to define
the class for the object.
AMAN UL HAQ
Class:
A class in object-oriented programming serves as a blueprint for the
object. A class can be considered as a map for the house. You can get
an idea of what the house looks like by simply seeing the map.
However, a class itself is nothing. For instance, a map is not a house,
it only explains how the actual house will look.
The relationship between a class and object can be understood by
looking at the relationship between a car and an Audi. An Audi is
actually a car. However, there is no such thing as a car only. A car is
an abstract concept, it is actually implemented in the form of Toyota,
Ferrari, Honda, etc.
The keyword class is used in order to create a class in Python. The
name of the class follows the class keyword, followed by the colon
character. The body of the class starts on a new line, indented one
tab from the left.
Let's see how we can create a very basic class in Python. Take a look
at the following code:
# Creates class Car
class Car:
# create class attributes
name = "c200"
make = "mercedez"
model = 2008
# create class methods
def start(self):
print ("Engine started")
def stop(self):
print ("Engine switched off")
AMAN UL HAQ
In the example above, we create a class named Car with three
attributes: name, make, and model. The car class also contains two
methods: start() and stop().
AMAN UL HAQ
Objects:
Earlier, we said that a class provides a blueprint. However, to actually
use the objects and methods of a class, you need to create
an object out of that class. There are few class methods and
attributes that can be used without an object, which we will see in
the later section. For now, just keep in mind that by default, we need
to create an object of a class before we can use its methods and
attributes.
An object is also called an instance; therefore, the process of creating
an object of a class is called instantiation. In Python, to create an
object of a class we simply need to write the class name followed by
opening and closing parenthesis.
Let's create an object of the Car class that we created in the last
section.
# Creates car_a object of Car class
car_a = Car()
# Creates car_b object of car class
car_b = Car()
In the script above, we created two objects of the car
class: car_a and car_b. To check the type of the objects we created,
we can use the type method and pass it the name of our object.
Execute the following script:
print ( type (car_b))
In the output, you will see:
<class '__main__.Car'>
AMAN UL HAQ
: Which says that the type of car_b object is a class Car.
At this point we've created our class and the corresponding objects.
Now is the time to access class attributes and call class method using
the class object. To do so, you simply have to write the object name,
followed by dot operator and the name of the attribute or the
method that you want to access or call, respectively. Take a look at
the following example
car_b.start()
In the script above, we call the start() method via the car_b object.
The output will be as follows:
Engine started
Similarly, you can access an attribute using the following syntax:
print (car_b.model)
In the output, you will see the value of the model attribute, as shown
below:
2008
AMAN UL HAQ
Attributes:
In the previous section, we saw how we can create objects of a class
and can use those objects to access the attributes of a class.
In Python, every object has some default attributes and methods in
addition to user-defined attributes. To see all the attributes and
methods of an object, the built-in dir() function can be used. Let's try
to see all the attributes of the car_b object that we created in the
last section. Execute the following script:
dir (car_b)
In the output, you will see the following attributes:
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
AMAN UL HAQ
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'make',
'model',
'name',
'start',
'stop']
This built-in function is useful for inspecting all of the attributes and
functions of an object, especially when used via Python's REPL.
AMAN UL HAQ
Class vs Instance Attributes:
Attributes can be broadly categorized into two types: Class attributes
and Instance attributes. Class attributes are shared by all the objects
of a class while instance attributes are the exclusive property of the
instance.
Remember, an instance is just another name for the object. Instance
attributes are declared inside any method while class attributes are
declared outside of any method. The following example clarifies the
difference:
class Car:
# create class attributes
car_count = 0
# create class methods
def start(self, name, make, model):
print ( "Engine started" )
[Link] = name
[Link] = make
[Link] = model
Car.car_count += 1
In the script above, we create a class Car with one class
attribute car_count and three instance
attributes name, make and mode. The class contains one
method start() which contains the three instance attributes. The
values for the instance attributes are passed as arguments to
the start() method. Inside the start method, the car_count attribute
is incremented by one.
AMAN UL HAQ
It is important to mention that inside the method, the instance
attributes are referred using the self keyword, while class attributes
are referred by the class name.
Let's create an object of the Car class and call the start() method.
car_a = Car()
car_a.start( "Corrola" , "Toyota" , 2015 )
print (car_a.name)
print (car_a.car_count)
In the above script we print the instance attribute name and class
attribute car count. You will see in the output that the car
count attribute will have a value of 1, as shown below:
Engine started
Corrola
Now, let's create another object of the car class and call
the start() method.
car_b = Car()
car_b.start( "City" , "Honda" , 2013 )
print (car_b.name)
print (car_b.car_count)
AMAN UL HAQ
Now if you print the value of the car count attribute, you will see 2 in
the output. This is because the car count attribute is a class attribute
and hence it is shared between the instances. The car_a object
incremented its value to 1, while car_b object incremented it again,
hence the final value became 2. The output looks like this:
Engine started
City
2
AMAN UL HAQ
Methods:
As we described earlier, in object-oriented programming, the
methods are used to implement the functionalities of an object. In
the previous section, we created start() and stop() methods for
the car class. Till now, we have been using the objects of a class in
order to call the methods. However, there is a type of method that
can be called directly using the class name. Such a method is called
a static method.
Static Methods:
To declare a static method, you have to specify
the @staticmethod descriptor before the name of the method as
shown below:
class Car:
@staticmethod
def get_class_details():
print ( "This is a car class" )
Car.get_class_details()
In the above script, we create a class Car with one static
method get_class_details(). Let's call this method using the class
name.
Car.get_class_details()
You can see that we did not need to create an instance of
the Car class in order to call the get_class_details() method, rather
AMAN UL HAQ
we simply used the class name. It is important to mention that static
methods can only access class attributes in Python.
Returning Multiple Values from a Method:
One of the best features of the Python language is the ability of class
methods to return multiple values. Take a look at the following
example:
class Square:
@staticmethod
def get_squares(a, b):
return a*a, b*b
print (Square.get_squares( 3 , 5 ))
In the above script, we created a class named Square with one static
method get_squares(). The method takes two parameters; multiply
each parameter with itself and returns both the results
using return statement. In the output of the script above, you will
see the squares of 3 and 5.
The str Method:
Till now we have been printing attributes using the print() method.
Let's see what happens if we print the object of a class.
To do so we'll create a simple Car class with one method and try to
print the object of the class to the console. Execute the following
script:
class Car:
AMAN UL HAQ
# create class methods
def start(self):
print ("Engine started")
car_a = Car()
print(car_a)
In the script above we create car_a object of the Car class and print
its value on the screen. Basically here we are treating car_a object as
a string. The output looks likes this:
<__main__.Car object at 0x000001CCCF4335C0>
The output shows the memory location where our object is stored.
Every Python object has a __str__ method by default. When you use
the object as a string, the __str__ method is called, which by default
prints the memory location of the object. However, you can provide
your own definition for the __str__ method as well. For instance,
look at the following example:
# Creates class Car
class Car:
# create class methods
def __str__(self):
return "Car class Object"
def start(self):
print ( "Engine started" )
car_a = Car()
AMAN UL HAQ
print (car_a)
In the script above, we override the __str__ method by providing our
own custom definition for the method. Now, if you print
the car_a object, you will see the message "Car class Object" on the
console. This is the message that we printed inside our custom
the __str__ method.
Using this method you can create custom and more meaningful
descriptions for when an object is printed. You could even display
some of the data within the class, like the name of a Person class.
AMAN UL HAQ
Constructors:
A constructor is a special method that is called by default whenever
you create an object of a class.
To create a constructor, you have to create a method with
keyword __init__. Take a look at the following example:
class Car:
# create class attributes
car_count = 0
# create class methods
def __init__(self):
Car.car_count += 1
print (Car.car_count)
In the script above, we create a Car class with one class
attribute car_count. The class contains a constructor which
increments the value of car_count and prints the resultant value on
screen.
Now, whenever an object of the Car class will be created the
constructor will be called, the value of the car_count will be
incremented and displayed on the screen. Let's create a simple
object and see what happens:
car_a = Car()
car_b = Car()
car_c = Car()
AMAN UL HAQ
In the output, you will see a value of 1, 2, and 3 printed since with
every object the value of car_count variable is incremented and
displayed on the screen.
Except for the name, the constructor can be used as an ordinary
method. You can pass and receive values from a constructor. It is
usually used in this way when you want to initialize attribute values
upon instantiating the class.
AMAN UL HAQ
Local vs Global Variables:
We know that there are two types of Python attributes, instance
attributes, and class attributes. The attributes of a class are also
referred to as variables. Depending on the scope, variables can also
be categorized into two types: Local variables and Global variables.
Local Variables:
A local variable in a class is a variable that can only be accessed
inside the code block where it is defined. For instance, if you define a
variable inside a method, it cannot be accessed anywhere outside
that method. Look at the following script:
# Creates class Car
class Car:
def start(self):
message = "Engine started"
return message
In the script above we create a local variable message inside
the start() method of the Car class. Now let's create an object of
the Car class and try to access the local variable message as shown
below:
car_a = Car()
print (car_a.message)
The above script will return the following error:
AttributeError: 'Car' object has no attribute 'message'
AMAN UL HAQ
This is because we cannot access the local variable outside the block
in which the local variable is defined.
Global Variable:
A global variable is defined outside of any code block e.g method, if-
statements, etc. A global variable can be accessed anywhere in the
class. Take a look at the following example.
# Creates class Car
class Car:
message1 = "Engine started"
def start(self):
message2 = "Car started"
return message2
car_a = Car()
print (car_a.message1)
In the script above, we created a global variable message1 and
printed its value on the screen. In the output, you will see the value
of the message1 variable, printed without an error.
It is important to mention that there is a difference between class
and instance attributes, and local vs global variables. The class and
instance attributes differ in the way they are accessed i.e. using class
name and using instance name. On the other hand, local vs global
variables differ in their scope, or in other words the place where they
can be accessed. A local variable can only be accessed inside the
method. Though in this article, both the local variable and instance
attributes are defined inside the method, local attribute is defined
with the self-keyword.
AMAN UL HAQ
Access Modifiers
The access modifiers in Python are used to modify the default scope
of variables. There are three types of access modifiers in Python:
public, private, and protected.
Variables with the public access modifiers can be accessed anywhere
inside or outside the class, the private variables can only be accessed
inside the class, while protected variables can be accessed within the
same package.
To create a private variable, you need to prefix double underscores
with the name of the variable. To create a protected variable, you
need to prefix a single underscore with the variable name. For public
variables, you do not have to add any prefixes at all.
Let's see public, private, and protected variables in action. Execute
the following script:
class Car:
def __init__(self):
print ( "Engine started" )
[Link] = "corolla"
self.__make = "toyota"
self._model = 1999
In the script above, we create a simple Car class with a constructor
and three variables name, make, and model. The name variable is
public while the make and model variables have been declared
private and protected, respectively.
Let's create an object of the Car class and try to access
the name variable. Execute the following script:
AMAN UL HAQ
car_a = Car()
print (car_a.name)
Since name is a public variable, therefore we can access it outside
the class. In the output, you will see the value for the name printed
on the console.
Now let's try to print the value of the make variable. Execute the
following script:
print (car_a.make)
In the output, you will see the following error message:
AttributeError: 'Car' object has no attribute 'make'
We have covered most of the basic object-oriented programming
concepts in the last few sections. Now, let's talk about the pillars of
the object-oriented programming: Polymorphism, Inheritance, and
Encapsulation, collectively referred to as PIE.
AMAN UL HAQ
Inheritance:
Inheritance in object-oriented programming is pretty similar to real-
world inheritance where a child inherits some of the characteristics
from his parents, in addition to his/her own unique characteristics.
In object-oriented programming, inheritance signifies an IS-A
relation. For instance, a car is a vehicle. Inheritance is one of the
most amazing concepts of object-oriented programming as it fosters
code re-usability.
The basic idea of inheritance in object-oriented programming is that
a class can inherit the characteristics of another class. The class
which inherits another class is called the child class or derived class,
and the class which is inherited by another class is called parent or
base class.
Let's take a look at a very simple example of inheritance. Execute the
following script:
# Create Class Vehicle
class Vehicle:
def vehicle_method(self):
print ( "This is parent Vehicle class method" )
# Create Class Car that inherits Vehicle
class Car(Vehicle):
def car_method(self):
print ( "This is child Car class method" )
In the script above, we create two classes Vehicle class, and
the Car class which inherits the Vehicle class. To inherit a class, you
simply have to write the parent class name inside the parenthesis
that follows the child class name. The Vehicle class contains a
method vehicle_method() and the child class contains a
AMAN UL HAQ
method car_method(). However, since the Car class inherits
the Vehicle class, it will also inherit the vehicle_method().
Let's see this in action. Execute the following script:
car_a = Car()
car_a.vehicle_method() # Calling parent class method
In the script above, we create an object of the Car class and call
the vehicle_method() using that Car class object. You can see that
the Car class doesn't have any vehicle_method() but since it has
inherited the Vehicle class that contains the vehicle_method(), the
car class can also use it. The output looks likes this:
This is parent Vehicle class method
In Python, a parent class can have multiple children and similarly, a
child class can have multiple parent classes. Let's take a look at the
first scenario. Execute the following script:
# Create Class Vehicle
class Vehicle:
def vehicle_method(self):
print ( "This is parent Vehicle class method" )
# Create Class Car that inherits Vehicle
class Car(Vehicle):
def car_method(self):
print ( "This is child Car class method" )
# Create Class Cycle that inherits Vehicle
class Cycle(Vehicle):
AMAN UL HAQ
def cycleMethod(self):
print ( "This is child Cycle class method" )
In the script above the parent Vehicle class is inherited by two child
classes Car and Cycle. Both the child classes will have access to
the vehicle_method() of the parent class. Execute the following script
to see that:
car_a = Car()
car_a.vehicle_method() # Calling parent class method
car_b = Cycle()
car_b.vehicle_method() # Calling parent class method
In the output, you will see the output of
the vehicle_method() method twice as shown below:
This is parent Vehicle class method
This is parent Vehicle class method
You can see how a parent class can be inherited by two child classes.
In the same way, a child can have multiple parents. Let's take a look
at the example:
class Camera:
def camera_method(self):
print ( "This is parent Camera class method" )
class Radio:
def radio_method(self):
AMAN UL HAQ
print ( "This is parent Radio class method" )
class CellPhone(Camera, Radio):
def cell_phone_method(self):
print ( "This is child CellPhone class method" )
In the script above, we create three classes: Camera, Radio,
and CellPhone. The Camera class and the Radio classes are inherited
by the CellPhoneclass which means that the CellPhone class will have
access to the methods of both Camera and Radio classes. The
following script verifies this:
cell_phone_a = CellPhone()
cell_phone_a.camera_method()
cell_phone_a.radio_method()
The output looks likes this:
This is parent Camera class method
This is parent Radio class method
AMAN UL HAQ
Polymorphism:
The term polymorphism literally means having multiple forms. In the
context of object-oriented programming, polymorphism refers to the
ability of an object to behave in multiple ways.
Polymorphism in programming is implemented via method-
overloading and method overriding.
Method Overloading:
Method overloading refers to the property of a method to behave in
different ways depending upon the number or types of the
parameters. Take a look at a very simple example of method
overloading. Execute the following script:
# Creates class Car
class Car:
def start(self, a, b=None):
if b is not None :
print (a + b)
else :
print (a)
In the script above, if the start() method is called by passing a single
argument, the parameter will be printed on the screen. However, if
we pass 2 arguments to the start() method, it will add both the
arguments and will print the result of the sum.
Let's try with single argument first:
AMAN UL HAQ
car_a = Car()
car_a.start( 10 )
In the output, you will see 10. Now let's try to pass 2 arguments:
car_a.start( 10 , 20 )
In the output, you will see 30.
AMAN UL HAQ
Method Overriding:
Method overriding refers to having a method with the same name in
the child class as in the parent class. The definition of the method
differs in parent and child classes but the name remains the same.
Let's take a simple example method overriding in Python.
# Create Class Vehicle
class Vehicle:
def print_details(self):
print ( "This is parent Vehicle class method" )
# Create Class Car that inherits Vehicle
class Car(Vehicle):
def print_details(self):
print ( "This is child Car class method" )
# Create Class Cycle that inherits Vehicle
class Cycle(Vehicle):
def print_details(self):
print ( "This is child Cycle class method" )
In the script above the Car and Cycle classes inherit the Vehicle class.
The vehicle class has print_details() method, which is overridden by
the child classes. Now if you call the print_details() method, the
output will depend upon the object through which the method is
being called. Execute the following script to see this concept in
action:
car_a = Vehicle()
car_a. print_details()
car_b = Car()
AMAN UL HAQ
car_b.print_details()
car_c = Cycle()
car_c.print_details()
The output will look like this:
This is parent Vehicle class method
This is child Car class method
This is child Cycle class method
You can see that the output is different, although
the print_details() method is being called through derived classes of
the same base class. However, since the child classes have
overridden the parent class method, the methods behave differently.
AMAN UL HAQ
Encapsulation:
Encapsulation is the third pillar of object-oriented programming.
Encapsulation simply refers to data hiding. As a general principle, in
object-oriented programming, one class should not have direct
access to the data of the other class. Rather, the access should be
controlled via class methods.
To provide controlled access to class data in Python, the access
modifiers and properties are used. We have already seen access
modifiers, in this section, we will see properties in action.
Suppose we want to ensure that the car model should always be
between 2000 and 2018. If a user tries to enter a value less than
2000 for the car model, the value is automatically set to 2000 and if
the entered value is greater than 2018, it should be set to 2018. If
the value is between 2000 and 2018, it should not be changed. We
can create a property for the model attribute which implements this
logic as follows:
# Creates class Car
class Car:
# Creates Car class constructor
def __init__(self, model):
# initialize instance variables
[Link] = model
# Creates model property
@property
def model(self):
return self.__model
# Create property setter
@[Link]
def model(self, model):
if model < 2000 :
AMAN UL HAQ
self.__model = 2000
elif model > 2018 :
self.__model = 2018
else :
self.__model = model
def getCarModel(self):
return "The car model is " + str ([Link])
carA = Car( 2088 )
print ([Link]())
A property has three parts. You have to define the attribute, which
is model in the above script. Next, you have to define the property
for the attribute using the @property decorator. Finally, you have to
create property setter which is @[Link] descriptor in the
above script.
Now, if you try to enter a value greater than 2018 for the model
attribute, you will see that the value is set to 2018. Let's test this.
Execute the following script:
car_a = Car( 2088 )
print (car_a.get_car_model())
Here we are passing 2088 as the value for model, however if you
print the value for the model attribute via get_car_model() function,
you will see 2018 in the output.
AMAN UL HAQ
Conclusion:
we studied some of the most important object-oriented
programming concepts. Object-oriented programming is one of the
most famous and commonly used programming paradigms. The
importance of object-oriented programming is reflected by the fact
that most of the modern programming languages are either fully
object-oriented or support object-oriented programming.
(AMAN UL HAQ)