You are on page 1of 24

Unit V

Classes and Objects


Python Classes/Objects

Python is an object oriented programming language.

Almost everything in Python is an object, with its properties and methods.

A Class is like an object constructor, or a "blueprint" for creating objects.

Create a Class

To create a class, use the keyword class:

Example

Create a class named MyClass, with a property named x:

class MyClass:
x=5

Create Object

Now we can use the class named MyClass to create objects:

Example

Create an object named p1, and print the value of x:

p1 = MyClass()
print(p1.x)

The __init__() Function

The examples above are classes and objects in their simplest form, and are not really useful
in real life applications.

To understand the meaning of classes we have to understand the built-in __init__() function.

All classes have a function called __init__(), which is always executed when the class is
being initiated.

Use the __init__() function to assign values to object properties, or other operations that are
necessary to do when the object is being created:
Example

Create a class named Person, use the __init__() function to assign values for name and age:

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

p1 = Person("John", 36)

print(p1.name)
print(p1.age)

Note: The __init__() function is called automatically every time the class is being used to
create a new object.

Object Methods

Objects can also contain methods. Methods in objects are functions that belong to the object.

Let us create a method in the Person class:

Example

Insert a function that prints a greeting, and execute it on the p1 object:

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

def myfunc(self):
print("Hello my name is " + self.name)

p1 = Person("John", 36)
p1.myfunc()

Note: The self parameter is a reference to the current instance of the class, and is used to
access variables that belong to the class.
The self Parameter

The self parameter is a reference to the current instance of the class, and is used to access
variables that belongs to the class.

It does not have to be named self , you can call it whatever you like, but it has to be the first
parameter of any function in the class:

Example

Use the words mysillyobject and abc instead of self:

class Person:
def __init__(mysillyobject, name, age):
mysillyobject.name = name
mysillyobject.age = age

def myfunc(abc):
print("Hello my name is " + abc.name)

p1 = Person("John", 36)
p1.myfunc()

Modify Object Properties

You can modify properties on objects like this:

Example

Set the age of p1 to 40:

p1.age = 40

Delete Object Properties

You can delete properties on objects by using the del keyword:

Example

Delete the age property from the p1 object:

del p1.age
Delete Objects

You can delete objects by using the del keyword:

Example

Delete the p1 object:

del p1

The pass Statement

class definitions cannot be empty, but if you for some reason have a class definition with no
content, put in the pass statement to avoid getting an error.

Example
class Person:
pass

Accessors and Mutators


Accessors and mutators are public member functions in a class that get (accessors) and set
(mutators) the values of class member functions. In other words, these are functions that
exist solely to set or get the value of a class member variable.

Accessor and Mutator methods


1. Accessor Method: This method is used to access the state of the object i.e, the data hidden in the
object can be accessed from this method. ...
2. Mutator Method: This method is used to mutate/modify the state of an object i.e, it alters the
hidden value of the data variable.
Python Scope
A variable is only available from inside the region it is created. This is called scope.

Local Scope
A variable created inside a function belongs to the local scope of that function, and can only
be used inside that function.
Example

A variable created inside a function is available inside that function:

def myfunc():
x = 300
print(x)

myfunc()

Function Inside Function


As explained in the example above, the variable x is not available outside the function, but it
is available for any function inside the function:

Example

The local variable can be accessed from a function within the function:

def myfunc():
x = 300
def myinnerfunc():
print(x)
myinnerfunc()

myfunc()

Global Scope
A variable created in the main body of the Python code is a global variable and belongs to
the global scope.

Global variables are available from within any scope, global and local.

Example

A variable created outside of a function is global and can be used by anyone:

x = 300

def myfunc():
print(x)

myfunc()

print(x)
Naming Variables
If you operate with the same variable name inside and outside of a function, Python will treat
them as two separate variables, one available in the global scope (outside the function) and
one available in the local scope (inside the function):

Example

The function will print the local x, and then the code will print the global x:

x = 300

def myfunc():
x = 200
print(x)

myfunc()

print(x)

Global Keyword
If you need to create a global variable, but are stuck in the local scope, you can use
the global keyword.

The global keyword makes the variable global.

Example

If you use the global keyword, the variable belongs to the global scope:

def myfunc():
global x
x = 300

myfunc()

print(x)

Also, use the global keyword if you want to make a change to a global variable inside a
function.

Example

To change the value of a global variable inside a function, refer to the variable by using
the global keyword:

x = 300

def myfunc():
global x
x = 200

myfunc()

print(x)

Operator Overloading in Python


The operator overloading in Python means provide extended meaning beyond their
predefined operational meaning. Such as, we use the "+" operator for adding two integers as
well as joining two strings or merging two lists. We can achieve this as the "+" operator is
overloaded by the "int" class and "str" class. The user can notice that the same inbuilt
operator or function is showing different behaviour for objects of different classes. This
process is known as operator overloading.
Example:
1. print (14 + 32)
2.
3. # Now, we will concatenate the two strings
4. print ("Good" + "Morning")
5.
6. # We will check the product of two numbers
7. print (23 * 14)
8.
9. # Here, we will try to repeat the String
10.print ("X Y Z " * 3)
Output:
46
GoodMorning
322
XYZXYZXYZ
How to Overload the Operators in Python?
Suppose the user has two objects which are the physical representation of a user-defined data
type class. The user has to add two objects using the "+" operator, and it gives an error. This
is because the compiler does not know how to add two objects. So, the user has to define the
function for using the operator, and that process is known as "operator overloading". The
user can overload all the existing operators by they cannot create any new operator. Python
provides some special functions, or we can say magic functions for performing operator
overloading, which is automatically invoked when it is associated with that operator. Such
as, when the user uses the "+" operator, the magic function __add__ will automatically
invoke in the command where the "+" operator will be defined.

When the user uses the operator on the user-defined data types of class, then a magic
function that is associated with the operator will be invoked automatically. The process of
changing the behaviour of the operator is as simple as the behaviour of the function or
method defined.
The user define methods or functions in the class and the operator works according to that
behaviour defined in the functions. When the user uses the "+" operator, it will change the
code of a magic function, and the user has an extra meaning of the "+" operator.
Program : Simply adding two objects.
Python program for simply using the overloading operator for adding two objects.
Example:
class example:
1. def __init__(self, X):
2. self.X = X
3.
4. # adding two objects
5. def __add__(self, U):
6. return self.X + U.X
7. object_1 = example( int( input( print ("Please enter the value: "))))
8. object_2 = example( int( input( print ("Please enter the value: "))))
9. print (": ", object_1 + object_2)
10.object_3 = example(str( input( print ("Please enter the value: "))))
11.object_4 = example(str( input( print ("Please enter the value: "))))
12.print (": ", object_3 + object_4)
Output:
Please enter the value: 23
Please enter the value: 21
: 44
Please enter the value: Good
Please enter the value: Morning
: GoodMorning

Python pickle
Python pickle module is used for serializing and de-serializing a Python object structure.
Any object in Python can be pickled so that it can be saved on disk. What pickle does is that
it “serializes” the object first before writing it to file. Pickling is a way to convert a python
object (list, dict, etc.)
In Python, pickling is the process by which Python objects are converted to byte
streams. Pickling is about serializing the object structure in python.
Python pickle module is used for serializing and de-serializing python object structures. The
process to converts any kind of python objects (list, dict, etc.) into byte streams (0s and 1s)
is called pickling or serialization or flattening or marshalling. We can converts the byte
stream (generated through pickling) back into python objects by a process called as
unpickling.
Why Pickle?: In real world sceanario, the use pickling and unpickling are widespread as
they allow us to easily transfer data from one server/system to another and then store it in a
file or database.
Precaution: It is advisable not to unpickle data received from an untrusted source as they
may pose security threat. However, the pickle module has no way of knowing or raise alarm
while pickling malicious data.
Only after importing pickle module we can do pickling and unpickling. Importing pickle can
be done using the following command −
import pickle
Pickle examples:
Pickle a simple dictionary −
import pickle
EmpID={1:"Zack",2:"53050",3:"IT",4:"38",5:"Flipkart"}
pickling_on=open("EmpID.pickle","wb")
pickle.dump(EmpID,pickling_on)
pickling_on.close()
Unpickle a dictionary −
import pickle
pickle_off=open("EmpID.pickle",'rb')
EmpID=pickle.load(pickle_off)
print(EmpID)
On running above script(unpickle) we get our dictionary back as we initialized earlier. Also,
please note because we are reading bytes here, we have used “rb” instead of “r”.
Output
{1: 'Zack', 2: '53050', 3: 'IT', 4: '38', 5: 'Flipkart'}
Pickle Exceptions
Below are some of the common exceptions raised while dealing with pickle module −
 Pickle.PicklingError: If the pickle object doesn’t support pickling, this exception is
raised.
 Pickle.UnpicklingError: In case the file contains bad or corrupted data.
 EOFError: In case the end of file is detected, this exception is raised.
Prons:
 Comes handy to save complicated data.
 Easy to use, lighter and doesn’t require several lines of code.
 The pickled file generated is not easily readable and thus provide some security.
Cons:
 Languages other than python may not able to reconstruct pickled python objects.
 Risk of unpickling data from malicious sources.

Python Try Except


The try block lets you test a block of code for errors.

The except block lets you handle the error.

The else block lets you execute code when there is no error.

The finally block lets you execute code, regardless of the result of the try- and except blocks.

Exception Handling

When an error occurs, or exception as we call it, Python will normally stop and generate an
error message.

These exceptions can be handled using the try statement:

Example

The try block will generate an exception, because x is not defined:

try:
print(x)
except:
print("An exception occurred")
Since the try block raises an error, the except block will be executed.

Without the try block, the program will crash and raise an error:

Example

This statement will raise an error, because x is not defined:

print(x)

Many Exceptions

You can define as many exception blocks as you want, e.g. if you want to execute a special
block of code for a special kind of error:

Example

Print one message if the try block raises a NameError and another for other errors:

try:
print(x)
except NameError:
print("Variable x is not defined")
except:
print("Something else went wrong")

Else

You can use the else keyword to define a block of code to be executed if no errors were
raised:

Example

In this example, the try block does not generate any error:

try:
print("Hello")
except:
print("Something went wrong")
else:
print("Nothing went wrong")
Finally

The finally block, if specified, will be executed regardless if the try block raises an error or
not.

Example
try:
print(x)
except:
print("Something went wrong")
finally:
print("The 'try except' is finished")

This can be useful to close objects and clean up resources:

Example

Try to open and write to a file that is not writable:

try:
f = open("demofile.txt")
try:
f.write("LorumIpsum")
except:
print("Something went wrong when writing to the file")
finally:
f.close()
except:
print("Something went wrong when opening the file")

The program can continue, without leaving the file object open.

Raise an exception

As a Python developer you can choose to throw an exception if a condition occurs.

To throw (or raise) an exception, use the raise keyword.

Example
Raise an error and stop the program if x is lower than 0:

x = -1

if x < 0:
raise Exception("Sorry, no numbers below zero")

The raise keyword is used to raise an exception.

You can define what kind of error to raise, and the text to print to the user.

Example

Raise a TypeError if x is not an integer:

x = "hello"

if not type(x) is int:


raise TypeError("Only integers are allowed")

Python Inheritance

Inheritance allows us to define a class that inherits all the methods and properties from
another class.

Parent class is the class being inherited from, also called base class.

Child class is the class that inherits from another class, also called derived class.

Create a Parent Class

Any class can be a parent class, so the syntax is the same as creating any other class:

Example

Create a class named Person, with firstname and lastname properties, and
a printname method:

class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
def printname(self):
print(self.firstname, self.lastname)

#Use the Person class to create an object, and then execute the printname method:

x = Person("John", "Doe")
x.printname()

Create a Child Class

To create a class that inherits the functionality from another class, send the parent class as a
parameter when creating the child class:

Example

Create a class named Student, which will inherit the properties and methods from
the Person class:

class Student(Person):
pass

Note: Use the pass keyword when you do not want to add any other properties or methods to
the class.

Now the Student class has the same properties and methods as the Person class.

Example

Use the Student class to create an object, and then execute the printname method:

x = Student("Mike", "Olsen")
x.printname()

Add the __init__() Function

So far we have created a child class that inherits the properties and methods from its parent.

We want to add the __init__() function to the child class (instead of the pass keyword).

Note: The __init__() function is called automatically every time the class is being used to
create a new object.
Example

Add the __init__() function to the Student class:

class Student(Person):
def __init__(self, fname, lname):
#add properties etc.

When you add the __init__() function, the child class will no longer inherit the
parent's __init__() function.

Note: The child's __init__() function overrides the inheritance of the


parent's __init__() function.

To keep the inheritance of the parent's __init__() function, add a call to the
parent's __init__() function:

Example
class Student(Person):
def __init__(self, fname, lname):
Person.__init__(self, fname, lname)

Now we have successfully added the __init__() function, and kept the inheritance of the
parent class, and we are ready to add functionality in the __init__() function.

Use the super() Function

Python also has a super() function that will make the child class inherit all the methods and
properties from its parent:

Example
class Student(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname)

By using the super() function, you do not have to use the name of the parent element, it will
automatically inherit the methods and properties from its parent.

Add Properties
Example
Add a property called graduationyear to the Student class:

class Student(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname)
self.graduationyear = 2019

In the example below, the year 2019 should be a variable, and passed into the Student class
when creating student objects. To do so, add another parameter in the __init__() function:

Example

Add a year parameter, and pass the correct year when creating objects:

class Student(Person):
def __init__(self, fname, lname, year):
super().__init__(fname, lname)
self.graduationyear = year

x = Student("Mike", "Olsen", 2019)

Polymorphism

Polymorphism in python defines methods in the child class that have the same name as
the methods in the parent class. In inheritance, the child class inherits the methods from
the parent class. Also, it is possible to modify a method in a child class that it has inherited
from the parent class.

Polymorphism means multiple forms. In python we can find the same operator or function
taking multiple forms. It also useful in creating different classes which will have class
methods with same name. That helps in re using a lot of code and decreases code
complexity. Polymorphism is also linked to inheritance as we will see in some examples
below.
Polymorphism in operators
The + operator can take two inputs and give us the result depending on what the inputs are.
In the below examples we can see how the integer inputs yield an integer and if one of the
input is float then the result becomes a float. Also for strings, they simply get concatenated.
This happens automatically because of the way the + operator is created in python.
Example
a =23
b =11
c =9.5
s1 ="Hello"
s2 ="There!"
print(a + b)
print(type(a + b))
print(b + c)
print(type (b + c))
print(s1 + s2)
print(type(s1 + s2))
Running the above code gives us the following result −
Output
34
20.5
HelloThere!
Polymorphism in in-built functions
We can also see that different python functions can take inputs of different types and then
process them differently. When we supply a string value to len() it counts every letter in it.
But if we five tuple or a dictionary as an input, it processes them differently.
Example
str='Hi There !'
tup=('Mon','Tue','wed','Thu','Fri')
lst=['Jan','Feb','Mar','Apr']
dict={'1D':'Line','2D':'Triangle','3D':'Sphere'}
print(len(str))
print(len(tup))
print(len(lst))
print(len(dict))
Running the above code gives us the following result −
Output
10
5
4
3
Polymorphism in user-defined methods
We can create methods with same name but wrapped under different class names. So we can
keep calling the same method with different class name pre-fixed to get different result. In
the below example we have two classes, rectangle and circle to get their perimeter and area
using same methods.
Example
from math import pi

classRectangle:
def __init__(self, length, breadth):
self.l= length
self.b= breadth
def perimeter(self):
return2*(self.l+self.b)
def area(self):
returnself.l*self.b

classCircle:
def __init__(self, radius):
self.r= radius
def perimeter(self):
return2* pi *self.r
def area(self):
return pi *self.r**2

# Initialize the classes


rec=Rectangle(5,3)
cr=Circle(4)
print("Perimter of rectangel: ",rec.perimeter())
print("Area of rectangel: ",rec.area())

print("Perimter of Circle: ",cr.perimeter())


print("Area of Circle: ",cr.area())
Running the above code gives us the following result −
Output
Perimter of rectangel: 16
Area of rectangel: 15
Perimter of Circle: 25.132741228718345
Area of Circle: 50.26548245743669

Abstract class
A class is called an Abstract class if it contains one or more abstract methods. An abstract
method is a method that is declared, but contains no implementation. Abstract classes may
not be instantiated, and its abstract methods must be implemented by its subclasses.

Abstract base classes provide a way to define interfaces when other techniques like hasattr()
would be clumsy or subtly wrong (for example with magic methods). ABCs introduce
virtual subclasses, which are classes that don’t inherit from a class but are still recognized by
isinstance() and issubclass() functions. There are many built-in ABCs in Python. ABCs for
Data structures like Iterator, Generator, Set, mapping etc. are defined in collections.abc
module. The numbers module defines numeric tower which is a collection of base classes
for numeric data types. The 'abc' module in Python library provides the infrastructure for
defining custom abstract base classes.

How Abstract Base classes work :


By default, Python does not provide abstract classes. Python comes with a module that
provides the base for defining Abstract Base classes(ABC) and that module name is
ABC. ABC works by decorating methods of the base class as abstract and then registering
concrete classes as implementations of the abstract base. A method becomes abstract when
decorated with the keyword @abstractmethod. For Example –

# Python program showing

# abstract base class work

from abc import ABC, abstractmethod

class Polygon(ABC):

@abstractmethod

def noofsides(self):

pass

class Triangle(Polygon):

# overriding abstract method


def noofsides(self):

print("I have 3 sides")

class Pentagon(Polygon):

# overriding abstract method

def noofsides(self):

print("I have 5 sides")

class Hexagon(Polygon):

# overriding abstract method

def noofsides(self):

print("I have 6 sides")

class Quadrilateral(Polygon):

# overriding abstract method

def noofsides(self):

print("I have 4 sides")

# Driver code

R = Triangle()

R.noofsides()
K = Quadrilateral()

K.noofsides()

R = Pentagon()

R.noofsides()

K = Hexagon()

K.noofsides()

Output:

I have 3 sides

I have 4 sides

I have 5 sides

I have 6 sides

Event-driven programming
Event-driven programming is a paradigm of system architecture where the logic flow
within the program is driven by events such as user actions, messages from other
programs, or hardware (sensor) inputs.

Event-driven programming focuses on events. Eventually, the flow of program depends upon
events. Until now, we were dealing with either sequential or parallel execution model but the
model having the concept of event-driven programming is called asynchronous model.
Event-driven programming depends upon an event loop that is always listening for the new
incoming events. The working of event-driven programming is dependent upon events. Once
an event loops, then events decide what to execute and in what order. Following flowchart
will help you understand how this works −
Python Module – Asyncio
Asyncio module was added in Python 3.4 and it provides infrastructure for writing single-
threaded concurrent code using co-routines. Following are the different concepts used by the
Asyncio module −
The event loop
Event-loop is a functionality to handle all the events in a computational code. It acts round
the way during the execution of whole program and keeps track of the incoming and
execution of events. The Asyncio module allows a single event loop per process. Followings
are some methods provided by Asyncio module to manage an event loop −
 loop = get_event_loop() − This method will provide the event loop for the current
context.
 loop.call_later(time_delay,callback,argument) − This method arranges for the
callback that is to be called after the given time_delay seconds.
 loop.call_soon(callback,argument) − This method arranges for a callback that is to
be called as soon as possible. The callback is called after call_soon() returns and when
the control returns to the event loop.
 loop.time() − This method is used to return the current time according to the event
loop’s internal clock.
 asyncio.set_event_loop() − This method will set the event loop for the current context
to the loop.
 asyncio.new_event_loop() − This method will create and return a new event loop
object.
 loop.run_forever() − This method will run until stop() method is called.

Example
The following example of event loop helps in printing hello world by using the
get_event_loop() method. This example is taken from the Python official docs.
importasyncio

defhello_world(loop):
print('Hello World')
loop.stop()

loop=asyncio.get_event_loop()

loop.call_soon(hello_world, loop)

loop.run_forever()
loop.close()
Output
Hello World

You might also like