0% found this document useful (0 votes)
14 views127 pages

OOP Python 1

Uploaded by

dijoveb657
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
14 views127 pages

OOP Python 1

Uploaded by

dijoveb657
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 127

Object Oriented Python

Prepared By
-Anooja Joy
Object Oriented VS Procedural
 In a procedural programming, the entire code is written into one long
procedure even though it might contain functions and subroutines. It is not
manageable as both data and logic get mixed together. Adding new data
and function is not easy. Procedural programming does not have any
proper way for hiding data so it is less secure.
 In object-oriented programming, the program is split into self-contained

objects or several mini-programs. Each object is representing a different


part of the application which has its own data and logic to communicate
among themselves. Adding new data and function is easy. Object oriented
programming provides data hiding so it is more secure.
Is Python Object Oriented?
 Python is a multi-paradigm programming language. Meaning, it

supports different programming approach like Object


 Python is considered as an object-oriented programming language rather

than a procedural programming language. Python packages like Scikit-


learn¹, pandas², and NumPy are all Python packages built with object-
oriented programming. In Python everything is an object or an instance of
some class.
Eg: All integer variables that we define are members of class int.
Object Oriented Programming
Advantages
 Object-oriented programming enables you to develop large,
modular programs that can instantly expand over time.
 Object-oriented programs hide the implementation from the end-
user.
 Object-oriented program would focus on the specific characteristics
of each object and what each object can do.
Python is Object Oriented
 Python follows object-oriented programming paradigm. Python is not
completely object-oriented as it contains some procedural functions.
 It deals with declaring python classes, creating objects from them
and interacting with the users.
 In an object-oriented language, the program is split into self-contained
objects or you can say into several mini-programs. Each object is
representing a different part of the application which can communicate
among themselves.
 OBJECT ORIENTED CONCEPTS
 Class

 Object

 Inheritance

 Polymorphism

 Method Overriding

 Data Abstraction

 Encapsulation
What is Python Class?
 A class in python is the blueprint from which specific objects are
created.
Why Class is required?
 Classes allow us to logically group our data and function in a way

that it is easy to reuse and a way to build upon if need to be.

Why Class is required in Software?


 A class, you can add consistency to your programs so that they can
be used in cleaner and efficient ways.
Class in Python
 Classes provide a means of bundling data and functionality together.
 A class creates a new local namespace where all its attributes are

defined. Attributes may be data or functions.


 A namespace is a mapping from names to objects. Most namespaces are
currently implemented as Python dictionaries, but normally not noticeable.
class Person:
'''This is a person class'''#DOCSTRING:first string inside
the class is called docstring and has a brief description about
the class
age = 10
def greet(self):
print('Hello')
#CREATING OBJECT to access different attributes and define logic
harry = Person()#similiar to function call
harry.greet()
#whenever an object calls its method, the object itself is
passed as the first argument. It translates into
Person.greet(harry)
Class in Python
 Class can be defined as a collection of objects.
 A class is a logical entity and can have:
 Class Variables:
 Constructor
 Functions/ Instance Methods
 Instance Attributes
Syntax: class Class_name:
statement-1
…..
Defining a Class Example
statement-N
class person:
count=0 #class variable
def __init__(self): #constructor
self.name="unknown" #instance attribute
self.age=0 #instance attribute
print('Constructor invoked')
def displayInfo(self): #Instance method
print(self.name,self.age)
Self parameter
The self
 The self-argument of constructor and methods refers to the object

itself. It is part of the Python syntax to access members of objects.


 self is used as a reference variable which refers to the current class
object. It is always the first argument in the function definition.
 When we call method, we don't have to supply the self-keyword. That's

automatically handled for us by the Python runtime


 Python self variable is used to bind the instance of the class to the instance
method. This variable is used only with the instance methods.
 If we have a method which takes no arguments, then we still have to

have one argument – the self.


 When we call a method of this object as myobject.method(arg1, arg2), this
is automatically converted by Python into MyClass.method(myobject, arg1,
arg2).
 It is needed because in instance methods object that invokes the method
should be passed as the first argument and self makes it possible.
Class
 A class is incomplete without some functionality.
 Functionalities of a class can be defined by setting various
attributes which acts as a container for data. Functions in classes
are called methods. Variables (class variables and instance
variables) in classes are called attributes
 The attributes and methods of a class are accessed via objects.
 The process of creating instances of a class is known as
instantiation.
 A class can be instantiated by:
 calling the class using the class name.
 Using the object
p1 = person()
p1.name
p1.age
 In python, we must notice that each class is associated with a
documentation string which can be accessed by using <class-
name>.__doc__.
Object
 A class is a blueprint for the object. When class is defined, only the
description for the object is defined so no memory or storage is allocated.
 The class come into an existence when it is instantiated.

 The object is an entity that has state/characteristics/attributes and


behavior/actions/method.
What is Object?
 It is used to create an instance of the class. An instance is an object of

a class created at run-time.


What is the purpose of Object?
 An object can be used to access class variables and class methods

using dot operator.


EXAMPLE
class Employee:
id=10
name="John"
def display(self):
print("ID is:",self.id,"\nName:",self.name)
emp=Employee()
Characteristics of Objects
 Objects
 can store data
 are instances of python classes

 are created by an expression

 can be referenced by one or more variable

 have a unique identifier returned by id()

 are mutable or immutable depending on the type (e.g., list vs tuple)

 can be converted to string using str()

 can be printed

 are deleted automatically when no longer needed

 Comparing instances: There are 6 specials methods related to comparison


that can be overlaoded. These methods can return any object not just 1/0 or
True/False.
method operator
__lt__(self, other) self < other
__le__(self, other) self <= other
__gt__(self, other) self > other
__ge__(self, other) self >= other
__eq__(self, other) self == other
__ne__(self, other) self != other
Built-in class attributes
 Built-in class attributes gives us information about the class and can be accessed
using the . operator
 Attributes of a class are function objects that define corresponding methods of its
instances. They are used to implement access controls of the classes.

Attribute Description

__dict__ It provides the dictionary containing the information about the class namespace.

__doc__ This gives us the class documentation if documentation is


present. None otherwise.

__name__ It is used to access the class name.

__module__ It is used to access the module in which, this class is defined.

__bases__ It contains a tuple including all base classes.

Function Description

getattr(obj,name,default) It is used to access the attribute of the object.

setattr(obj, name,value) It is used to set a particular value to specific attribute of an object.

delattr(obj, name) It is used to delete a specific attribute.

hasattr(obj, name) It returns true if object contains some specific attribute.


EXAMPLE
class Student:
def __init__(self,name,id,age):
self.name=name
self.id=id
self.age=age
s=Student("John",101,22)#creates the object of class Student
print(getattr(s,'name')) #prints the attribute name of object
setattr(s,"age",23) #reset the value of attribute age to 23
print(getattr(s,'age'))#prints the modified value of age
print(hasattr(s,'id'))#prints true
if the student contains the attribute with name id
#delattr(s,'age') #deletes the attribute age
print(s.age)
#this will give an error since the attribute age has been delete
print(s.__doc__)
print(s.__dict__)
print(s.__module__)
#accessing information abt class using classs attriibutes
Constructor vs __new__()
Object Creation
 Object creation is controlled by a static class method with the

name __new__.
 when you call Example(), to create an object of the class Example,

then the __new__ method of this class is called. Python defines this
function for every class by default. But we can redefine it

class Example:
def __new__(self):
return “hello”
Obj = Example()
type(Obj)

class Example:
count=1 #class variable
Obj = Example()
type(Obj)
Name Space
 A namespace(collection of names) is a mapping from names to
objects. Most namespaces are currently implemented as Python
dictionaries.
 Everything in Python is an object and the Name is a way to access
the underlying object.
 To get the address (in RAM) of some object through the built-in
function id()
a = 2
print('id(a) =', id(a))
a = a+1
print('id(a) =', id(a))
print('id(3) =', id(3))
b = 2
print('id(b) =', id(b))
print('id(2) =', id(2))
Deleting object
c1 = ComplexNumber(1,3)
del c1
 a new instance object is created in memory and the name c1 binds
with it.
 On the command del c1, this binding is removed and the
name c1 is deleted from the corresponding namespace. The object
however continues to exist in memory and if no other name is
bound to it, it is later automatically destroyed.
 This automatic destruction of unreferenced objects in Python is also
called garbage collection.
Destroying Objects (Garbage Collection)
 Python deletes unneeded objects (built-in types or class instances)
automatically to free the memory space. The process by which
Python periodically reclaims blocks of memory that no longer are in
use is termed Garbage Collection.
 Python's garbage collector runs during program execution and is
triggered when an object's reference count reaches zero.
 An object's reference count increases when it is assigned a new
name or placed in a container (list, tuple, or dictionary). The
object's reference count decreases when it's deleted with del, its
reference is reassigned, or its reference goes out of scope. When an
object's reference count reaches zero, Python collects it
automatically.
 a class can implement the special method __del__(), called a
destructor, that is invoked when the instance is about to be
destroyed. This method might be used to clean up any non memory
resources used by an instance.
EXAMPLE
class Point:
def __init__( self, x=0, y=0):
self.x = x
self.y = y
def __del__(self):
class_name = self.__class__.__name__
print class_name, "destroyed"
pt1 = Point()
pt2 = pt1
pt3 = pt1
print id(pt1), id(pt2), id(pt3)
# prints the ids of the obejcts
del pt1
del pt2
del pt3
Constructor
 Purpose:
 A constructor is a special type of method (function) with no explicit
return type which allows you to create an object of class and is
used to initialize instance members/ attributes of instance of the
class.
 the constructor method is invoked automatically whenever a new
object of a class is instantiated.
 Constructors also verify that there are enough resources for the object
to perform any start-up task.
 Executed when: Constructor definition is executed when we
create the object of this class.
 Types: Constructors can be of two types.
 Parameterized Constructor
 Non-parameterized Constructor
 How? In python, the method __init__ simulates the constructor of
the class. It gets called whenever a new object of class is instantiated.
 Normally constructor don’t returns anything ie none.(since
separation of data and logic is needed)
EXAMPLE
class Employee:
def __init__(self,name,id):
self.id=id
self.name=name
def display(self):
print("ID:",self.id,"\nName:",self.name)
emp1=Employee("John",101)
emp2=Employee("Did",102)
#accessing display() method to print employee1 information
emp1.display()
#accessing display() method to print employee2 information
emp2.display()
Parametrized VS Non- Parametrized
class Student: class Student:
# Constructor - # Constructor -
parameterized non parameterized
def __init__(self,name): def __init__(self):
print("This is non
print("This is parametrized parametrized constructor")
constructor") def show(self,name):
self.name=name print("Hello",name)
def show(self): student=Student()
student.show("John")
print("Hello",self.name)
student=Student("John")
student.show()
Variables Assocciated with a class
1. Class variable/Static variable is a variable that is shared by all the
different objects/instances of a class. Its value is assigned in class and
outside normal methods.
 Class attributes are accessed using the name of the class.

 Changing the class attribute using the class name will be reflected for

all the instances of a class.


 changing the class attribute using the instance will not reflect

elsewhere. It will affect only that particular instance.


class person:
greet="Hello!“ #class variable
print(person.greet)
p1=person()
p2=person()
print(p1.greet)
print(p2.greet)
person.greet="Hi!"
print(p1.greet)
print(p2.greet)
Class Variable
 Class variable must be prefixed by class name and dot operator.
 Uses:
 Class variable are used to keep count of number of objects created
from class.
 To define constants associated with particular class or to specify
default values.
class Sample:
cl_var=0
def __init__(self,x):
Sample.cl_var+=1
self.inst_var=x
print("The instance variable val
is",self.inst_var)
print("The instance variable val
is",Sample.cl_var)
obj1=Sample(10)
obj2=Sample(20)
Variables Assocciated with a class
2. Instance variables are
class person:
variables which are unique
to each instance. greet="Hello!"
 Instance variables are def __init__(self,greet):
variables whose value is self.greet=greet#Instance variable
assigned inside a print(self.greet)
constructor or method
print(greet+self.greet)
with self.
 It belongs only to the current print(person.greet+self.greet)
instance of a class. It is also def greetings1(self):
known as object variables. self.greet="Hi"
 Instance or non-static print(self.greet)
variables are different for
def greetings2(self):
different objects (every
object has a copy of it). self.greet="Good"
Python instance variables can print(self.greet)
have different values across print(person.greet)
multiple instances of a class.
p1=person("Morining")
p1.greetings1()
p1.greetings2()
Instance Attributes Value
setting
 An instance attribute can be accessed using object using dot notation:
p1 = person()
p1.name= “Python”
p1.name
 Using Constructor
class person:#using constructor
def __init__(self,name):
self.name=name
print("Name:",name)
person("Arun")
Challenge
 Create a python Program to accept Employee details like Name,
Employee id and Salary. Accept at least the details of 3 employees
and display it.
Creating List of Objects in
Python
#List of objects
class EmpClass():
def __init__(self,name,empid,salary):
self.name=name
self.empid=empid
self.salary=salary
def display(self):
print("Name ",self.name,"\t Employee id",self.empid,"\t
Salary",self.salary)
emp_objects = []
l=int(input("Enter number of records:"))
for i in range(l):
x,y,z=input("Enter Name, EmpId and Salary: ").split()
m=EmpClass(x,y,z)
emp_objects.append(m)
j=1
for obj in emp_objects:
print("Record ",j)
obj.display()
j=j+1
Methods associated with a class
 Functions defined in a class to describes the behavior of an object is
called as Methods in python.
 There are 3 types of methods in Python:
1. Instance Methods
2. Class Methods
3. Static Methods
4. Instance Methods: Instance methods are defined like normal functions
in Python but each instance method must have the first parameter,
as self which refers to the calling instance.
 Instance methods of a class can be accessed using an object.
class person:
def __init__(self):
self.name="unknown"
self.age=0
def displayInfo(self): #instance method
print(self.name, self.age)
p1=person()
p1.displayInfo()
Methods associated with a class
 Class method: These methods are called by class instead of object and
and first argument is cls and not self.
 A class method is a method that is bound to a class rather than its object.
It doesn't require creation of a class instance,
 @classmethod decorator should be applied to method
 Properties
 A class method is a method which is bound to the class and not the object of
the class.
 It can’t modify object instance state but it can modify a class state that would
apply across all the instances of the class.
 The class method can be called both by the class and its object{C.f())
or on an instance (such as C().f())}
 class methods are used to create factory methods. Factory methods
return class object ( similar to a constructor )
Example
#Class methods
class Rectangle:
def __init__(self,length,breadth): #constructor
self.length=length
self.breadth=breadth
def area(self): #instance method
return self.length*self.breadth
@classmethod
def Square(cls,side):
return cls(side,side)
S=Rectangle.Square(10)
print("AREA=",S.area())
Decorator
 In Python, the function is a first-order object. It means that
 Function can be passed as an argument to another function.

 It is also possible to define a function inside another function called as

nested function
 a function can return another function.

 A decorator is a function that receives another function as


argument. The behavior of the argument function is extended by the
decorator without actually modifying it.
 A decorator is a syntactic convenience that takes in a function,
adds some functionality and then returns it.
 Python includes the @[decorator_function_name] syntax to specify a
decorator function. .
 Usage of decorator is also known as meta-programming because a part
of the program tries to modify another part of the program at compile
time.
@displaydecorator
def display(str): #A custom decorator function
print(str)
Properties of first class
functions:
 A function is an instance of the Object type.
 You can store the function in a variable.
 You can pass the function as a parameter to another function.
 You can return the function from a function.
 You can store them in data structures such as hash tables, lists, …
 decorators are used to modify the behavior of function or class. In
Decorators, functions are taken as the argument into another
function and then called inside the wrapper function.
def uppercase_decorator(function):
def wrapper():
func = function()
make_uppercase = func.upper()
return make_uppercase
return wrapper
EXAMPLE 2
class person:
totalObjects=0
def __init__(self):
person.totalObjects=person.totalObjects+1
@classmethod
def showcount(cls):
print("Total objects: ",cls.totalObjects)
p1=person()
p2=person()
person.showcount()
p1.showcount() #accessing class methods using objects
Methods associated with a class
 Static Method: A method that belongs to class and doesn’t
requires object to access it. Static method is bound to a class
rather than the objects for that class.
 Static methods doesn’t require any additional arguments like self,
cls.
 static method an be called by an instance of a class or by the class
itself since it doesn't receive any reference argument
 We generally use static methods to create utility functions.
 A static method can’t access or modify class state.
 Python Static methods can be created in two ways.
 Using staticmethod()
 Using @staticmethod
Static Methods
Using staticmethod()
class Calculator:
def multiply(x,y):
return x+y
Calculator.multiply=staticmethod(Calculator.multiply)
print("Product is",Calculator.multiply(2,3))
Using @staticmethod
class person:
@staticmethod
def greet():
print("Hello!")
person.greet()
p1=person()
p1.greet()
EXAMPLE 2
#Static methods
class choice:
def __init__(self,object):
self.subjects=subjects
@staticmethod
def validate_subject(subjects):
if "CSA" in subjects:
print("Option Not Available")
else:
return True
subjects=["DS","CASA","FoC","OS"]
if all(choice. validate_subject(i) for i in subjects):
ch=choice(subjects)
print("you have been allocated the
subjects:",subjects)
Class method Static Method
1. A class method takes cls 1. A static method needs no
as first parameter specific parameters.
2. A class method can access 2. a static method can’t access or
or modify class state. modify it.
3. class methods must have 3. static methods know nothing
class as parameter. about class state. They are
4. @classmethod decorator is utility type methods that take
used to create a some parameters and work
class method upon those parameters
5. use class method to create 4. @staticmethod decorator is
factory methods. Factory used to create a static method
methods return class in python.
object ( similar to a 5. use static methods to create
constructor ) for different utility functions.
use cases.
Access Modifiers in Python
 Classical object-oriented languages, such as C++ and Java, control the
access to class resources by public, private and protected keywords.
 Public members (generally methods declared in a class) are

accessible from outside the class. The object of the same class is
required to invoke a public method.
 Protected members of a class are accessible from within the class

and are also available to its sub-classes.


 Private members of a class are denied access from the environment

outside the class. They can be handled only from within the class.
 Access modifiers play an important role to protect the data from
unauthorized access as well as protecting it from getting manipulated.
When inheritance is implemented there is a huge risk for the data to get
destroyed(manipulated) due to transfer of unwanted data from the parent
class to the child class. Therefore, it is very important to provide the right
access modifiers for different data members and member functions
depending upon the requirements.
 The arrangement of private instance variables and public methods
ensures the principle of data encapsulation means to restrict class
variable’s access outer class methods.
Access Specifiers in Python
 Python does not support access control.Python doesn't have any
mechanism that effectively restricts access to any instance
variable/method.
 All members in a Python class are public by default. Any member can be
accessed from outside the class environment.

Naming Type Meaning


These attributes can be freely used inside or outside
Name Public
of a class definition

Protected attributes should not be used outside of the


_name Protected
class definition, unless inside of a subclass definition.

This kind of attribute is inaccessible and invisible. It’s


__name Private neither possible to read nor to write those attributes,
except inside of the class definition itself.

 Python prescribes a convention of prefixing the name of the


variable/method with single or double underscore to emulate the
behaviour of protected and private access specifiers.
PUBLIC EXAMPLE
 all the variables and member functions of a class are public in a
python program.
class Employee:
# constructor
def __init__(self, name, sal):
self.name = name
self.sal = sal
emp = Employee("Ironman", 999000)
emp.sal
 name mangling, which means that there is a limited support for
a valid use-case for class-private members basically to avoid name
clashes of names with names defined by subclasses.
 The double underscore prefix for a member variable or method is a
commonly used convention to denote a private method. It doesn't
actually change access privilege.
 Names begin and end with double underscores (such
as __init__, __str__, __add__) are special magic methods
PROTECTED EXAMPLE
 Protected in fact, doesn't prevent instance variables from accessing
or modifying the instance.
class employee: #protected access specifier
def __init__(self, name, sal):
self._name=name # protected attribute
self._salary=sal # protected attribute
e1=employee("Swati", 10000)
print(e1._salary)
e1._salary=20000
print(e1._salary)
class HR(employee): # defining a child class
def task(self): # member function task
print("We manage Employees")
hrEmp = HR("Captain", 10000)
print(hrEmp._salary)
hrEmp.task()
PRIVATEEXAMPLE
 Any attempt to touch private attribute will result in an
AttributeError:
class employee: #private acces specifier
def __init__(self, name, sal):
self.__name=name # private attribute
self.__salary=sal # private attribute
self.__salary=self.__salary+500
print(self.__salary)
e1=employee("Swati", 10000)
print(e1.__salary)
e1.__salary=20000
print(e1.__salary)
Every member with double underscore will be changed to
_object._class__variable. If so required, it can still be accessed from
outside the class, but the practice should be refrained.
e1=Employee("Bill",10000)
e1._Employee__salary
PRIVATE METHODS
 Private methods are methods which cannot be accessed outside the class.
 But technically private variables is a convention private methods are also a
convention.
Syntax: objectname._ classname__privatemethodname
class P:
def __init__(self, name, alias):
self.name = name # public
self.__alias = alias # private
def who(self):
print('name : ', self.name)
print('alias : ', self.__alias)
def __foo(self): # private method
print('This is private method')
def foo(self): # public method
print('This is public method')
self.__foo()
x = P('Alex', 'amem')
x.who()
#x.__foo()
x._P__foo()
Inner Classes/ Sub-classes
 Inner or Nested Class is a Class defined inside another class. If
an object is created using a class, the object inside the root class
can be used.
 Why Inner Classes?
 Grouping of two or more classes. Suppose you have two
classes Car and Engine. Every Car needs an Engine. But, Engine won't
be used without a Car. So, you make the Engine an inner class to
the Car. It helps save code.
 Hiding code is another use of Nested classes. You can hide the Nested
classes from the outside world.
 It's easy to understand the classes. Classes are closely related here.
You don't have to search for the classes in the code. They are all
together.
 Inner or Nested classes are not the most commonly used feature
in Python.
 Multiple innerclasses and multilevel inerclasses are also permitted.
EXAMPLE
class Outer:#Outer Class
def __init__(self):## instantiating the 'Inner' class
self.inner = self.Inner()
def reveal(self):## calling the 'Inner'class function display
self.inner.inner_display("Calling Inner class function
from Outer class")
class Inner: #Inner Class
def inner_display(self, msg):
print(msg)
outer = Outer()## calling the 'reveal()' method
outer.reveal()
Outer().Inner().inner_display("Calling the Inner class method
directly")
outer = Outer()
## instantiating the inner class
inner = outer.Inner() ## inner = Outer().Inner() or inner =
outer.inner
inner.inner_display("Just Print It!")
OOPs Concepts
Inheritance
Inheritance
 Why? Inheritance provides code reusability to the program because we
can use an existing class to create a new class instead of creating it from
scratch. Inheritance allows us to inherit attributes and methods from the
base/parent class.
 What? In inheritance, the child class acquires the properties and can
access all the data members and functions defined in the parent class. A
child class can also provide its specific implementation to the functions of
the parent class.
 This is useful as we can create sub-classes and get all of the functionality

from our parent class. Then we can overwrite and add new functionalities
without affecting the parent class.
 The newly formed class is a derived class (or child class or sub-class).

The existing class is a base class (or parent class or super class).
Syntax:
class derived-class(base class):
<class-suite>
EXAMPLE
class Animal:
def speak(self):
print("Animal Speaking")
#child class Dog inherits the base class Animal
class Dog(Animal):
def bark(self):
print("dog barking")
class Cat(Animal):
pass
d=Dog()
c=Cat()
d.bark()
d.speak()
c.speak()
Inheritance comes into picture when a new class possesses the 'IS A'
relationship with an existing class.
Message Communication
 Accessing attributes and methods of one class in another class
 Accessing attributes and methods of one class in another class is done by
passing the object of one class to another.
class ClassA():
def __init__(self):
self.var1 = 1
self.var2 = 2
def methodA(self):
self.var1 = self.var1 + self.var2
return self.var1
class ClassB(ClassA):
def __init__(self, class_a):
self.var1 = class_a.var1
self.var2 = class_a.var2
object1 = ClassA()
summ = object1.methodA()
print(summ)
object2 = ClassB(object1)#MESSAGE COMMUNICATION
print(object2.var1)
print(object2.var2)
Initialization of parent class
attributes
 If you forget to invoke the __init__() of the parent class then its
instance variables would not be available to the child class.
#Single Inheritance
class A:
def __init__(self,n='Rahul'):
self.name=n
class B(A):
def __init__(self,roll):
#A.__init__(self,n='Rahul')
self.roll = roll
object=B(23)
print (object.name)
Object Class
 In Python (from version 3.x), object is root of all classes.

 So “class Test(object)” and “class Test” are same.


Can Constructor be inherited?
 __init__ is like any other method; it can be inherited
 If a class does not have a __init__ constructor, Python will
check its parent class to see if it can find one.
 As soon as it finds one, Python calls it and stops looking
class Person:
def __init__(self,name,idnumber,salary,post):
self.name=name
self.idnumber=idnumber
self.salary=salary
self.post=post
# child class
class Employee(Person):
def display2(self):
print(self.salary)
print(self.post)
print(self.name)
print(self.idnumber)
a=Employee('Rahul',886012,20000,"manager")
a.display2()
Pass keyword in python
 Use the pass keyword when you do not want to add any other
properties or methods to the class. pass is a null statement. It is
used as a placeholder.
 Suppose we have a loop or a function that is not implemented yet,

but we want to implement it in the future. They cannot have an


empty body. The interpreter would complain. So, we use
the pass statement to construct a body that does nothing.
# pass is just a placeholder for
# functionality to be added later.
sequence = {'p', 'a', 's', 's'}
for val in sequence:
pass
Types of Inheritance
 There are basically 4 types of inheritances.
SINGLE INHERITANCE
 Single inheritance: When a child class inherits from only one
parent class, it is called as single inheritance.
class Person:
def __init__(self,name,idnumber):
self.name=name
self.idnumber=idnumber
def display(self):
print(self.name)
print(self.idnumber)
class Employee(Person):# child class
def __init__(self,name,idnumber,salary,post):
self.salary=salary
self.post=post
Person.__init__(self,name,idnumber)# invoking the
__init__ of the parent class
a=Person('Rahul',886012) # creation of an object variable or an
instance
a.display() # calling a function of the class Person using its
Multiple Inheritance
 Python provides us the flexibility to inherit multiple base classes in the child class
which is known as multiple inheritance.

class Calculation1:
def Summation(self,a,b):
return a+b
class Calculation2:
def Multiplication(self,a,b):
return a*b
class Derived(Calculation1,Calculation2):
def Divide(self,a,b):
return a/b
d=Derived()
print(d.Summation(10,20))
print(d.Multiplication(10,20))
EXAMPLE 2
class Base1:
def __init__(self):
self.str1 = "Super Class"
print("Base1")
class Base2:
def __init__(self):
self.str2 = "Sub class"
print("Base2")
class Derived(Base1, Base2):
def __init__(self):# Calling constructors of Base1 and Base2
classes
Base1.__init__(self)
Base2.__init__(self)
print("Derived class showing multiple inheritance")
def printStrs(self):
print(self.str1, self.str2)
ob = Derived()
ob.printStrs()
Multilevel Inheritance
 Multi-Level inheritance is possible in python
#Multilivel Inheritance
class Animal:
def speak(self):
print("Animal Speaking")
#The child class Dog inherits the base class Animal
class Dog(Animal):
def bark(self):
print("dog barking")
#The child class Dogchild inherits another child class Dog
class DogChild(Dog):
def eat(self):
print("Eating bread...")
d=DogChild()
d.bark()
d.speak()
d.eat()
METHOD RESOLUTION ORDER
 Method Resolution Order(MRO) denotes the way a programming language
resolves a method or attribute or the order in which the base classes are
searched when executing a method. It's the order in which method should be
inherited in the presence of multiple inheritance.
 In multiple inheritance scenario, the method or attribute is searched first within the
current class. If not found, the search continues into parent classes in depth-first,
left-right fashion without searching same class twice. The methods are executed
based on the order specified while inheriting the classes.This order is also called
Linearization of a class and set of rules are called MRO(Method Resolution Order).
class A:
def meth(self):
print(" In class A")
class B(A):
def meth(self):
print(" In class B")
class C(A):
def meth(self):
print("In class C")
class D(B,C):
pass
r=D()
MRO
MRO of a class can be viewed as the __mro__ attribute
or mro() method. The former returns a tuple while latter returns a
list.
Syntax: classname.__mro__ OUTPUT
or classname.mro()
In class C
Example:
class A: (<class '__main__.C'>, <class
'__main__.A'>, <class '__main__.B'>,
def meth(self):
<class 'object'>)
print(" In class A")
[<class '__main__.C'>, <class
class B: '__main__.A'>, <class '__main__.B'>,
def meth(self): <class 'object'>]
print(" In class B")
class C(A,B):
def meth(self):
print("In class C")
r=C()
r.meth()
print(C.__mro__)
Other cases of MRO
class A: OUTPUT
def process(self): C process()
print('A process()') [<class '__main__.D'>, <class
class B: '__main__.C'>, <class
def process(self): '__main__.A'>, <class
'__main__.B'>, <class
print('B process()')
'object'>]
class C(A, B):
def process(self):
print('C process()')
class D(C,B):
pass
obj = D()
obj.process()
print(D.mro())
Other cases of MRO
class A: OUTPUT
def process(self): A process()
print('A process()') [<class '__main__.D'>, <class
class B: '__main__.C'>, <class
def process(self): '__main__.A'>, <class
'__main__.B'>, <class
print('B process()')
'object'>]
class C(A, B):
pass
class D(C,B):
pass
obj = D()
obj.process()
print(D.mro())
Other cases of MRO
class A: OUTPUT
def process(self): C process()
print('A process()') [<class '__main__.D'>, <class
class B(A): '__main__.B'>, <class
pass '__main__.C'>, <class
'__main__.A'>, <class
'''def process(self):
'object'>]
print('B
process()')'''
class C(A):
def process(self):
print('C process()')
class D(B,C):
pass
obj = D()
obj.process()
print(D.mro())
Other cases of MRO
class A:
def process(self):
print('A process()')
class B(A):
def process(self):
print('B process()')
class C(A, B):
pass
obj = C()
obj.process()
OUTPUT
--------- TypeError Traceback (most recent call
last) <ipython-input-8-868896ad885b> in
<module> 6 def process(self): 7 print('B
process()') ----> 8 class C(A, B): 9 pass 10 obj
= C() TypeError: Cannot create a consistent
method resolution order (MRO) for bases A, B
Other cases of MRO
class X: pass
class Y: pass
class Z: pass

class A(X,Y): pass


class B(Y,Z): pass

class M(B,A,Z): pass


print(M.mro())
OUTPUT
[<class '__main__.M'>,
<class '__main__.B'>,
<class '__main__.A'>,
<class '__main__.X'>,
<class '__main__.Y'>,
<class '__main__.Z'>,
<class 'object'>]
Other Inheritances
 Hierarchical inheritance More than one derived classes are
created from a single base.
 Hybrid inheritance: This form combines more than one form of
inheritance. Basically, it is a blend of more than one type of
inheritance.
How to access parent members in a
subclass?
1. Using Parent class name
2. Using super()
Using Parent class name
class Base:
def __init__(self, x): # Constructor
self.x=x
class Derived(Base):
def __init__(self, x, y):
Base.x=x
self.y=y
def printXY(self):
print(self.x,self.y)
d=Derived(10, 20) # Driver Code
d.printXY()
Using Super()
 super() builtin returns a proxy object that allows you to refer
parent class by 'super'.
 Super() Uses:
 provides the access to those methods of the super-class (parent class) which
have been overridden in a sub-class (child class) that inherits from it.
 By avoiding the using base class name we can access base class constructor,
instance methods and instance variables and without Passing self parameter.
 For indirection in multiple Inheritance.
EXAMPLE
#Using super()
class Base:
def __init__(self, x): # Constructor
self.x=x
class Derived(Base):
def __init__(self, x, y):
super().__init__(x)
#super(Derived, self).__init__(x)
self.y=y
def printXY(self):
print(self.x,self.y)
d=Derived(10, 20) # Driver Code
d.printXY()
EXAMPLE
class Bird: # parent class
def __init__(self):
print("Bird is ready")
def whoisThis(self):
print("Bird")
def swim(self):
print("Swim faster")
class Penguin(Bird): # child class
def __init__(self):
super().__init__() # call super() function
print("Penguin is ready")
def whoisThis(self):
print("Penguin")
def run(self):
print("Run faster")
peggy=Penguin()
peggy.whoisThis()
peggy.swim()
Super() in multilevel inheritance
class LEVEL1:
def __init__(self):
print('HEY !!!!!!I am initialised(Class LEVEL1)')
def sub_LEVEL(self, b):
print('Printing from class LEVEL1:', b)
class LEVEL2(LEVEL1):
def __init__(self):
print('HEY !!!!!! I am initialised(Class LEVEL2)')
super().__init__()
def sub_LEVEL(self, b):
print('Printing from class LEVEL2:', b)
super().sub_LEVEL(b + 1)
class LEVEL3(LEVEL2):
def __init__(self):
print('HEY !!!!!!I am initialised(Class LEVEL3)')
super().__init__()
def sub_LEVEL(self, b):
print('Printing from class LEVEL3:', b)
super().sub_LEVEL(b + 1)
gfg = LEVEL3()
gfg.sub_LEVEL(10)
Super() in Multiple inheritance
 super() returns a proxy object, a substitute object that has ability to call
method of the base class via delegation. This is called indirection (ability
to reference base object with super())
class Animal:
def __init__(self, animalName):
print(animalName, 'is an animal.');
class Mammal(Animal):
def __init__(self, mammalName): OUTPUT
print(mammalName, 'is a warm-blooded animal.')
Dog has 4 legs.
super().__init__(mammalName)
class NonWingedMammal(Mammal): Dog can't swim.
def __init__(self, NonWingedMammalName): Dog can't fly.
print(NonWingedMammalName, "can't fly.")
super().__init__(NonWingedMammalName) Dog is a warm-
class NonMarineMammal(Mammal): blooded animal.
def __init__(self, NonMarineMammalName):
Dog is an animal.
print(NonMarineMammalName, "can't swim.")
super().__init__(NonMarineMammalName) Bat can't swim.
class Dog(NonMarineMammal, NonWingedMammal): Bat is a warm-blooded
def __init__(self): animal.
print('Dog has 4 legs.')
super().__init__('Dog') Bat is an animal
d = Dog()
print('')
Checking Inheritances
issubclass(sub, sup): It returns true if the first class is the subclass of the
second class, and false otherwise.
isinstance(): It returns true if the first parameter, i.e., obj is the instance of
the second parameter, i.e., class.
class Calculation1:
def Summation(self,a,b):
return a+b
class Calculation2:
def Multiplication(self,a,b):
return a*b
class Derived(Calculation1,Calculation2):
def Divide(self,a,b):
return a/b
d=Derived()
print(issubclass(Derived,Calculation2))
print(issubclass(Calculation1,Calculation2))
print(isinstance(d,Derived))
POLYMORPHISM
Polymorhism
 Polymorphism in Computer Science is the ability to present the same
interface for differing underlying forms.
 Polymorphism is an ability of an object to use common interface for
multiple form (data types).
 Polymorphism in Python can be implemented using:
1. Method Overriding: Overriding a method means redefining a
method in the subclass when it has already been defined in some
other class. In practical terms, polymorphism in overriding means that
if class B inherits from class A, it doesn’t have to inherit everything
about class A, it can do some of the things that class A does
differently.It can be achieved using Regular Inheritance and
Abstract Class Inheritance.
2. Overloading: It can be operator overloading(Python has
the ability to overload standard operators so that they have
appropriate behavior based on the type of object. Applying operator
to objects of different types) and Method overloading(Its not
supported in Python but can be achieved using *args)
3. Common Interface: A concept of using common operation in
different ways for different data input. Applying a method to objects
of different types.
Method Overriding
 When the parent class method is defined in the child class with some
specific implementation, then the concept is called method overriding.
 When? We may need to perform method overriding in the scenario where

the different definition of a parent class method is needed in the child


class.
 For example When you add the __init__() function, the child class will no

longer inherit the parent's __init__() function. 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:


class Person:
def __init__(self,fname,lname):
self.firstname=fname
self.lastname=lname
def printname(self):
print(self.firstname,self.lastname)
class Student(Person):
def __init__(self,fname,lname):
Polymorphism using
MethodOverriding
#Method overriding
class Bank:
def getroi(self):
return 10
class SBI(Bank):
def getroi(self):
return 7
class ICICI(Bank):
def getroi(self):
return 8
b1=Bank()
b2=SBI()
b3=ICICI()
print("Bank Rate of interest:",b1.getroi())
print("SBI Rate of interest:",b2.getroi())
print("ICICI Rate of interest:",b3.getroi())
Method Overriding
 we cannot override a private method of a superclass, which is the
one having double underscores before its name.
class A:
def __init__(self):
constant1 = 1
def method1(self):
print('method1 of class A')
class B(A):
def __init__(self):
constant2=2
self.method1()
A. __init__(self)
A.method1(self)
def method1(self):
print('method1 of class B')
b = B()
OPERATOR OVERLOADING
 Python operators work for built-in classes. But same operator
behaves differently with different types.
 Example: the + operator will, perform arithmetic addition on

two numbers, merge two lists and concatenate two strings.


 This feature in Python, that allows same operator to have different

meaning according to the context is called operator overloading.


 But if we try to use operators in user defined class we get error. To

avoid these we can use special function.


class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
p1 = Point(2,3)
p2 = Point(-1,2)
p1 + p2
Special Function
 Class functions that begins with double underscore __ are called
special functions in Python.
 Example: __init__()

 It gets called every time we create a new object of that class.

 def __str__(self)is used to create string representation of an

instance and will be invoked automatically when instance is


created. It is used for informal representation of an instance.
 __str__, which can be overloed.

class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x,self.y)
p1 = Point(2,3)
Print(p1)
Operator Overloading with Special
Function
 add__ is a magic method which can be overridden. In Python,
numbers are not primitive literals but objects.
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x,self.y)
def __add__(self,other):
x = self.x + other.x
y = self.y + other.y
return Point(x,y)
p1 = Point(2,3)
p2 = Point(-1,2)
print(p1 + p2)
Overloading Comparison Operators
 Python does not limit operator overloading to arithmetic operators
only. We can overload comparison operators as well
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x,self.y)
def __lt__(self,other):
self_mag = (self.x ** 2) + (self.y ** 2)
other_mag = (other.x ** 2) + (other.y ** 2)
return self_mag < other_mag
Point(1,1) < Point(-2,-3)
Point(1,1) < Point(0.5,-0.2)
METHOD OVERLOADING
 Method Overloading means same function name but different
signatures or being used for different types.
 python does not supports method overloading. We may overload
the methods but can only use the latest defined method.
 Used for different types
# len() being used for a string
print(len("geeks"))
# len() being used for a list
print(len([10, 20, 30]))
 Different signatures
def add(x, y, z = 0):
return x + y+z

# Driver code
print(add(2, 3))
print(add(2, 3, 4))
Method overloading using * args
mimics
def add(datatype, *args):
# if datatype is int initialize answer as 0
if datatype =='int':
answer = 0
# if datatype is str initialize answer as ''
if datatype =='str':
answer =''
# Traverse through the arguments
for x in args:
# This will do addition if the arguments are int. Or
concatenation if the arguments are str
answer = answer + x
print(answer)
#Integer
add('int', 5, 6)
# String
add('str', 'Hi ', 'Hello')
Polymorphism using Common
Interface
A program to demonstrate the usage of function that can take any object.
Here function flying_test acts as interface.
class Parrot:
def fly(self):
print("Parrot can fly")
def swim(self):
print("Parrot can't swim")
class Penguin:
def fly(self):
print("Penguin can't fly")
def swim(self):
print("Penguin can swim")
def flying_test(bird): # common interface
bird.fly()
blu = Parrot() #instantiate objects
peggy = Penguin()
flying_test(blu) # passing the object
flying_test(peggy)
DATA ABSTRACTION,
ENCAPSULATION, INFORMATION
HIDING
Encapsulation
 Encapsulation is defined as the wrapping up of data under a single unit.
It binds together code and the data. It prevents the data from being
accessed by the code outside ie hiding the private details of a class from
other objects.
 In encapsulation, the variables or data of a class is hidden from any

other class and can be accessed only through any member function of
its own class in which it is declared.
 As in encapsulation, the data in a class is hidden from other classes

using the data hiding concept which is achieved by making the


members or methods of a class private, and the class is exposed to the
end-user or the world without providing any details behind
implementation using the abstraction concept, so it is also known as
a combination of data-hiding and abstraction.
 Encapsulation can be achieved by Declaring all the variables in the

class as private and writing public methods in the class to set and get
the values of variables
JAVA EXAMPLE
/An Account class which is a fully encapsulated //A Java class to test the encapsulated class
class Account { Account.
private long acc_no; //private data members public class TestEncapsulation {
private String name,email; public static void main(String[] args) {
private float amount; Account acc=new Account();
public long getAcc_no() { //public getter and
//setting values through setter methods
setter methods
acc.setAcc_no(7560504000L);
return acc_no; }
acc.setName("Sonoo Jaiswal");
public void setAcc_no(long acc_no) {
acc.setEmail("sonoojaiswal@gmail.co
this.acc_no = acc_no; }
m");
public String getName() {
acc.setAmount(500000f);//getting valu
return name; }
es through getter methods
public void setName(String name) {
this.name = name;} System.out.println(acc.getAcc_no()+"
public String getEmail() { "+acc.getName()+" "+acc.getEmail()+"
return email;} "+acc.getAmount()); }
public void setEmail(String email) { }
this.email = email;}
public float getAmount() {
return amount; }
public void setAmount(float amount) {
this.amount = amount;} }
Encapsulation, Hiding &
Abstraction
 Information hiding is the principle that some internal information or
data is "hidden", so that it can't be accidentally changed
 In encapsulation, the variables of a class will be hidden from other
classes, and can be accessed only through the methods of their
current class. Therefore, it is also known as data hiding.
 Data Abstraction = Data Encapsulation + Data Hiding
 Benefits of Encapsulation
 The fields of a class can be made read-only or write-only.
 A class can have total control over what is stored in its fields.
Encapsulating Data
 Traditional object-oriented languages like Java and C# use getter
and setter method to access encapsulated data or private
data. They are also known as mutator methods.
 Getter Method is used for retrieving data and setter method is

used for setting a new value for the data.


class person:
def __init__(self, name="Guest"):
self.__name=name
def setname(self, name):
self.__name=name
def getname(self):
return self.__name
from person import person
p1=person()
p1.getname()
p1.setname('Bill')
p1.getname()
Setters and getters
 Getters and setters are used in many object oriented programming
languages to ensure the principle of data encapsulation.
 Getter and Setter method helps to access encapsulated data(declared
private).
 Getter method returns the value of the private instance attribute.
 Setter method assigns the value to the private instance attribute.
class person: #SETTERS AND GETTERS
def __init__(self, name="Guest"):
self.__name=name
def setname(self, name):
self.__name=name
def getname(self):
return self.__name
p1=person()
print(p1.getname())
p1.setname('Bill')
p1.getname()
Why Setters & Getters?
 While there is no concept of "private" attributes in Python, we could
still rewrite our class with "public" getter/setter. This is often done
because the getter and setter need to carry out certain processing,
such as data conversion in getter, or input validation in
setter.
 Getter and Setter method helps to access encapsulated
data(declared private).To avoid direct access of a class field i.e.
private variables cannot be accessed directly or modified by
external user.
 With setters and getters we have exactly one entry and one exit
point for your field, as getter/setters are methods, which allows
blocks of code, so you can do validation checks on them! The object
takes the decision whether you should set the caller value or not.
The same applies to a getter method — you can take the decision
to return the actual reference or clone it and return the same to the
caller.
Why Setters & Getters?
from math import pi
class Circle:
def __init__(self, _radius = 1.0):
self.set_radius(_radius) # Call setter
def set_radius(self, _radius):#Setter for instance variable radius with input validation
if _radius < 0:
raise ValueError('Radius shall be non-negative')
self._radius = _radius
def get_radius(self): #Getter for instance variable radius
return self._radius
def get_area(self): #Return the area of this Circle instance
return self.get_radius() * self.get_radius() * pi # Call getter
def __repr__(self):#Return a command string to recreate this instance
# Used by str() too as __str__() is not defined
return 'Circle(radius={})'.format(self.get_radius()) # Call getter
if __name__ == '__main__':
c1 = Circle(1.2) # Constructor and Initializer
print(c1) # Invoke __repr__(). Output: Circle(radius=1.200000)
print(vars(c1)) # Output: {'_radius': 1.2}
print(c1.get_area()) # Output: 4.52389342117
print(c1.get_radius()) # Run Getter. Output: 1.2
c1.set_radius(3.4) # Test Setter
print(c1) # Output: Circle(radius=3.400000)
Using property() function to achieve
getters and setters behaviour
In Python property()is a built-in function that creates and returns a
property object. A property object has three methods, getter(),
setter(), and delete(). property() function in Python has four
arguments property(fget, fset, fdel, doc), A property object has three
methods, getter(), setter(), and delete() to specify fget, fset and fdel
individually.
Parameters:
fget() – used to get the value of attribute
fset() – used to set the value of atrribute
fdel() – used to delete the attribute value
doc() – string that contains the documentation (docstring) for the
attribute
 Return: Returns a property attribute from the given getter, setter

and deleter.
 If no arguments are given, property() method returns a base

property attribute that doesn’t contain any getter, setter or deleter.


 If doc isn’t provided, property() method takes the docstring of the

getter function.
EXAMPLE
class Person: #property()
def __init__(self, name):
self._name = name
def getName(self):
print('Getting name')
return self._name
def setName(self, value):
print('Setting name to ' + value)
self._name = value
def delName(self):
print('Deleting name')
del self._name
# Set property to use getName, setName
# and delName methods
name = property(getName, setName, delName, 'Name property')
p = Person('Adam')
print(p.name)
p.name = 'John'
Property()
 A class in Python can also include properties by using the property() function.
The property() method in Python provides an interface to instance attributes
and encapsulate it.
 The property() method takes the get, set and delete methods as arguments
and returns an object of the property class. It encapsulates instance
attributes and provides a property, same as Java and C#.
Syntax: prop=property(getter, setter, deleter, docstring)
class person:
def __init__(self):
self.__name=‘’
def setname(self, name):
print('setname() called')
self.__name=name
def getname(self):
print('getname() called')
return self.__name
name=property(getname, setname)
from person import person
p1=person()
p1.name="Steve“
Property() with deleter
class person:
def __init__(self, name):
self.__name=name
def setname(self, name):
print('setname() called')
self.__name=name
def getname(self):
print('getname() called')
return self.__name
def delname(self):
print('delname() called')
del self.__name
name=property(getname, setname, delname)
from person import person
p1=person()
p1.name="Steve“
del p1.name
@property Decorator
 @property decorator allows us to define properties easily without
calling the property() function manually.
class person:
def __init__(self):
self.__name='‘
@property
def name(self):
return self.__name
@name.setter
def name(self, value):
self.__name=value
p=person()
p.name='Steve'
p.name
@setter and @deleter
 Use @[property-name].setter to call a setter method and @[property-
name].deleter to call deleter method.
class person:
def __init__(self):
self.__name=''
@property
def name(self):
return self.__name
@name.sette
def name(self, value):
self.__name=value
@name.deleter
def name(self, value):
print('Deleting..')
del self.__name
p=person()
p.name='Steve'
p.name
del p.name
Data Hiding
 In Python, data hiding is achieved by using double underscore (__)
before the attributes name to hide it.
 After this, the attribute will not be visible outside of the class
through the object.
 access of hidden variable outside the class using object will threw
an exception.
 To change the value of hidden variables use a setter function which
takes hidden variable as parameter.
 In Python, we denote private attribute using underscore as prefix
double “ __“.
 So variables can be treated as private data members
Data Hiding
class MyClass:
__hiddenVariable = 0 # Hidden member of MyClass

# A member method that changes __hiddenVariable


def add(self, increment):
self.__hiddenVariable += increment
print (self.__hiddenVariable)
# Driver code
myObject = MyClass()
myObject.add(2)
myObject.add(5)
# This line causes error
print (myObject.__hiddenVariable)
#Error can be removed if we use
print (myObject._MyClass__hiddenVariable)
EXAMPLE
class Employee:
__count = 0;
def __init__(self):
Employee.__count = Employee.__count+1
def display(self):
print("The number of employees",Employee.__count)

emp = Employee()
emp2 = Employee()
try:
print(emp.__count)
finally:
emp.display()
Changing value of hidden variable
class Computer:
def __init__(self):
self.__maxprice = 900
def sell(self):
print("Selling Price: {}".format(self.__maxprice))
def setMaxPrice(self, price):
self.__maxprice = price
c = Computer()
c.sell()
# change the price
c.__maxprice = 1000
c.sell()
# using setter function
c.setMaxPrice(1000)
c.sell()
ABSTRACT CLASS
 Abstract classes are classes that contain one or more abstract methods.
 An abstract method is a method that is declared, but contains no
implementation. Abstract method decorator should be added
 Abstract classes may not be instantiated, and require subclasses to provide
implementations for the abstract methods. Subclasses of an abstract class
in Python are not required to implement abstract methods of the
parent class.
 Python on its own doesn't provide abstract classes. Yet, Python comes with a
module which provides the infrastructure for defining Abstract Base Classes
(ABCs). This module is called - for obvious reasons - abc.
 Abstract class cannot be instantiated. This means you cannot create objects
or instances for these classes. It can only be used for inheriting certain
functionalities which you call as a base class. So you can inherit functionalities
but at the same time, you cannot create an instance of this particular class.
 A class that is derived from an abstract class cannot be instantiated unless all
of its abstract methods are overridden. Ie, Sub-class inheriting abstract
classes should provide definition of abstract method else it will throw
an error.
 NOTE: An abstract method can have an implementation in the abstract
class! Even if they are implemented, designers of subclasses will be
forced to override the implementation.
Data Abstraction
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
def __init__(self, value):
self.value = value
@abstractmethod
def do_something(self):
pass
from abc import ABC, abstractmethod
class Employee(ABC):
@abstractmethod
def calculate_salary(self,sal):
pass
class Developer(Employee):
def calculate_salary(self,sal):
finalsalary= sal*1.10
return finalsalary
emp_1=Developer()
print(emp_1.calculate_salary(10000))
from abc import ABC, from abc import ABC, abstractmethod
abstractmethod class AbstractClassExample(ABC):
class def __init__(self, value):
AbstractClassExample(ABC):
self.value = value
def __init__(self,
super().__init__()
value):
@abstractmethod
self.value =
value def do_something(self):
pass
super().__init__() class
@abstractmethod DoAdd42(AbstractClassExample):
def def do_something(self):
do_something(self): return self.value + 42
pass
class
class DoMul42(AbstractClassExample):
DoAdd42(AbstractClassExample
def do_something(self):
):
pass return self.value * 42
x = DoAdd42(4)#will throw x = DoAdd42(10)
error y = DoMul42(10)
print(x.do_something())
print(y.do_something())
EXAMPLE
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
@abstractmethod
def do_something(self):
print("Some implementation!")
@abstractmethod
def another_method(self):
pass
class AnotherSubclass(AbstractClassExample):
def do_something(self):
super().do_something()
print("The enrichment from AnotherSubclass")
def another_method(self):
print("this is also implemented")
x = AnotherSubclass()
x.do_something()
EXCEPTION HANDLING IN PYTHON
Errors & Exceptions
 In Python, abnormal behavior can be due to an error or an exception. A
Python program terminates as soon as it encounters an error.
1. Errors can be Syntax Error Error(due to poor understanding of Language ie
when the parser detects an incorrect statement due to improper structure
(syntax) of the language) and Logical Error(due to poor understanding of
problem).
print( 4 / 2 ) )
File "<stdin>", line 1 print( 4 / 2 )) ^
SyntaxError: invalid syntax
2. Exception: Even if a statement or expression is syntactically correct, it may
cause an error when an attempt is made to execute it. Errors detected during
execution are called exceptions. An exception is an error or abnormal
condition that happens during execution of a program which can cause
termination of program. Exceptions can be synchronous exception(divide by
zero, araay index out of bound) which are controlled by program and
asynchronous exception(hardware malfunction, disk failure, keyboard
interrupt). Eg: IndexError, ImportError, IOError, ZeroDivisionError, TypeError.
Most exceptions are not handled by programs, however, and result in error
messages as shown
10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
 Tracebacks are generated due to runtime errors.
ERROR HANDLING
 Python provides two very important ways to handle any unexpected
error:
 Exception Handling : An exception is an event, which occurs during
the execution of a program that disrupts the normal flow of the
program's instructions.
 Assertions: An assertion is a sanity-check that you can turn on or
turn off when you are done with your testing of the program.
Exception Handling in Python
 An exception is an event which occurs during execution of a
program and disrupts normal flow of execution.
 Since program cannot handle the situation it raises an exception which
is a python object that represents the error.
 When a program generate an exception it must be be handled, which
avoids your program to crash.
print( 0 / 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
 In the above code exceptions are not handled and error message of string
type indicating type of exception is printed. It’s a built in exception.
 Exception is the base class for all the exceptions in python.
 Python provides us some basic exception classes which are already defined
under Exception class and can be used in generic cases.
Built in Exception Classes
Exception Class Event
ArithmeticError Raised when numeric calculations fails
FloatingPointError Raised when a floating point calculation fails
Raised when division or modulo by zero takes place for
ZeroDivisionError
all numeric types
AssertionError Raised when Assert statement fails
Raised when result of an arithmetic operation is too
OverflowError
large to be represented
ImportError Raised when the imported module is not found
IndexError Raised when index of a sequence is out of range
KeyboardInterrup Raised when the user interrupts program execution,
t generally by pressing Ctrl+c
IndentationError Raised when there is incorrect indentation
SyntaxError Raised by parser when syntax error is encountered
Raised when the specified key is not found in the
KeyError
dictionary
Raised when an identifier is not found in the local or
NameError
global namespace
Exception Handling in Python
 Exception handling in Python is done by following methods:
 Try block: Python executes code following the try statement as a

“normal” part of the program. All statements are executed until an


exception is encountered.
 Except block: The code that follows the except statement is the program’s

response to any exceptions in the preceding tryclause. It is used to catch


and handle the exception(s) that are encountered in the try clause.
 Else Block: instruct a program to execute a certain block of code only in

the absence of exceptions. It lets you code sections that should run only
when no exceptions are encountered in the try clause.
 Finally: finally enables you to execute sections of code that should always

run, with or without any previously encountered exceptions.


Try & Except
 A critical operation that can raise an exception is put under try block. Once
the exception occurs remaining statements of try block are skipped. A
specific type of exception in front of the except keyword. The except
block will be executed only if the specified exception occurs. Exception
handler code is written inside except block. It can be an information like
what, why and how something went wrong.
Syntax: try :
#Put statements which are likely to encounter an exception.
except ExceptionName:
#executed when error in try block
#except block without exception #Except block with exception
try:
 Example: try:
a=5 a=5
b='0' b='0'
print(a/b) print (a+b)
except: except TypeError:
print('Some error occurred.') print('Unsupported type')
print("Out of try except blocks.") print("Out of try except
block")
try with multiple except blocks
A sing try block can have multiple except blocks. The block that matches
exception will get executed and it will be only one.
try:
a=5
b=0
print (a/b)
except TypeError:
print('Unsupported operation')
except ZeroDivisionError:
print ('Division by zero not allowed')
print ('Out of try except blocks')
 An except clause can have multiple exceptions as a paranthesized tuple.
#multiple exceptions in a single block
try:
x=int(input('Enter a number: '))
print(num**2)
except (KeyboardInterrupt,ValueError, TypeError):
print("please check the value you enter before")
Else block
 Try block can optionally have else clause. The else block gets processed if
the try block is found to be exception free. It must be the last block.
try:
print("try block")
x=int(input('Enter a number: '))
y=int(input('Enter another number: '))
z=x/y
except ZeroDivisionError:
print("except ZeroDivisionError block")
print("Division by 0 not accepted")
else:
print("else block")
print("Division = ", z)
print ("Out of try, except, and else blocks." )
Finally block
 finally block consists of statements which should be processed
regardless of an exception occurring in the try block or not. It is
used for clean up actions(file handling, network connections,
memory resources) as it will be executed under all circumstances.
 We cannot have an else block with a finally block

try:
print("try block")
x=int(input('Enter a number: '))
y=int(input('Enter another number: '))
z=x/y
except ZeroDivisionError:
print("except ZeroDivisionError block")
print("Division by 0 not accepted")
finally:
print("finally block")
print ("Out of try, except, else and finally blocks." )
Raising an Exception
 raise : It is used to throw an exception explicitly if a condition occurs ie a
specified exception to occur. The statement can be complemented with a
custom exception as well.
 Syntax: raise[Exception[,args[,traceback]]]

x = 10
if x > 5:
raise Exception('x should not exceed 5. The value of x
was: {}'.format(x))
The program comes to a halt and displays our exception to screen, offering
clues about what went wrong. Means just to raise exception without handling
it as except block is not there
try:
x=int(input('Enter a number upto 100: '))
if x > 100:
raise ValueError(x)
except ValueError:
print(x, "is out of allowed range")
else:
print(x, "is within the allowed range")
Assertion in Python
 assert enables you to verify if a certain condition is met and throw
an exception if it isn’t. It prevents program from crashing. If the
condition is True, then program can continue. If the is False, then
program throw an AssertionError exception.
Syntax: assert expression[,arguments]
num=int(input('Enter a number: '))
assert num>=0
print('You entered: ', num)
The assert statement can optionally include an error message string,
which gets displayed along with the AssertionError.
num=int(input('Enter a number: '))
assert num>=0, "Only positive numbers accepted."
print('You entered: ', num)
 The program will come to halt and will not continue.
 To continue the error has to be handled by try..except block.
AssertionError
 Python assert keyword is defined as a debugging tool that tests a condition. The
AssertionError is also a built-in exception and can be handled using the
try...except construct
try:
num=int(input('Enter a number: '))
assert(num >=0), "Only positive numbers accepted.”
print(num)
except AssertionError as msg:
print(msg)
 It is merely a Boolean expression that has a condition or expression checks
if the condition returns true or false. If it is true, the program does not do
anything, and it moves to the next line of code. But if it is false, it raises
an AssertionError exception with an optional error message.
 When the input causes an AssertionError, the program will not terminate,
as was the case earlier. Instead, it will be handled by the except block. The
error message in the assert statement will be passed as argument to the
exception argument msg, using keyword as.
 as is a keyword that allowsz programmers to name a variable within an
except statement.
Why Assertion is used?
It is a debugging tool, and its primary task is to check the
condition. If it finds that the condition is true, it moves to the next
line of code, and If not, then stops all its operations and throws an
error. It points out the error in the code.
Where Assertion in Python used?
1. Checking the outputs of the functions.
2. Used for testing the code.
3. In checking the values of arguments.
4. Checking the valid input.
 If the assertion fails, Python uses ArgumentExpression as the
argument for the AssertionError. AssertionError exceptions can be
caught and handled like any other exception using the try-except
statement, but if not handled, they will terminate the program and
produce a traceback.
User Defined Exceptions
 Programmers can name their own exceptions by creating a new exception
class
 Exceptions should typically be derived from the Exception class.
 When creating a module that can raise several distinct errors, a common
practice is to create a base class for exceptions defined by that module,
and subclass that to create specific exception classes for different error
conditions.
#Custom exceptions
class myError(Exception):
def __init__(self,val):
self.val=val
def __str__(self):
return repr(self.val)
try:
raise myError(10)
except myError as e:
print("User defined exception generated with", e.val)
EXAMPLE 1
#User Defined Exceptions
class Error(Exception): #Base class for other exceptions
pass
class ValueTooSmallError(Error): #Raised when the input value is too small
pass
class ValueTooLargeError(Error): #Raised when the input value is too large
pass
number = 10 # Driver main program
while True:
try:
i_num = int(input("Enter a number: "))
if i_num < number:
raise ValueTooSmallError
elif i_num > number:
raise ValueTooLargeError
break
except ValueTooSmallError:
print("This value is too small, try again!")
print()
except ValueTooLargeError:
DECORATORS
 functions are the first class objects, which means that –
 Functions are objects; they can be referenced to, passed to a variable
and returned from other functions as well.
 Functions can be defined inside another function and can also be
passed as argument to another function.
 Decorators allows programmers to modify the behavior of function
or class. Decorators allow us to wrap another function in order to
extend the behavior of wrapped function, without permanently
modifying it.
 In Decorators, functions are taken as the argument into another
function and then called inside the wrapper function.
 Decorators allow you to make simple modifications to callable
objects like functions, methods, or classes.
 a decorator is just another function which takes a functions and
returns one.
Decorators
 a decorator takes in a function, adds some functionality and
returns it.
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
def ordinary():
print("I am ordinary")
ordinary()
pretty = make_pretty(ordinary)
 make_pretty() is a decorator. The function ordinary() got decorated
and the returned function was given the name pretty.
 The decorator acts as a wrapper. The nature of the object that got
decorated (actual gift inside) does not alter. But now, it looks
pretty (since it got decorated). we decorate a function and reassign
it as, ordinary = make_pretty(ordinary).
Decorators
 Python has a syntax to simplify decorator, we can use
the @ symbol along with the name of the decorator function and
place it above the definition of the function to be decorated.
@make_pretty
def ordinary():
print("I am ordinary")
is equivalent to
def ordinary():
print("I am ordinary")
ordinary = make_pretty(ordinary)
print(oridinary())
 Reusing Decorators

You might also like