Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
20 views

Python Unit 2

Uploaded by

Bindu
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views

Python Unit 2

Uploaded by

Bindu
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

Unit 2: Classes in Python: OOPS Concepts, Classes and objects , Classes in Python, Constructors, Data hiding,

Creating Classes, Instance Methods, Special Methods, Class Variables, Inheritance, Polymorphism, Type
Identification, Custom Exception Classes, Iterators, generators and decorators.

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:

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()
The self Parameter
The self is used to represent the instance of the class. With this keyword, you can access the attributes and methods
of the class in python. It binds the attributes with the given arguments. The reason why we use self is that Python
does not use the ‘@’ syntax to refer to instance attributes.

self is a parameter in function and the user can use a different parameter name in place of it. Although it is
advisable to use self because it increases the readability of code.
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

Special Methods

Special Methods are variety of instance methods that are reserved by Python, which affect an object’s high level
behaviour and its interactions with operators. These are known as special methods. __init__ is an example of a
special method; recall that it controls the process of creating instances of a class.

Similarly, we will see that __add__ controls the behaviour of an object when it is operated on by the + symbol,
for example. In general, the names of special methods take the form of __<name>__ , where the two underscores
precede and succeed the name. Accordingly, special methods can also be referred to as “dunder” (double-
underscore) methods. Learning to leverage special methods will enable us to design elegant and powerful classes
of objects.

The following special methods control how an object interacts with + , * , ** , and other mathematical operators.

A full listing of all the special methods used to emulate numeric types are

Method Signature Explanation

Add __add__(self, other) x + y invokes x.__add__(y)

Subtract __sub__(self, other) x - y invokes x.__sub__(y)

Multiply __mul__(self, other) x * y invokes x.__mul__(y)

Divide __truediv__(self, other) x / y invokes x.__truediv__(y)

Power __pow__(self, other) x ** y invokes x.__pow__(y)

Constructor in Python
Constructor in Python is a special method which is used to initialize the members of a class during run-time when
an object is created.
In Python, we have some special built-in class methods which start with a double underscore (__) and they have a
special meaning in Python.

The name of the constructor will always be __init__().

Every class must have a constructor, even if you don’t create a constructor explicitly it will create a default
constructor by itself.

Example:
class MyClass:
sum = 0

def __init__ (self, a, b):


self.sum = a+b

def printSum(self):
print(“Sum of a and b is: ”, self.sum)

#Creating an object of class MyClass


ob = MyClass(12, 15)
ob.printSum()
Output:
Sum of a and b is: 27

Data hiding

Data hiding means making the data private so that it will not be accessible to the other class members. It can be
accessed only in the class where it is declared.

In python, if we want to hide the variable, then we need to write double underscore (__) before the variable name.

Example:
Class MyClass:
__num = 10
def add(self, a):
sum = self.__num + a
print(sum)

ob = MyClass()
ob.add(20)

print(ob.__num)

#The above statement gives an error because we are trying to access private variable outside the class
Output:
30
Traceback (most recent call last):
File “DataHiding.py”, line 10, in
print (ob.__num)
AttributeError: MyClass instance has
no attribute ‘__num

Inheritance

Inheritance is one of the most powerful concepts of OOPs.

A class which inherits the properties of another class is called Inheritance.


The class which inherits the properties is called child class/subclass and the class from which properties are
inherited is called parent class/base class.

Python provides three types of Inheritance:


• Single Inheritance
• Multilevel Inheritance
• Multiple Inheritance
Recommended Reading =>> Inheritance in Java
#1) Single Inheritance
In Single inheritance, one class will inherit the properties of one class only.

Example:
class Operations:
a = 10
b = 20
def add(self):
sum = self.a + self.b
print(“Sum of a and b is: “, sum)

class MyClass(Operations):
c = 50
d = 10
def sub(self):
sub = self.c – self.d
print(“Subtraction of c and d is: ”, sub)

ob = MyClass()
ob.add()
ob.sub()
Output:
Sum of a and b is: 30
Subtraction of c and d is: 40

In the above example, we are inheriting the properties of the ‘Operations’ class into the class ‘MyClass’.

Hence, we can access all the methods or statements present in the ‘Operations’ class by using the MyClass objects.

#2) Multilevel Inheritance


In multilevel Inheritance, one or more class act as a base class.

Which means the second class will inherit the properties of the first class and the third class will inherit the
properties of the second class. So the second class will act as both the Parent class as well as Child class.

Example:
class Addition:
a = 10
b = 20
def add(self):
sum = self.a + self.b
print(“Sum of a and b is: ”, sum)

class Subtraction(Addition):
def sub(self):
sub = self.b-self.a
print(“Subtraction of a and b is: ”, sub)

class Multiplication(Subtraction):
def mul(self):
multi = self.a * self.b
print(“Multiplication of a and b is: ”, multi)

ob = Multiplication ()
ob.add()
ob.sub()
ob.mul()
Output:
Sum of a and b is: 30
Subtraction of a and b is: 10
Multiplication of a and b is: 200

In the above example, class ‘Subtraction’ inherits the properties of class ‘Addition’ and class ‘Multiplication’ will
inherit the properties of class ‘Subtraction’. So class ‘Subtraction’ will act as both Base class and derived class.

#3) Multiple Inheritance


The class which inherits the properties of multiple classes is called Multiple Inheritance.

Further Reading =>> Does Java support Multiple Inheritance?


Example:
class Addition:
a = 10
b = 20
def add(self):
sum = self. a+ self.b
print(“Sum of a and b is: “, sum)

class Subtraction():
c = 50
d = 10
def sub(self):
sub = self.c-self.d
print(“Subtraction of c and d is: ”, sub)

class Multiplication(Addition,Subtraction):
def mul(self):
multi = self.a * self.c
print(“Multiplication of a and c is: ”, multi)

ob = Multiplication ()
ob.add()
ob.sub()
ob.mul()
Output:
Sum of a and b is: 30
Subtraction of c and d is: 10
Multiplication of a and c is: 50

Python Inheritance
The inheritance is one of the important feature in object oriented programming, that gives you a way to reuse of
code.

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()

Polymorphism

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 is used in Python programs when you have commonly named methods in two or more classes or
subclasses. It allows these methods to use objects of different types at different times. So, it provides flexibility,
using which a code can be extended and easily maintained over time.
Python allows us to define polymorphism in different ways. So, let us go ahead and see how it works.

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

class Rectangle:
def __init__(self, length, breadth):
self.l = length
self.b = breadth
def perimeter(self):
return 2*(self.l + self.b)
def area(self):
return self.l * self.b

class Circle:
def __init__(self, radius):
self.r = radius
def perimeter(self):
return 2 * 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
type() function in Python

type() method returns class type of the argument(object) passed as parameter. type() function is mostly used for
debugging purposes.

Two different types of arguments can be passed to type() function, single and three argument. If single argument
type(obj) is passed, it returns the type of given object. If three arguments type(name, bases, dict) is passed, it
returns a new type object.

Syntax :

type(object)
type(name, bases, dict)
Parameters :

name : name of class, which later corresponds to the __name__ attribute of the class.
bases : tuple of classes from which the current class derives. Later corresponds to the __bases__ attribute.
dict : a dictionary that holds the namespaces for the class. Later corresponds to the __dict__ attribute.
Returntype :

returns a new type class or essentially a metaclass.

Example :

# Python3 code to explain


# the type() function

# Class of type dict


class DictType:
DictNumber = {1:'John', 2:'Wick', 3:'Barry', 4:'Allen'}

# Class of type list


class ListType:
ListNumber = [1, 2, 3, 4, 5]

# Creating object of each class


d = DictType()
l = ListType()

# Will print accordingly whether both


# the objects are of same type or not
if type(d) is not type(l):
print("Both class have different object type.")
else:
print("Same Object type")

Output :

Both class have different object type.

Iterators in Python
Iterator in python is an object that is used to iterate over iteratable objects like lists, tuples, dicts, and sets. The
iterator object is initialized using the iter() method. It uses the next() method for iteration.

mytuple = ("apple", "banana", "cherry")


myit = iter(mytuple)

print(next(myit))
print(next(myit))
print(next(myit))

We can also use a for loop to iterate through an iterable object:

Example:

mytuple = ("apple", "banana", "cherry")

for x in mytuple:
print(x)

The for loop actually creates an iterator object and executes the next() method
for each loop.
Create an Iterator

To create an object/class as an iterator you have to implement the


methods __iter__() and __next__() to your object.

All classes have a function called __init__(), which allows you to do some
initializing when the object is being created.

The __iter__() method acts similar, you can do operations (initializing etc.), but
must always return the iterator object itself.

The __next__() method also allows you to do operations, and must return the
next item in the sequence.

Example
Create an iterator that returns numbers, starting with 1, and each sequence
will increase by one (returning 1,2,3,4,5 etc.):

class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
x = self.a
self.a += 1
return x

myclass = MyNumbers()
myiter = iter(myclass)

print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))

StopIteration

The example above would continue forever if you had enough next()
statements, or if it was used in a for loop.

To prevent the iteration to go on forever, we can use


the StopIteration statement.

In the __next__() method, we can add a terminating condition to raise an error


if the iteration is done a specified number of times:
Example

Stop after 20 iterations:


class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration

myclass = MyNumbers()
myiter = iter(myclass)

for x in myiter:
print(x)

There are two terms involved when we discuss generators.

Generator-Function : A generator-function is defined like a normal function, but whenever it needs to generate a
value, it does so with the yield keyword rather than return. If the body of a def contains yield, the function
automatically becomes a generator function.
# A generator function that yields 1 for first time,
# 2 second time and 3 third time
def simpleGeneratorFun():
yield 1
yield 2
yield 3

# Driver code to check above generator function


for value in simpleGeneratorFun():
print(value)

Generator-Object : Generator functions return a generator object. Generator objects are used either by calling the
next method on the generator object or using the generator object in a “for in” loop (as shown in the above
program).

# A Python program to demonstrate use of


# generator object with next()

# A generator function
def simpleGeneratorFun():
yield 1
yield 2
yield 3

# x is a generator object
x = simpleGeneratorFun()

# Iterating over the generator object using next


print(x.next()) # In Python 3, __next__()
print(x.next())
print(x.next())

Decorators are a very powerful and useful tool in Python since it allows programmers to modify the behaviour of
function or class. Decorators allow us to wrap another function in order to extend the behaviour of the wrapped
function, without permanently modifying it. But before diving deep into decorators let us understand some
concepts that will come in handy in learning the decorators.

First Class Objects


In Python, functions are first class objects that mean that functions in Python can be used or passed as arguments.
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, …
Consider the below examples for better understanding.
Example 1: Treating the functions as objects.

# Python program to illustrate functions


# can be treated as objects
def shout(text):
return text.upper()

print(shout('Hello'))

yell = shout

print(yell('Hello'))

Method Overloading in Python

Multiple methods with the same name but with a different type of parameter or a different number of parameters is
called Method overloading

Example:
def product(a, b):
p = a*b
print(p)

def product(a, b, c):


p = a*b*c
print(p)

#Gives you an error saying one more argument is missing as it updated to the second function
#product(2, 3)
product(2, 3, 5)
Output:
30

Conclusion
The class is a blueprint or template which contains all the details of an object, where the object is an instance of a
class.

• If we want to get the properties of another class into a class, then this can be achieved by
inheritance.
• Inheritance is of 3 types- Single Inheritance, Multilevel Inheritance, and Multiple Inheritance.
• Method overloading is not supported in Python.
• Method overriding is used to override the implementation of the same function which is defined
in another class.
• We can make the data attributes as private or hide them so that it will not be accessible outside
the class where it is defined.

Python Decorators
A decorator takes in a function, adds some functionality and returns it.

Decorators in Python
Python has an interesting feature called decorators to add functionality to an existing
code.
This is also called metaprogramming because a part of the program tries to modify
another part of the program at compile time.
Decorating Functions with Parameters

def divide(a, b):


return a/b

This function has two parameters, a and b . We know it will give an error if we pass
in b as 0.

>>> divide(2,5)
0.4
>>> divide(2,0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero

Now let's make a decorator to check for this case that will cause the error.

def smart_divide(func):
def inner(a, b):
print("I am going to divide", a, "and", b)
if b == 0:
print("Whoops! cannot divide")
return

return func(a, b)
return inner
@smart_divide
def divide(a, b):
print(a/b)

This new implementation will return None if the error condition arises.

>>> divide(2,5)
I am going to divide 2 and 5
0.4

>>> divide(2,0)
I am going to divide 2 and 0
Whoops! cannot divide

In this manner, we can decorate functions that take parameters.

You might also like