0% found this document useful (0 votes)
33 views

Unit 3

Uploaded by

Dr.M.Sangeetha
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views

Unit 3

Uploaded by

Dr.M.Sangeetha
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 60

6

PYTHON PROGRAMMING - I – M.Sc CS

UNIT – III
Python Modules
In this article, you will learn to create and import custom modules in Python. Also, you will
find different techniques to import and use custom and built-in modules in Python.
What are modules in Python?
Modules refer to a file containing Python statements and definitions.
A file containing Python code, for example: example.py, is called a module, and its module
name would be example.
We use modules to break down large programs into small manageable and organized files.
Furthermore, modules provide reusability of code.
We can define our most used functions in a module and import it, instead of copying their
definitions into different programs.
Let us create a module. Type the following and save it as example.py.

# Python Module example

def add(a, b):


"""This program adds two
numbers and return the result"""

result = a + b
return result

Here, we have defined a function add() inside a module named example. The function takes
in two numbers and returns their sum.

How to import modules in Python?


We can import the definitions inside a module to another module or the interactive interpreter
in Python.
We use the import keyword to do this. To import our previously defined module example,
we type the following in the Python prompt.
6

PYTHON PROGRAMMING - I – M.Sc CS

>>> import example

This does not import the names of the functions defined in example directly in the current
symbol table. It only imports the module name example there.
Using the module name we can access the function using the dot . operator. For example:

>>> example.add(4,5.5)
9.5

Python has tons of standard modules. You can check out the full list of Python standard
modules and their use cases. These files are in the Lib directory inside the location where you
installed Python.
Standard modules can be imported the same way as we import our user-defined modules.
There are various ways to import modules. They are listed below..

Python import statement


We can import a module using the import statement and access the definitions inside it using
the dot operator as described above. Here is an example.

# import statement example


# to import standard module math

import math
print("The value of pi is", math.pi)

When you run the program, the output will be:

The value of pi is 3.141592653589793

Import with renaming


6

PYTHON PROGRAMMING - I – M.Sc CS

We can import a module by renaming it as follows:

# import module by renaming it

import math as m
print("The value of pi is", m.pi)

We have renamed the math module as m. This can save us typing time in some cases.
Note that the name math is not recognized in our scope. Hence, math.pi is invalid,
and m.pi is the correct implementation.

Python from...import statement


We can import specific names from a module without importing the module as a whole. Here
is an example.

# import only pi from math module

from math import pi


print("The value of pi is", pi)

Here, we imported only the pi attribute from the math module.


In such cases, we don't use the dot operator. We can also import multiple attributes as
follows:

>>> from math import pi, e


>>> pi
3.141592653589793
>>> e
2.718281828459045
6

PYTHON PROGRAMMING - I – M.Sc CS

Import all names


We can import all names(definitions) from a module using the following construct:

# import all names from the standard module math

from math import *


print("The value of pi is", pi)

Here, we have imported all the definitions from the math module. This includes all names
visible in our scope except those beginning with an underscore(private definitions).
Importing everything with the asterisk (*) symbol is not a good programming practice. This
can lead to duplicate definitions for an identifier. It also hampers the readability of our code.

Python Module Search Path


While importing a module, Python looks at several places. Interpreter first looks for a built-in
module. Then(if built-in module not found), Python looks into a list of directories defined
in sys.path. The search is in this order.
 The current directory.
 PYTHONPATH (an environment variable with a list of directories).
 The installation-dependent default directory.

>>> import sys


>>> sys.path
['',
'C:\\Python33\\Lib\\idlelib',
'C:\\Windows\\system32\\python33.zip',
'C:\\Python33\\DLLs',
'C:\\Python33\\lib',
'C:\\Python33',
'C:\\Python33\\lib\\site-packages']

We can add and modify this list to add our own path.
6

PYTHON PROGRAMMING - I – M.Sc CS

Reloading a module
The Python interpreter imports a module only once during a session. This makes things more
efficient. Here is an example to show how this works.
Suppose we have the following code in a module named my_module.

# This module shows the effect of


# multiple imports and reload

print("This code got executed")

Now we see the effect of multiple imports.

>>> import my_module


This code got executed
>>> import my_module
>>> import my_module

We can see that our code got executed only once. This goes to say that our module was
imported only once.
Now if our module changed during the course of the program, we would have to reload
it.One way to do this is to restart the interpreter. But this does not help much.
Python provides a more efficient way of doing this. We can use the reload() function inside
the imp module to reload a module. We can do it in the following ways:

>>> import imp


>>> import my_module
This code got executed
>>> import my_module
>>> imp.reload(my_module)
This code got executed
<module 'my_module' from '.\\my_module.py'>
6

PYTHON PROGRAMMING - I – M.Sc CS

The dir() built-in function


We can use the dir() function to find out names that are defined inside a module.
For example, we have defined a function add() in the module example that we had in the
beginning.
We can use dir in example module in the following way:

>>> dir(example)
['__builtins__',
'__cached__',
'__doc__',
'__file__',
'__initializing__',
'__loader__',
'__name__',
'__package__',
'add']

Here, we can see a sorted list of names (along with add). All other names that begin with an
underscore are default Python attributes associated with the module (not user-defined).
For example, the __name__ attribute contains the name of the module.

>>> import example


>>> example.__name__
'example'

All the names defined in our current namespace can be found out using the dir() function
without any arguments.

>>> a = 1
>>> b = "hello"
>>> import math
>>> dir()
6

PYTHON PROGRAMMING - I – M.Sc CS

['__builtins__', '__doc__', '__name__', 'a', 'b', 'math', 'pyscripter']

Python - Command Line Arguments

Python provides a getopt module that helps you parse command-line options and arguments.
$ python test.py arg1 arg2 arg3

The Python sys module provides access to any command-line arguments via the sys.argv.
This serves two purposes −

 sys.argv is the list of command-line arguments.


 len(sys.argv) is the number of command-line arguments.

Here sys.argv[0] is the program ie. script name.

Example

Consider the following script test.py −


#!/usr/bin/python

import sys

print 'Number of arguments:', len(sys.argv), 'arguments.'


print 'Argument List:', str(sys.argv)

Now run above script as follows −


$ python test.py arg1 arg2 arg3

This produce following result −


Number of arguments: 4 arguments.
Argument List: ['test.py', 'arg1', 'arg2', 'arg3']

NOTE − As mentioned above, first argument is always script name and it is also being
counted in number of arguments.

Parsing Command-Line Arguments


6

PYTHON PROGRAMMING - I – M.Sc CS

Python provided a getopt module that helps you parse command-line options and
arguments. This module provides two functions and an exception to enable command line
argument parsing.

getopt.getopt method

This method parses command line options and parameter list. Following is simple syntax for
this method −
getopt.getopt(args, options, [long_options])

Here is the detail of the parameters −

 args − This is the argument list to be parsed.


 options − This is the string of option letters that the script wants to recognize, with
options that require an argument should be followed by a colon (:).
 long_options − This is optional parameter and if specified, must be a list of strings
with the names of the long options, which should be supported. Long options, which
require an argument should be followed by an equal sign ('='). To accept only long
options, options should be an empty string.
 This method returns value consisting of two elements: the first is a list of (option,
value) pairs. The second is the list of program arguments left after the option list was
stripped.
 Each option-and-value pair returned has the option as its first element, prefixed with
a hyphen for short options (e.g., '-x') or two hyphens for long options (e.g., '--long-
option').

Exception getopt.GetoptError

This is raised when an unrecognized option is found in the argument list or when an option
requiring an argument is given none.

The argument to the exception is a string indicating the cause of the error. The
attributes msg and opt give the error message and related option.

Example

Consider we want to pass two file names through command line and we also want to give an
option to check the usage of the script. Usage of the script is as follows −
6

PYTHON PROGRAMMING - I – M.Sc CS

usage: test.py -i <inputfile> -o <outputfile>

Here is the following script to test.py −


#!/usr/bin/python

import sys, getopt

def main(argv):
inputfile = ''
outputfile = ''
try:
opts, args = getopt.getopt(argv,"hi:o:",["ifile=","ofile="])
except getopt.GetoptError:
print 'test.py -i <inputfile> -o <outputfile>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'test.py -i <inputfile> -o <outputfile>'
sys.exit()
elif opt in ("-i", "--ifile"):
inputfile = arg
elif opt in ("-o", "--ofile"):
outputfile = arg
print 'Input file is "', inputfile
print 'Output file is "', outputfile

if __name__ == "__main__":
main(sys.argv[1:])

Now, run above script as follows −


$ test.py -h
usage: test.py -i <inputfile> -o <outputfile>
6

PYTHON PROGRAMMING - I – M.Sc CS

$ test.py -i BMP -o
usage: test.py -i <inputfile> -o <outputfile>

$ test.py -i inputfile
Input file is " inputfile
Output file is "

Python Programming/Standard Library

The Python Standard Library is a collection of script modules accessible to a Python program
to simplify the programming process and removing the need to rewrite commonly used
commands. They can be used by 'calling/importing' them at the beginning of a script.

It is important to become familiar with the Python Standard Library as so many problems can
be solved quickly if you are familiar with the things that these libraries can do.

A list of the Standard Library modules, the following are among the most important:

 Time
The datetime module provides us with the objects which we can use to store information
about date and time: are not associated with a

 sys - sys:

The sys module contains system-specific functionality. The sys module has a
version_info tuple that gives us information about the version.

 math

The math module is a collection of mathematical functions. They are used on


integers and on floats as well but are mostly used on floats and usually return
floats too.

 Random
6

PYTHON PROGRAMMING - I – M.Sc CS

This module is used to generate pseudo-random numbers (sequence of numbers)


and also do some more things depending on randomness. The main function of
this module generates a random float between 0 and 1 and most of the other
functions are derived from it.
 urllib
urllib module is used to handle and fetch URLs. urllib is a package that collects several
modules for working with URLs like

 re

This module allows us to write regular expressions (mini-language for matching


strings and can be used to find and replace text). The re module not only explains
how to use the module but also contains a reference for the complete regular
expression syntax which the python supports.

Python Objects and Classes

Python is an object-oriented programming language. Unlike procedure-oriented


programming, where the main emphasis is on functions, object-oriented programming
stresses on objects.

An object is simply a collection of data (variables) and methods (functions) that act on those
data. Similarly, a class is a blueprint for that object.

We can think of a class as a sketch (prototype) of a house. It contains all the details about the
floors, doors, windows, etc. Based on these descriptions we build the house. House is the
object.

As many houses can be made from a house's blueprint, we can create many objects from a
class. An object is also called an instance of a class and the process of creating this object is
called instantiation.
6

PYTHON PROGRAMMING - I – M.Sc CS

Defining a Class in Python

Like function definitions begin with the def keyword in Python, class definitions begin with
a class keyword.
The first string inside the class is called docstring and has a brief description of the class.
Although not mandatory, this is highly recommended.

Here is a simple class definition.

class MyNewClass:
'''This is a docstring. I have created a new class'''
pass

A class creates a new local namespace where all its attributes are defined. Attributes may be
data or functions.
There are also special attributes in it that begins with double underscores __. For
example, __doc__ gives us the docstring of that class.
As soon as we define a class, a new class object is created with the same name. This class
object allows us to access the different attributes as well as to instantiate new objects of that
class.

class Person:
"This is a person class"
age = 10

def greet(self):
print('Hello')

# Output: 10
print(Person.age)
6

PYTHON PROGRAMMING - I – M.Sc CS

# Output: <function Person.greet>


print(Person.greet)

# Output: "This is a person class"


print(Person.__doc__)

Output

10
<function Person.greet at 0x7fc78c6e8160>
This is a person class

Creating an Object in Python

We saw that the class object could be used to access different attributes.

It can also be used to create new object instances (instantiation) of that class. The procedure
to create an object is similar to a function call.

>>> harry = Person()

This will create a new object instance named harry. We can access the attributes of objects
using the object name prefix.
Attributes may be data or method. Methods of an object are corresponding functions of that
class.

This means to say, since Person.greet is a function object (attribute of


class), Person.greet will be a method object.

class Person:
"This is a person class"
age = 10
6

PYTHON PROGRAMMING - I – M.Sc CS

def greet(self):
print('Hello')

# create a new object of Person class


harry = Person()

# Output: <function Person.greet>


print(Person.greet)

# Output: <bound method Person.greet of <__main__.Person object>>


print(harry.greet)

# Calling object's greet() method


# Output: Hello
harry.greet()

Output

<function Person.greet at 0x7fd288e4e160>


<bound method Person.greet of <__main__.Person object at 0x7fd288e9fa30>>
Hello

You may have noticed the self parameter in function definition inside the class but we called
the method simply as harry.greet() without any arguments. It still worked.
This is because, whenever an object calls its method, the object itself is passed as the first
argument. So, harry.greet() translates into Person.greet(harry).
In general, calling a method with a list of n arguments is equivalent to calling the
corresponding function with an argument list that is created by inserting the method's object
before the first argument.

For these reasons, the first argument of the function in class must be the object itself. This is
conventionally called self. It can be named otherwise but we highly recommend to follow the
convention.
Now you must be familiar with class object, instance object, function object, method object
and their differences.
6

PYTHON PROGRAMMING - I – M.Sc CS

Constructors in Python

Class functions that begin with double underscore __ are called special functions as they
have special meaning.
Of one particular interest is the __init__() function. This special function gets called
whenever a new object of that class is instantiated.
This type of function is also called constructors in Object Oriented Programming (OOP). We
normally use it to initialize all the variables.

class ComplexNumber:
def __init__(self, r=0, i=0):
self.real = r
self.imag = i

def get_data(self):
print(f'{self.real}+{self.imag}j')

# Create a new ComplexNumber object


num1 = ComplexNumber(2, 3)

# Call get_data() method


# Output: 2+3j
num1.get_data()

# Create another ComplexNumber object


# and create a new attribute 'attr'
num2 = ComplexNumber(5)
num2.attr = 10

# Output: (5, 0, 10)


print((num2.real, num2.imag, num2.attr))

# but c1 object doesn't have attribute 'attr'


# AttributeError: 'ComplexNumber' object has no attribute 'attr'
print(num1.attr)
6

PYTHON PROGRAMMING - I – M.Sc CS

Output

2+3j
(5, 0, 10)
Traceback (most recent call last):
File "<string>", line 27, in <module>
print(num1.attr)
AttributeError: 'ComplexNumber' object has no attribute 'attr'

In the above example, we defined a new class to represent complex numbers. It has two
functions, __init__() to initialize the variables (defaults to zero) and get_data() to display the
number properly.
An interesting thing to note in the above step is that attributes of an object can be created on
the fly. We created a new attribute attr for object num2 and read it as well. But this does not
create that attribute for object num1.

Deleting Attributes and Objects

Any attribute of an object can be deleted anytime, using the del statement. Try the following
on the Python shell to see the output.

>>> num1 = ComplexNumber(2,3)


>>> del num1.imag
>>> num1.get_data()
Traceback (most recent call last):
...
AttributeError: 'ComplexNumber' object has no attribute 'imag'

>>> del ComplexNumber.get_data


>>> num1.get_data()
Traceback (most recent call last):
...
AttributeError: 'ComplexNumber' object has no attribute 'get_data'

We can even delete the object itself, using the del statement.
6

PYTHON PROGRAMMING - I – M.Sc CS

>>> c1 = ComplexNumber(1,3)
>>> del c1
>>> c1
Traceback (most recent call last):
...
NameError: name 'c1' is not defined

Actually, it is more complicated than that. When we do c1 = ComplexNumber(1,3), 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.

Deleting objects in Python removes the name binding

Python Inheritance

Inheritance enables us to define a class that takes all the functionality from a parent class and
allows us to add more. In this tutorial, you will learn to use inheritance in Python.

Video: Python Inheritance


6

PYTHON PROGRAMMING - I – M.Sc CS

Inheritance in Python

Inheritance is a powerful feature in object oriented programming.

It refers to defining a new class with little or no modification to an existing class. The new
class is called derived (or child) class and the one from which it inherits is called the base
(or parent) class.

Python Inheritance Syntax

class BaseClass:

Body of base class

class DerivedClass(BaseClass):

Body of derived class

Derived class inherits features from the base class where new features can be added to it. This
results in re-usability of code.

Example of Inheritance in Python

To demonstrate the use of inheritance, let us take an example.

A polygon is a closed figure with 3 or more sides. Say, we have a class


called Polygon defined as follows.
6

PYTHON PROGRAMMING - I – M.Sc CS

class Polygon:
def __init__(self, no_of_sides):
self.n = no_of_sides
self.sides = [0 for i in range(no_of_sides)]

def inputSides(self):
self.sides = [float(input("Enter side "+str(i+1)+" : ")) for i in range(self.n)]

def dispSides(self):
for i in range(self.n):
print("Side",i+1,"is",self.sides[i])

This class has data attributes to store the number of sides n and magnitude of each side as a
list called sides.
The inputSides() method takes in the magnitude of each side and dispSides() displays these
side lengths.
A triangle is a polygon with 3 sides. So, we can create a class called Triangle which inherits
from Polygon. This makes all the attributes of Polygon class available to the Triangle class.
We don't need to define them again (code reusability). Triangle can be defined as follows.

class Triangle(Polygon):
def __init__(self):
Polygon.__init__(self,3)

def findArea(self):
a, b, c = self.sides
# calculate the semi-perimeter
s = (a + b + c) / 2
area = (s*(s-a)*(s-b)*(s-c)) ** 0.5
print('The area of the triangle is %0.2f' %area)

However, class Triangle has a new method findArea() to find and print the area of the
triangle. Here is a sample run.

>>> t = Triangle()

>>> t.inputSides()
Enter side 1 : 3
Enter side 2 : 5
6

PYTHON PROGRAMMING - I – M.Sc CS

Enter side 3 : 4

>>> t.dispSides()
Side 1 is 3.0
Side 2 is 5.0
Side 3 is 4.0

>>> t.findArea()
The area of the triangle is 6.00

We can see that even though we did not define methods like inputSides() or dispSides() for
class Triangle separately, we were able to use them.
If an attribute is not found in the class itself, the search continues to the base class. This
repeats recursively, if the base class is itself derived from other classes.

Method Overriding in Python

In the above example, notice that __init__() method was defined in both classes, Triangle as
well Polygon. When this happens, the method in the derived class overrides that in the base
class. This is to say, __init__() in Triangle gets preference over the __init__ in Polygon.
Generally when overriding a base method, we tend to extend the definition rather than simply
replace it. The same is being done by calling the method in base class from the one in derived
class (calling Polygon.__init__() from __init__() in Triangle).
A better option would be to use the built-in function super(). So, super().__init__(3) is
equivalent to Polygon.__init__(self,3) and is preferred. To learn more about
the super() function in Python, visit Python super() function.
Two built-in functions isinstance() and issubclass() are used to check inheritances.
The function isinstance() returns True if the object is an instance of the class or other classes
derived from it. Each and every class in Python inherits from the base class object.
6

PYTHON PROGRAMMING - I – M.Sc CS

>>> isinstance(t,Triangle)
True

>>> isinstance(t,Polygon)
True

>>> isinstance(t,int)
False

>>> isinstance(t,object)
True

Similarly, issubclass() is used to check for class inheritance.

>>> issubclass(Polygon,Triangle)
False

>>> issubclass(Triangle,Polygon)
True

>>> issubclass(bool,int)
True

Python Multiple Inheritance

In this tutorial, you'll learn about multiple inheritance in Python and how to use it in your
program. You'll also learn about multi-level inheritance and the method resolution order.

Python Multiple Inheritance

A class can be derived from more than one base class in Python, similar to C++. This is
called multiple inheritance.
In multiple inheritance, the features of all the base classes are inherited into the derived class.
The syntax for multiple inheritance is similar to single inheritance.
Example
6

PYTHON PROGRAMMING - I – M.Sc CS

class Base1:
pass

class Base2:
pass

class MultiDerived(Base1, Base2):


pass

Here, the MultiDerived class is derived from Base1 and Base2 classes.

Multiple Inheritance in Python

The MultiDerived class inherits from both Base1 and Base2 classes.

Python Multilevel Inheritance

We can also inherit from a derived class. This is called multilevel inheritance. It can be of
any depth in Python.
6

PYTHON PROGRAMMING - I – M.Sc CS

In multilevel inheritance, features of the base class and the derived class are inherited into the
new derived class.

An example with corresponding visualization is given below.

class Base:
pass

class Derived1(Base):
pass

class Derived2(Derived1):
pass

Here, the Derived1 class is derived from the Base class, and the Derived2 class is derived
from the Derived1 class.

Multilevel Inheritance in Python


6

PYTHON PROGRAMMING - I – M.Sc CS

Method Resolution Order in Python

Every class in Python is derived from the object class. It is the most base type in Python.
So technically, all other classes, either built-in or user-defined, are derived classes and all
objects are instances of the object class.

# Output: True
print(issubclass(list,object))

# Output: True
print(isinstance(5.5,object))

# Output: True
print(isinstance("Hello",object))

In the multiple inheritance scenario, any specified attribute is searched first in the current
class. If not found, the search continues into parent classes in depth-first, left-right fashion
without searching the same class twice.

So, in the above example of MultiDerived class the search order is


[MultiDerived, Base1, Base2, object]. This order is also called linearization
of MultiDerived class and the set of rules used to find this order is called Method
Resolution Order (MRO).
MRO must prevent local precedence ordering and also provide monotonicity. It ensures that a
class always appears before its parents. In case of multiple parents, the order is the same as
tuples of base classes.

MRO of a class can be viewed as the __mro__ attribute or the mro() method. The former
returns a tuple while the latter returns a list.

>>> MultiDerived.__mro__
(<class '__main__.MultiDerived'>,
<class '__main__.Base1'>,
<class '__main__.Base2'>,
<class 'object'>)

>>> MultiDerived.mro()
6

PYTHON PROGRAMMING - I – M.Sc CS

[<class '__main__.MultiDerived'>,
<class '__main__.Base1'>,
<class '__main__.Base2'>,
<class 'object'>]

Here is a little more complex multiple inheritance example and its visualization along with
the MRO.

Visualizing Multiple Inheritance in Python

# Demonstration of MRO

class X:
pass

class Y:
pass

class Z:
pass
6

PYTHON PROGRAMMING - I – M.Sc CS

class A(X, Y):


pass

class B(Y, Z):


pass

class M(B, A, Z):


pass

# Output:
# [<class '__main__.M'>, <class '__main__.B'>,
# <class '__main__.A'>, <class '__main__.X'>,
# <class '__main__.Y'>, <class '__main__.Z'>,
# <class 'object'>]

print(M.mro())

Output

[<class '__main__.M'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.X'>,


<class '__main__.Y'>, <class '__main__.Z'>, <class 'object'>]

To know the actual algorithm on how MRO is calculated, visit Discussion on MRO.

Python Operator Overloading

You can change the meaning of an operator in Python depending upon the operands used. In
this tutorial, you will learn how to use operator overloading in Python Object Oriented
Programming.

Python Operator Overloading

Python operators work for built-in classes. But the same operator behaves differently with
different types. For example, the + operator will perform arithmetic addition on two
numbers, merge two lists, or concatenate two strings.
6

PYTHON PROGRAMMING - I – M.Sc CS

This feature in Python that allows the same operator to have different meaning according to
the context is called operator overloading.

So what happens when we use them with objects of a user-defined class? Let us consider the
following class, which tries to simulate a point in 2-D coordinate system.

class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y

p1 = Point(1, 2)
p2 = Point(2, 3)
print(p1+p2)

Output

Traceback (most recent call last):


File "<string>", line 9, in <module>
print(p1+p2)
TypeError: unsupported operand type(s) for +: 'Point' and 'Point'

Here, we can see that a TypeError was raised, since Python didn't know how to add
two Point objects together.
However, we can achieve this task in Python through operator overloading. But first, let's get
a notion about special functions.

Python Special Functions

Class functions that begin with double underscore __ are called special functions in Python.
6

PYTHON PROGRAMMING - I – M.Sc CS

These functions are not the typical functions that we define for a class.
The __init__() function we defined above is one of them. It gets called every time we create
a new object of that class.
There are numerous other special functions in Python. Visit Python Special Functions to learn
more about them.
Using special functions, we can make our class compatible with built-in functions.

>>> p1 = Point(2,3)
>>> print(p1)
<__main__.Point object at 0x00000000031F8CC0>

Suppose we want the print() function to print the coordinates of the Point object instead of
what we got. We can define a __str__() method in our class that controls how the object gets
printed. Let's look at how we can achieve this:

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)

Now let's try the print() function again.

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)

Output
6

PYTHON PROGRAMMING - I – M.Sc CS

(2, 3)

That's better. Turns out, that this same method is invoked when we use the built-in
function str() or format().

>>> str(p1)
'(2,3)'

>>> format(p1)
'(2,3)'

So, when you use str(p1) or format(p1), Python internally calls the p1.__str__() method.
Hence the name, special functions.
Now let's go back to operator overloading.

Overloading the + Operator

To overload the + operator, we will need to implement __add__() function in the class. With
great power comes great responsibility. We can do whatever we like, inside this function. But
it is more sensible to return a Point object of the coordinate sum.

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

PYTHON PROGRAMMING - I – M.Sc CS

Now let's try the addition operation again:

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(1, 2)
p2 = Point(2, 3)

print(p1+p2)

Output

(3,5)

What actually happens is that, when you use p1 + p2, Python calls p1.__add__(p2) which in
turn is Point.__add__(p1,p2). After this, the addition operation is carried out the way we
specified.
Similarly, we can overload other operators as well. The special function that we need to
implement is tabulated below.

Operator Expression Internally

Addition p1 + p2 p1.__add__(p2)

Subtraction p1 - p2 p1.__sub__(p2)
6

PYTHON PROGRAMMING - I – M.Sc CS

Multiplication p1 * p2 p1.__mul__(p2)

Power p1 ** p2 p1.__pow__(p2)

Division p1 / p2 p1.__truediv__(p2)

Floor Division p1 // p2 p1.__floordiv__(p2)

Remainder (modulo) p1 % p2 p1.__mod__(p2)

Bitwise Left Shift p1 << p2 p1.__lshift__(p2)

Bitwise Right Shift p1 >> p2 p1.__rshift__(p2)

Bitwise AND p1 & p2 p1.__and__(p2)

Bitwise OR p1 | p2 p1.__or__(p2)

Bitwise XOR p1 ^ p2 p1.__xor__(p2)

Bitwise NOT ~p1 p1.__invert__()

Overloading Comparison Operators

Python does not limit operator overloading to arithmetic operators only. We can overload
comparison operators as well.

Suppose we wanted to implement the less than symbol < symbol in our Point class.
6

PYTHON PROGRAMMING - I – M.Sc CS

Let us compare the magnitude of these points from the origin and return the result for this
purpose. It can be implemented as follows.

# overloading the less than operator


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

p1 = Point(1,1)
p2 = Point(-2,-3)
p3 = Point(1,-1)

# use less than


print(p1<p2)
print(p2<p3)
print(p1<p3)

Output

True
False
False

Similarly, the special functions that we need to implement, to overload other comparison
operators are tabulated below.

Operator Expression Internally

Less than p1 < p2 p1.__lt__(p2)


6

PYTHON PROGRAMMING - I – M.Sc CS

Less than or equal to p1 <= p2 p1.__le__(p2)

Equal to p1 == p2 p1.__eq__(p2)

Not equal to p1 != p2 p1.__ne__(p2)

Greater than p1 > p2 p1.__gt__(p2)

Greater than or equal to p1 >= p2 p1.__ge__(p2)

Python setattr()

In this tutorial, we will learn about the Python setattr() function with the help of examples.

The setattr() function sets the value of the attribute of an object.


Example

class Student:
marks = 88
name = 'Sheeran'

person = Student()

# set value of name to Adam


setattr(person, 'name', 'Adam')

print(person.name)

# set value of marks to 78


setattr(person, 'marks', 78)

print(person.marks)

# Output: Adam
6

PYTHON PROGRAMMING - I – M.Sc CS

# 78

setattr() Syntax

The syntax of the setattr() function is:

setattr(object, name, value)

If you want to get the attribute of an object, use getattr().

setattr() Parameters

The setattr() function takes three parameters:


 object - object whose attribute has to be set
 name - attribute name
 value - value given to the attribute

setattr() Return Value

The setattr() method returns None.


6

PYTHON PROGRAMMING - I – M.Sc CS

Example 1: How setattr() works in Python?

class Person:
name = 'Adam'

p = Person()
print('Before modification:', p.name)

# setting name to 'John'


setattr(p, 'name', 'John')

print('After modification:', p.name)

Output

Before modification: Adam


After modification: John

Example 2: When the attribute is not found in setattr()

If the attribute is not found, setattr() creates a new attribute an assigns value to it. However,
this is only possible if the object implements the __dict__() method.
You can check all the attributes of an object by using the dir() function.

class Person:
name = 'Adam'

p = Person()
6

PYTHON PROGRAMMING - I – M.Sc CS

# setting attribute name to John


setattr(p, 'name', 'John')

print('Name is:', p.name)

# setting an attribute not present in Person


setattr(p, 'age', 23)

print('Age is:', p.age)

Output

Name is: John


Age is: 23

Python getattr()

In this tutorial, we will learn about the Python getattr() method with the help of examples.

The getattr() method returns the value of the named attribute of an object. If not found, it
returns the default value provided to the function.
Example

class Student:
marks = 88
name = 'Sheeran'

person = Student()

name = getattr(person, 'name')

print(name)

marks = getattr(person, 'marks')

print(marks)
6

PYTHON PROGRAMMING - I – M.Sc CS

# Output: Sheeran
# 88

getattr() Syntax

The syntax of getattr() method is:

getattr(object, name[, default])

The above syntax is equivalent to:

object.name

getattr() Parameters

getattr() method takes multiple parameters:


 object - object whose named attribute's value is to be returned
 name - string that contains the attribute's name
 default (Optional) - value that is returned when the named attribute is not found

getattr() Return Value

getattr() method returns:


 value of the named attribute of the given object

 default, if no named attribute is found


6

PYTHON PROGRAMMING - I – M.Sc CS

 AttributeError exception, if named attribute is not found and default is not


definedExample 1: How getattr() works in Python?

class Person:
age = 23
name = "Adam"

person = Person()
print('The age is:', getattr(person, "age"))

print('The age is:', person.age)

Output

The age is: 23


The age is: 23

Example 2: getattr() when named attribute is not found

class Person:
age = 23
name = "Adam"

person = Person()

# when default value is provided


print('The sex is:', getattr(person, 'sex', 'Male'))

# when no default value is provided


print('The sex is:', getattr(person, 'sex'))

Output

The sex is: Male


6

PYTHON PROGRAMMING - I – M.Sc CS

AttributeError: 'Person' object has no attribute 'sex'

The named attribute sex is not present in the class Person. So, when calling getattr() method
with a default value Male, it returns Male.
But, if we don't provide any default value, when the named attribute sex is not found, it raises
an AttributeError saying the object has no sex attribute.

Python property()

The property() construct returns the property attribute.

The syntax of property() is:

property(fget=None, fset=None, fdel=None, doc=None)

Recommended Reading: Python @property: How to Use it and Why?

property() Parameters

The property() takes four optional parameters:


 fget (optional) - Function for getting the attribute value. Defaults to None.
 fset (optional) - Function for setting the attribute value. Defaults to None.
 fdel (optional) - Function for deleting the attribute value. Defaults to None.
 doc (optional) - A string that contains the documentation (docstring) for the attribute.
Defaults to None.
6

PYTHON PROGRAMMING - I – M.Sc CS

Return value from property()

property() returns the property attribute from the given getter, setter, and deleter.
 If no arguments are given, property() returns a base property attribute that doesn't
contain any getter, setter or deleter.
 If doc isn't provided, property() takes the docstring of the getter function.

Example 1: Create attribute with getter, setter, and deleter

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

def get_name(self):
print('Getting name')
return self._name

def set_name(self, value):


print('Setting name to ' + value)
self._name = value

def del_name(self):
print('Deleting name')
del self._name

# Set property to use get_name, set_name


# and del_name methods
name = property(get_name, set_name, del_name, 'Name property')

p = Person('Adam')
print(p.name)
p.name = 'John'
del p.name

Output
6

PYTHON PROGRAMMING - I – M.Sc CS

Getting name
The name is: Adam
Setting name to John
Deleting name

Here, _name is used as the private variable for storing the name of Person.
We also set:

 a getter method get_name() to get the name of the person,


 a setter method set_name() to set the name of the person,
 a deleter method del_name() to delete the name of the person.
Now, we set a new property attribute name by calling the property() method.
As shown in the program, referencing p.name internally calls get_name() as
getter, set_name() as setter and del_name() as deleter through the printed output present
inside the methods.

Example 2: Using @property decorator

Instead of using property(), you can use the Python decorator @property to assign the getter,
setter, and deleter.

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

@property
def name(self):
print('Getting name')
return self._name

@name.setter
def name(self, value):
print('Setting name to ' + value)
self._name = value

@name.deleter
def name(self):
print('Deleting name')
6

PYTHON PROGRAMMING - I – M.Sc CS

del self._name

p = Person('Adam')
print('The name is:', p.name)
p.name = 'John'
del p.name

Output

Getting name
The name is: Adam
Setting name to John
Deleting name

Here, instead of using property(), we've used the @property decorator.


First, we specify that name() method is also an attribute of Person. This is done by
using @property before the getter method as shown in the program.
Next, we use the attribute name to specify the setter and the deleter.

This is done by using @name.setter for the setter method and @name.deleter for the deleter
method.
Notice, we've used the same method name() with different definitions for defining the getter,
setter, and deleter.
Now, whenever we use p.name, it internally calls the appropriate getter, setter, and deleter as
shown by the printed output present inside the method.

Name Mangling in Python

In this tutorial, we are going to discuss the name mangling process in Python and how we can
use the name mangling process in Python with different methods.

Name Mangling

A process in which any given identifier with one trailing underscore and two leading
underscores is textually replaced with the __ClassName__Identifier is known as Name
mangling. In __ClassName__Identifier name, ClassName is the name of current class where
identifier is present.

Illustration:
6

PYTHON PROGRAMMING - I – M.Sc CS

Basically, above given definition of name mangling means that any identifier in the form
such as __Jtp (Either at least two leading underscores or at most one underscore trailing the
name) will be replaced by __ClassName__Jtp (the name of the current class will replace
ClassName) with the leading underscore (s) striped in ClassName.

Look at the following example to understand the name mangling process.

Example:

1. # A testing class for identifier


2. class Testing:
3. # Giving Name as an identifier
4. def __init__(self, name):
5. # Identifier initializing
6. self.__name = name
7. def PrintName(self):
8. print(self.__name)
9. t1 = Testing("JavaTpoint") # Calling variable name with the class
10. t1.PrintName() # Printing name in the output

Output:

JavaTpoint

Explanation:

We have defined a testing class with a name identifier in the class in the above program.
Inside the testing class, we have defined two default functions and one with the PrintName().

In the PrintName() function, we have given the print command to print the name. Then, we
initialized a t1 variable with the testing class. In last, we have used PrintName() to print the
name we used in the Testing class while initializing it.

Note: If we try to access the functions and variables of the Testing class outside the
class, it will throw an error. Any changes made to the variable given inside the Testing
Class can be done inside the class only.

Example: 2

# A testing class for identifier

1. class Testing:
6

PYTHON PROGRAMMING - I – M.Sc CS

2. # Giving Name as an identifier


3. def __init__(self, name):
4. # Identifier initializing with double underscore
5. self.__name = name
6. def PrintName(self):
7. print(self.__name)
8. t1 = Testing("JavaTpoint") # Calling variable name with the class
9. t1.PrintName() # Printing name in the output
10. # Accessing identifier outside the class
11. print(t1.__name) # will throw an error in the output

Output:

JavaTpoint
Traceback (most recent call last):
File "C:\Users\Manish\Downloads\code.py", line 12, in
print(t1.__name) # will throw an error in the output
AttributeError: 'Testing' object has no attribute '__name'

Name Mangling in Python

Implementation of the name mangling process in Python is the same as we have discussed
above. We will use different methods in our Python program to implement the name
mangling process and accessing variables in it.

We will perform the following tasks in this section:

o Name mangling in Python with dir() method


o Accessing Name mangled variables in the program
o Name mangling with method overriding in Python

We will use a program for each method to understand its implementation in Python.

1. Name mangling with dir() method

We can use the dir() method to perform the name mangling process, and it will be done to a
class given in the code. The Python interpreter will do the process of name mangling to the
class. We can use the dir() method by passing the defined class object in it, and the dir()
method will return all the valid attributes belonging to the given class object.

Look at the following exemplar program to understand this dir() method of name mangling:

Example:
6

PYTHON PROGRAMMING - I – M.Sc CS

1. # A testing class for name mangling


2. class Testing:
3. def __init__(self, name):
4. self.__name = name
5. # Initializing variable with the testing class
6. t1 = Testing("JavaTpoint")
7. # Using dir() method on initialized variable
8. print(dir(t1))

Output:

['_Testing__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',


'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

Explanation:

As we look at the output, we can see that the dir() method we used on the initialized variable,
i.e., t1, returned all the valid attributes of the class testing and printed them. We can also see
that the name of the identifier, i.e., __name, is changed to _Testing__name by the interpreter.

2. Accessing name mangled variables

We can access the name mangled variables even outside the class and print the in output (Not
like accessing the class variable that will return an error). To access the name mangled
variables outside the class, we simply have to add _ClassName with the variable, and we can
also print the value in the output.

Look at the following program where we have accessed name mangled variables outside the
testing class.

Example:

1. # A testing class for name mangling


2. class Testing:
3. def __init__(self, name):
4. self.__name = name
5. # Initializing variable with the testing class
6. t1 = Testing("JavaTpoint")
7. # Accessing Name mangled variables outside testing class
6

PYTHON PROGRAMMING - I – M.Sc CS

8. print("The name mangled that we are accessing outside the class: ", t1._Testing__nam
e)

Output:

The name mangled that we are accessing outside the class: JavaTpoint

Explanation:

We have been able to access the __name variable outside as it was a name mangled variable,
and it returned the name value in the output.

3. Name mangling using method overriding

As we are using the name mangling process in our program, we are limited because of little
support for a valid use case of members from a private class. The limited support for the
private class member's valid use case is to avoid name clashes of various names with names
defined inside the subclasses. As long as the name mangling process will occur as per the
definition of a Python class, the mangling process will be done by the interpreter. And, it is
very helpful for the subclasses in the program to let them override methods without even
breaking calls of the interclass method.

Let's understand the following example.

Example:

1. # A default testing class for name mangling


2. class Testing:
3. def __init__(self):
4. self.__jtp() # name mangling with the Jtp variable
5. def jtp(self): # default function for name mangling in parent class
6. print("Name mangling process done inside the parent testing class")
7. # copy of jtp() method for private class members
8. __jtp = jtp # Name mangling with method overriding process
9. # A subclass for Testing class
10. class SubTesting(Testing):
11. # Providing new signature for jtp() function
12. def jtp(self):
13. print("Name mangling process done inside the child sub-testing class")
14. # Calling the objects from subclass and function of it
15. obj = SubTesting()
16. obj.jtp()
6

PYTHON PROGRAMMING - I – M.Sc CS

Output:

Name mangling process done inside the parent testing class


Name mangling process done inside the child sub-testing class

Conclusion

First, we have learned about the introduction of the Name mangling process in this tutorial.
We also learned that how we can use the dir() method for name mangling in Python. Then,
we accessed the name mangled variables outside the class in which they are present. In last,
we also learn about that how we can use the name mangling process with method overriding
in given subclasses in the program.

What are Methods in Python?

In Object-Oriented Programming, we have (drum roll please) objects. These objects consist

of properties and behavior. Furthermore, properties of the object are defined by the attributes

and the behavior is defined using methods. These methods are defined inside a class. These

methods are the reusable piece of code that can be invoked/called at any point in the program.

Python offers various types of these methods. These are crucial to becoming an efficient

programmer and consequently are useful for a data science professional.

Types of Methods in Python

There are basically three types of methods in Python:

 Instance Method
 Class Method
 Static Method

Instance Methods

The purpose of instance methods is to set or get details about instances (objects), and that is

why they’re known as instance methods. They are the most common type of methods used in

a Python class.
6

PYTHON PROGRAMMING - I – M.Sc CS

They have one default parameter- self, which points to an instance of the class. Although you

don’t have to pass that every time. You can change the name of this parameter but it is better

to stick to the convention i.e self.

Any method you create inside a class is an instance method unless you specially specify

Python otherwise. Let’s see how to create an instance method:

class My_class:
def instance_method(self):
return "This is an instance method."

It’s as simple as that!

In order to call an instance method, you’ve to create an object/instance of the class. With the

help of this object, you can access any method of the class.

obj = My_class()
obj.instance_method()

When the instance method is called, Python replaces the self argument with the instance

object, obj. That is why we should add one default parameter while defining the instance

methods. Notice that when instance_method() is called, you don’t have to pass self. Python

does this for you.

Along with the default parameter self, you can add other parameters of your choice as well:

class My_class:

def instance_method(self, a):


6

PYTHON PROGRAMMING - I – M.Sc CS

return f"This is an instance method with a parameter a = {a}."

We have an additional parameter “a” here. Now let’s create the object of the class and call

this instance method:

obj = My_class()
obj.instance_method(10)

Again you can see we have not passed ‘self’ as an argument, Python does that for us. But

have to mention other arguments, in this case, it is just one. So we have passed 10 as the

value of “a”.

You can use “self” inside an instance method for accessing the other attributes and methods

of the same class:

class My_class:

def __init__(self, a, b):


self.a = a
self.b = b

def instance_method(self):
return f"This is the instance method and it can access the variables a = {self.a} and\
b = {self.b} with the help of self."

Note that the __init__() method is a special type of method known as a constructor. This

method is called when an object is created from the class and it allows the class to initialize

the attributes of a class.


6

PYTHON PROGRAMMING - I – M.Sc CS

obj = My_class(2,4)
obj.instance_method()

Let’s try this code in the live coding window below.

With the help of the “self” keyword- self.a and self.b, we have accessed the variables present

in the __init__() method of the same class.

Along with the objects of a class, an instance method can access the class itself with the help

of self.__class__ attribute. Let’s see how:

class My_class():

def instance_method(self):
print("Hello! from %s" % self.__class__.__name__)
6

PYTHON PROGRAMMING - I – M.Sc CS

obj = My_class()
obj.instance_method()

The self.__class__.__name__ attribute returns the name of the class to which class

instance(self) is related.

2. Class Methods

The purpose of the class methods is to set or get the details (status) of the class. That is why

they are known as class methods. They can’t access or modify specific instance data. They

are bound to the class instead of their objects. Two important things about class methods:

 In order to define a class method, you have to specify that it is a class method with the
help of the @classmethod decorator
 Class methods also take one default parameter- cls, which points to the class. Again,
this not mandatory to name the default parameter “cls”. But it is always better to go
with the conventions

Now let’s look at how to create class methods:

class My_class:

@classmethod
def class_method(cls):
return "This is a class method."

As simple as that!

As I said earlier, with the help of the instance of the class, you can access any method. So
we’ll create the instance of this My_class as well and try calling this class_method():

obj = My_class()
6

PYTHON PROGRAMMING - I – M.Sc CS

obj.class_method()

This works too! We can access the class methods with the help of a class instance/object. But

we can access the class methods directly without creating an instance or object of the class.

Let’s see how:

My_class.class_method()

Without creating an instance of the class, you can call the class method with

– Class_name.Method_name().

But this is not possible with instance methods where we have to create an instance of the

class in order to call instance methods. Let’s see what happens when we try to call the

instance method directly:

My_class.instance_method()

We got an error stating missing one positional argument – “self”. And it is obvious because

instance methods accept an instance of the class as the default parameter. And you are not

providing any instance as an argument. Though this can be bypassing the object name as the

argument:

My_class.instance_method(obj)
6

PYTHON PROGRAMMING - I – M.Sc CS

3. Static Methods

Static methods cannot access the class data. In other words, they do not need to access the

class data. They are self-sufficient and can work on their own. Since they are not attached to

any class attribute, they cannot get or set the instance state or class state.

In order to define a static method, we can use the @staticmethod decorator (in a similar way

we used @classmethod decorator). Unlike instance methods and class methods, we do not

need to pass any special or default parameters. Let’s look at the implementation:

class My_class:

@staticmethod
def static_method():
return "This is a static method."

And done!

Notice that we do not have any default parameter in this case. Now how do we call static

methods? Again, we can call them using object/instance of the class as:

obj = My_class()
obj.static_method()

And we can call static methods directly, without creating an object/instance of the class:

My_class.static_method()
6

PYTHON PROGRAMMING - I – M.Sc CS

You can notice the output is the same using both ways of calling static methods.

Here’s a summary of the explanation we’ve seen:


o An instance method knows its instance (and from that, it’s class)
o A class method knows its class
o A static method doesn’t know its class or instance

When to Use Which Python Method?

The instance methods are the most commonly used methods. Even then there is difficulty in

knowing when you can use class methods or static methods. The following explanation will

satiate your curiosity:

Class Method – The most common use of the class methods is for creating factory methods.

Factory methods are those methods that return a class object (like a constructor) for different

use cases. Let’s understand this using the given example:

from datetime import date

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

# a class method to create a Dog object with birth year.


@classmethod
def Year(cls, name, year):
return cls(name, date.today().year - year)
6

PYTHON PROGRAMMING - I – M.Sc CS

Here as you can see, the class method is modifying the status of the class. If we have the year

of birth of any dog instead of the age, then with the help of this method we can modify the

attributes of the class.

Let’s check this:

Dog1 = Dog('Bruno', 1)
Dog1.name , Dog1.age

Here we have constructed an object of the class. This takes two parameters name and age. On
printing the attributes of the class we get Bruno and 1 as output, which was the values we
provided.

Dog2 = Dog.Year('Dobby', 2017)


Dog2.name , Dog2.age

Here, we have constructed another object of the class Dog using the class
method Year(). The Year() method takes Person class as the first parameter cls and returns
the constructor by calling cls(name, date.today().year – year), which is equivalent
to Dog(name, date.today().year – year).
As you can see in printing the attributes name and age we got the name that we provided and
the age converted from the year of birth using the class method.
Static Method – They are used for creating utility functions. For accomplishing routine
programming tasks we use utility functions. A simple example could be:

class Calculator:

@staticmethod
def add(x, y):
return x + y

print('The sum is:', Calculator.add(15, 10))


6

PYTHON PROGRAMMING - I – M.Sc CS

You can see that the use-case of this static method is very clear, adding the two numbers

given as parameters. Whenever you have to add two numbers, you can call this method

directly without worrying about object construction.

Duck Typing in Python


Duck Typing is a type system used in dynamic languages. For example, Python, Perl, Ruby,
PHP, Javascript, etc. where the type or the class of an object is less important than the method
it defines. Using Duck Typing, we do not check types at all. Instead, we check for the
presence of a given method or attribute.
The name Duck Typing comes from the phrase:

# Python program to demonstrate


# duck typing

class Specialstring:
def __len__(self):
return 21

# Driver's code
if __name__ == "__main__":

string = Specialstring()
print(len(string))

Output:
21

In this case, we call method len() gives the return value from __len__ method.
Here __len__ method defines the property of the class Specialstring
The object’s type itself is not significant in this we do not declare the argument in method
prototypes. This means that compilers can not do type-checking. Therefore, what really
matters is if the object has particular attributes at run time. Duck typing is hence
implemented by dynamic languages. But now some of the static languages like Haskell also
supports it. But, Java/C# doesn’t have this ability yet.
Example: Now, lets look demonstrates how an object be used in any other circumstances
until it is not supported.

# Python program to demonstrate


6

PYTHON PROGRAMMING - I – M.Sc CS

# duck typing

class Bird:
def fly(self):
print("fly with wings")

class Airplane:
def fly(self):
print("fly with fuel")

class Fish:
def swim(self):
print("fish swim in sea")

# Attributes having same name are


# considered as duck typing
for obj in Bird(), Airplane(), Fish():
obj.fly()

Output:
fly with wings
fly with fuel
Traceback (most recent call last):
File "/home/854855e5570b9ce4a9e984209b6a1c21.py", line 20, in
obj.fly()
AttributeError: 'Fish' object has no attribute 'fly'
In this example, we can see a class supports some method we can modify it or give them
new functionality. Duck-typing emphasis what the object can really do, rather than what the
object is.

Special Methods for Python

Everything in Python is an object and we define objects through classes. When we define an

object, we actually create an instance of a class. Thus, class is the most fundamental piece in

Python.

Classes have:
6

PYTHON PROGRAMMING - I – M.Sc CS

 Data attributes: Define what is needed to create an instance of a class

 Methods (i.e. procedural attributes): Define how to interact with the instances of a

class

We can create our own classes using data and procedural attributes. It is our playground so we

can implement various functions to customize a class.

In addition to the user-defined functions, it is possible to use built-in Python function within

user-defined classes. This is what special (or magic) methods are for.

Special methods allow for using the built-in Python functions to enrich user-defined classes.

Consider the print function which is one of the most commonly used Python function. If you

use it to print an instance of your class, it will print out something like the following:
<__main__.Book object at 0x7f9ed5b1d590>

It displays the name of the class (Book) and the memory location of the object which is not a

proper use of the print function. We can customize its behavior by implementing the __str__

special method in our class.

In this article, we will go over 4 special methods that you will be likely to use in your classes.

1. __init__

The __init__ special method is automatically executed when an instance of class is created. It

is also called class constructor. The parameters of the __init__ represent the data attributes of a

class.

Let’s create a class called Book.


class Book(): def __init__(self, name, writer, pages):
self.name = name
6

PYTHON PROGRAMMING - I – M.Sc CS

self.writer = writer
self.pages = pages

The self refers to the instance itself. The Book class has 3 data attributes that need to be

specified when creating a Book instance.


b = Book("Moby Dick", "Herman Melville", "378")type(b)
__main__.Book

The variable b is an instance of the Book class.

2. __str__

We use the __str__ special method to implement the built-in print function within our class.

Without the __str__, here is what print function does.


print(b)
<__main__.Book object at 0x7f9ed5b1d590>

Let’s define the __str__ method in our class definition.


def __str__(self):
return f"The title of the book is {self.name}"

Now the print function will return the title of the name. It accesses the name of the book

through the name attribute. You can customize it in any way you’d like.
print(b)
The title of the book is Moby Dick

3. __len__

The len function returns the length of an object. For strings, it returns the number of

characters. For a Pandas data frame, it returns the number of row.

We can customize its behavior by implementing the __len__ special method in our class

definition. Let’s make it to return the number of pages of a book object.


6

PYTHON PROGRAMMING - I – M.Sc CS

If the __len__ is not implemented in the class definition, you will get an error if you try to use

it on an object of your class. It does not have a default behavior like the print function.
def __len__(self):
return int(self.pages)len(b)
378

Please note that each time you add a new function to your class, you need to recreate the

object to be able to use the new functions.

4. __eq__

The __eq__ special method allows for comparing two instances of a class. If it is defined in
our class, we can check if an instance is equal to another instance. The equality condition is

specified using the __eq__ method.

In our case, we can declare two books being equal if the names and writers of the book are the

same. They might have different number of pages.


def __eq__(self, other):
return (self.name == other.name) & (self.writer == other.writer)

The “==” operator will return True if both names and writes are the same for two instances.

Let’s create two books and check if they are equal.


b = Book("Moby Dick", "Herman Melville", "378")a = Book("Moby Dick", "Herman Melville",
"410")b == a
True

If either names or writes is different, the equality operator returns False.


b = Book("Moby Dick", "Herman Melville", "378")a = Book("Moby Dick", "Melville", "410")b
== a
False

You might also like