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

Core Python Concepts - FLM

Uploaded by

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

Core Python Concepts - FLM

Uploaded by

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

Python Concepts Tour

Dachuri Chaitanya
M.Tech (IIT Roorkee), AI Expert
Mob: +91 9701 37 97 97, YouTube Channel: python.trainer.helper
Instagram: python.trainer.helper , Facebook: python.trainer.helper
WhatsApp Channel: https://whatsapp.com/channel/0029Va9Tj7j0AgW8byyzl81j
Trainer Introduction
• Post graduate from IIT Roorkee

• 20+ yrs Industry Experience

• Worked in TCS, HCL, TechM, Capgemini, etc…

• 10+ yrs Training Experience

• 60+ Batches, 4800+ students, 75000+ Weekly Tests, 9450+ Mock Interviews….

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Course Specialties
Session recording Code notebook

Course Material Assignments

Highlight IMP Anytime Questions

Weekly Tests, Interviews Accessible Trainer

5 months 100% Job Assistance


D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
DOs & DON'Ts
DOs DON'Ts
• Clear doubts immediately • Do not absent to classes

• Spend min. 2-6 hrs per day • Do not take long leaves

• Better to have own laptop • Do not be late to classes

• Practice all assignments • No need to write Notes in class

• See absent class recordings ASAP • Do not take food before class

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


At the end of Course…

• Becomes equal to ~ 3 yrs exp. professional Python Full stack developer.

• Gains more than enough knowledge & hands on required for IT Job.

• Can easily crack interviews and get job in few days.

• Gets recommendation to jobs in all tied up start up IT companies.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Career options with PYTHON
PYTHON

Django sklearn,
pytest, numpy, pygame,
DB asyncio, Kivy, numpy,
pandas, Tensorflow,
HTML Lettuce BeeWare pandas, panda3D
Diesel matplotlib Math
CSS matplotlib
ML, DL Algor…
React AI, pybrain
sklearn,
Tensorflow
ML Algor…
DL Algor..
Math AI Developer Games
Web Developer Networking Mobile App Developer
Developer Developer

Data Analyst Data Data


Engineer
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert) Scientist
Automation Tester
What can do with PYTHON ?
Artificial Intelligence
Data Visualization

Gaming & Multimedia

</>
System Programming
pybrain
sklearn Automation
Testing

tkinter
numpy, pandas

GUIs
Numeric & Scientific
Programming

Network Programming DB Development

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Web Development Mobile Apps
Course Concepts Summary
• Built-in Types, Variables • Data Libraries (numpy, pandas, matplotlib)

• Simple & Compound Statements • Database basics (mysql)

• Arguments, Functions, Modules • Web Frameworks (Django)

• OOP Concepts, Exceptions • Maths (Algebra, Statistics, Probability, Calculus)

• Advanced Python Topics • Machine Learning

• Regular Expressions • Front End (HTML, CSS, JS, BS, React)


D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Who using PYTHON ?

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Download PYTHON
• https://www.python.org/downloads/

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Install PYTHON
1 2

3 4

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Verify PYTHON
In Command prompt: In Start Menu:

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


What is PYTHON ?
• Python is an interpreted, object-oriented, high level programming language.

Compiled PL Interpreted PL Non OOPL OOPL HL PL LL PL


PL does not
PL supports OOP Machine/Byte
Program Program supports OOP Program
(written by developer) (written by developer) features (written by developer) Code
features
Ex: C Ex: C++, Java, Python Ex: Perl, Python, Ruby Ex: Assembly Language
Compiling
Interpret & run
Line by line.
Machine/Byte Interpretation OOP Features
Code generates byte - Classes
code, saves in - Encapsulation
RAM/Drive
Running - Inheritance
(Faster) - Polymorphism
- Composition
Output Output
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Ex: C, C++, Java Ex: JS, Perl, Python
Why PYTHON ?
• Developer Productivity • Huge Support Libraries

• Portable • Open Source

• Software Quality • Powerful

• Easy to Learn • Easy to Use

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


PYTHON is… Interpreter
P V M : Python Virtual Machine

Software code
package

PYTHON P
mycode.py or V Output • Low level, platform independent representation of
Python M source code.
• Executes much faster
Interpreter

Software code
Source code byte code
package
1. Reads line by line of source code (mycode.py)
mycode.pyc Output
2. Generates byte code for every line (mycode.pyc) mycode.py PVM

3. Executes the byte code by PVM


Python Interpreter

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


How to run PYTHON script
python mycode.py To get o/p using this command

Using windows command prompt 1) Python installation path must be set in PATH system variable.
2) Source code (mycode.py) must be available in CWD: C:\Users\Lenovo

python mycode.py
or
Executes the python D:\code\mycode.py To get o/p using this command

py mycode.py python script


1) Python installation path must be set in PATH system variable.
2) NO need to have source code (mycode.py) in CWD.
Current Working Run Command
Directory (CWD) syntax
Example:
py mycode.py To get o/p using this command

1) NO need to set python installation path in PATH environment


variable
2) Source code (mycode.py) must be available in CWD.

py D:\code\mycode.py To get o/p using this command

1) NO need to set python installation path in PATH environment variable.


Output
2) NO need to have
(Print statements) D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
source code (mycode.py) in CWD.
Built-in Types

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Built-in Types, Benefits
Why Built-in Types?
• Easy and quick to write programs

• Efficient than custom data structures

• Extensible

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Built-in Number objects

Type Literals Creating variables: Examples


Integer (unlimited size) 1234, -24, 0, size = 12, count = 203 • Assignment Operator.
99999999999999
• Variables are created and assigned
Float point number 1.23, 1., 3.14e-10, percentage = 98.34 to value when they are first assigned
4E210, 4.0e+210 a value.
Octal 0o177, 0O146 v1 = 0O146 • Variable values are changed on
further assignments.
Hex 0x9ff, 0X7AE2 v2 = 0x9ff
• Variables are replaced with their
values when used in expression.
Binary 0b1010100, 0B1101 v3 = 0b1010100
• Variables must be assigned before
3+4j, 0+4.0j, 3J v4 = 3j they use in expressions.
Complex number
Decimal (Fixed Precision) Decimal('1.0') d1 = Decimal('1.0')

Fraction (Rational Numbers) Fraction(1, 3) f1 = Fraction(1, 3)

Boolean True, False exists = False

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Integer & Float-point Numbers
Integers Float-point Numbers
• Decimal digits without decimal point. • Decimal digits with decimal point.
• int(N)– built in function to convert any number • float(N)– built in function to convert any number
to Integer to float point number

Ex: Ex:
size = 782 percentage = 84.23
print(int(23.43)) prints 23 print(float(size)) prints 782.0

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Hexadecimal Numbers
• Integer coded in hexadecimal (base 16)
• Starts with a leading 0x or 0X
• Followed by string of hexadecimal digits 0-9 and A-F
• Hex digits can be coded in lower or upper case.
• hex(I)– built in function to convert integer to hex number (str representation).
• int(hex)– built in function to convert hex number to integer.
int(hNum)

Ex:
hNum = 0x02AF print(hNum) Prints equivalent integer
value 687

Starting with Followed by hexa


0x or 0X digits: 0-9 or A-F

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


hex(687)
Octal Numbers
• Integer coded in octal (base 8)
• Starts with a leading 0o or 0O
• Followed by string of octal digits 0-7
• oct(I) – built in function used to convert integer to octal number (str repr).
• int(oct)– built in function to convert octal number to integer.
int(octNum)

Ex:
octNum = 0O01745 print(octNum) Prints equivalent integer
value 997

Starting with Followed by octal


0o or 0O digits: 0-7

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


oct(997)
Binary Numbers
• Integer coded in binary (base 2)
• Starts with a leading 0b or 0B
• Followed by string of binary digits 0 or 1
• bin(I) – built in function used to convert integer to binary number (str repr).
• int(bin)– built in function to convert binary number to integer.
int(binNum)

Ex:
binNum = 0b01001 print(binNum) Prints equivalent integer
value 9

Starting with Followed by binary


0b or 0B digits: 0 or 1

bin(9)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Complex Numbers
• Format: realpart + imginarypart
• Real part is optional.
• Imaginary part is terminated with a j or J
• Also be created using built in function: complex(real, img)
created using complex(real,
img) built in function

Ex:
clxNum = 3.0+4.0j cNum2 = complex(2, 7)
Imaginary
Imaginary Real part part
Real part part

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Decimals & Fractions
Decimals Fractions
• Floating point numbers with fixed number of • Implements rational numbers
decimal points. • Keeps both numerator and denominator explicitly to
• Also, called as fixed-precision floating point values. avoid inaccuracies.
• Well suited for money related calculations
Ex: import fractions
Ex: import decimal x = fractions.Fraction(1, 3)
cost = decimal.Decimal('785.42') y = fractions.Fraction(4, 6)
decimal.Decimal('1')/decimal.Deci print(x) 1/3
mal('7') Decimal('0.14285714…')
print(x) 2/3
Setting decimal precision globally.
x+y Fraction(1, 1)
prints

decimal.getcontext().prec = 3
x-y Fraction(-1, 3)
prints

decimal.Decimal('1')/decimal.Deci
mal('7') Decimal('0.143') print(x-y) -1/3
x*y Fraction(2, 9)
prints
Can use Integer, float values also

decimal.Decimal(1)/decimal.Decima print(x*y) 2/9


l(7.5) Decimal('0…')
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Boolean
• Has 2 values: True, False
• Nothing but integers. but, customized versions of integers: 1 (i.e.
True), 0 (i.e. False)
• Behave exactly as integers 1, 0. but, with customized printing logic.

Ex:
True + 4 5
prints

True == 1 True
prints

k = bool(1)
print(k) True
prints

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Lowest
Operators for Numbers
O Operator Meaning 1) A*B+C*D is equal to (A*B)+(C*D) by applying operator precedence.
p
e x < y, x <= y, Magnitude comparison, Set 2) Can use Paratheses. Ex: (X+Y)*Z, X+(Y*Z)
r x > y, x >= y subset, superset
a
t x == y, x != y Value equality operators 3) Mixed types converted up.
o
r
x | y Bitwise OR, Set Union Ex: 40+3.14 Convert
to float 40.0+3.14 Do
Addition 43.14
x ^ y Bitwise XOR
P 4) Normal & Chained Comparisons
r x & y Bitwise AND, Set Intersection
e
x << y, x >> y Bitwise SHIFT left/right Ex: 2.0>=1 Normal comparison
c
e 1<2>3.0 is equal to 1<2 and 2>3.0 Chained
x + y Addition (faster) (slower)
d
e x – y Subtraction, Set difference 5) True Division always keeping remainders in floating point results,
n regardless of types.
c x * y Multiplication
e Ex: 10/4 2.5, -10/4.0 -2.5
x % y
results

Remainder results

O x / y Division: True 6) Floor Division always rounds fractional remainders down to their floor
r
d x // y Division: Floor (closest number below true value), regardless of types. Result depends on
e the types.
r −x Negation
x ** y Power (exponentiation) Ex: 10//4
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
results
2, -10//4.0 results
-3.0, -10//4 results
-3
Highest
Lowest
Operators for Numbers
O Operator Meaning 7) All bit wise operations shall be performed on equivalent binary
p numbers and results to integer value.
e x < y, x <= y, Magnitude comparison, Set
r x > y, x >= y subset, superset Ex: x = 1 # 1 decimal is 0001 in bits
a
t x == y, x != y Value equality operators x << 2 prints 4 # shift left 2 bits: 0100 and prints resulted integer.
o
r
x | y Bitwise OR, Set Union x | 2 prints
3 # bitwise OR (either bit=1): 0011
x ^ y Bitwise XOR
P x & 1 prints
1 # bitwise AND (both bits=1): 0001
r x & y Bitwise AND, Set Intersection
e
c x << y, x >> y Bitwise SHIFT left/right
e 8) Other built-in numeric functions: pow, abs, sum, min, max, …
x + y Addition
d
e x – y Subtraction, Set difference Ex: pow(2, 4) 16, abs(-42.0) 42.0
n
c x * y Multiplication sum((2, 0, 4)) 6, min(3, 1, 2, 4) 1
e
x % y Remainder
9) Other built-in numeric modules: math, random, round, …
O x / y Division: True
r
d x // y Division: Floor Ex: math.floor(-2.567) -3,
e math.trunc(-2.567) -2
r −x Negation math.sqrt(144), math.pi, math.e
x ** y random.randint(1,
D. Chaitanya Reddy (IIT Roorkee Alumni,
Power (exponentiation)
AI Expert) 10) 5
Highest
Strings 0 1 2 3 4 5

• Used to represent encoded text / bytes. M a h e s h


-6 -5 -4 -3 -2 -1
• str(name) to convert any object to string.
String basic operations:
• Categorized as immutable sequences.
Operation Interpretation
Different String versions: S1 + S2 Concatenate

String Version Interpretation S * 3 Repeat


S = '' or S = str() Empty String S[i], S[-i] Indexing
S = "spam's" Double quotes, same as S[i:j], S[i:], S[i:j:k], S[::k] Slicing, slicing with skip
S = 'spam"s' single
len(S) Length of string
S = 's\npa\tm' Escape sequences
'a %s parrot %s' % (S1, S2) String formatting expr
S = """…multiline…""" Triple quoted block
strings S in 'spam' Substring finding
S = r'c:\temp\new' Raw string
1. Multi line text in code.
B = b'sp\xc4m' Byte string menu = """spam Sequence operations
eggs
drinks
Mutable: In place changes are allowed for object's value """
Immutable: In place changes are NOT allowed for object's value
2. Documentation purpose.
Sequence: object that support sequence operations
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
3. Disabling/commenting the code.
Contd…

Strings
String methods Escape chars
String method Interpretation Escape Meaning
'a {0} parrot'.format(S1) String formatting method \\ Single backslash

S.find('pa') String search \' Single quote

S.rstrip() Remove whitespaces \" Double quote

S.replace('pa', 'xx') Replacement \n New line

S.split(',') Split with char \t Horizontal tab

S.isdigit() Content test \v Vertical tab

S.lower() Case conversion

S.endswith() End test ASCII values: (0 – 127)


','.join(strlist) Join with char Char ASCII Value • Char to ASCII: ord()
A – Z 65 to 90 ord('s') → 115
a – z 97 to 122
Any operation/method call does NOT change 0 – 9 48 to 57
the string, rather generates a new string object. • ASCII to Char: chr()
Space 32
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert) chr(115) → 's'
1) Easy and Quick to write code.
Iterating String Sequence 2) 10x Faster in execution.
name = 'Mahesh Babu' 3) Saves memory

Using for loop: Using List Comprehension:

name = 'Mahesh Babu' ''.join([ch*2 for ch in name])


new_name = ''
for ch in name: Output:
new_name = new_name + ch*2 MMaahheesshh BBaabbuu

print(new_name)

Output:
MMaahheesshh BBaabbuu D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Lists
• An ordered (insertion order)
collection of arbitrary objects. List creation techniques:
• Accessed by offset/index, i.e., List Version Interpretation
supports sequence operations. L = [] or L = list() Empty list

• Mutable: can grow and shrink on L = [3, 'a', 5.4, {}, [4, 5]] List with 5 items with nesting
demand. L = list('spam') List of an iterable's items

• Iterable: can traverse through all L = list(range(-4, 4)) List of successive integers
elements Sequence operations
List basic operations:
• Nestable: can create list of list of Operation Interpretation
list, so on. L[i], L[-i], L[i][j], Index, index of index, slicing
• Heterogeneous: can contain any L[i:j], L[-i:]
L1 + L2
type of object as elements. Concatenate

L * 3 Repeat
0 1 2 3 4 5
len(L) Length/size of list
'hi' 5 3.4 [7, 'No'] 0b100 True Results new list,
NO in place
3 Roorkee
D. Chaitanya Reddy (IIT in L Alumni, AI Expert) Element existence test/finding changes
-6 -5 -4 -3 -2 -1
Contd…

List methods
Lists
List method Interpretation
L.append(4) Add new element at last.

L.extend([5, 1.23, 'hi']) Add multiple elements at last.

L.insert(i, el) Add element at index i.

L.index(el) Get the first index (from left) of element el.

L.count(el) Get the count of element el.


Any operation/method call results in place change
L.sort() Sort elements. of the list, rather generating a new list.
L.reverse() Reverse the order of elements.

L.copy() Copy the list.

L.clear() Remove all elements in list.

L.pop(i) Remove and return element at index i.

L.remove(el) Remove the element el at all indexes.

del L[i], del L[i:j] Delete element at index i, elements in slice


i:j
L[i:j]=[] Removing all elements in slice i:j

L[i] = 3, L[i:j]=[4, 5, 6] D. Chaitanya


Index assignment, Reddy (IIT Roorkee Alumni, AI Expert)
slice assignment.
1) Easy and Quick to write code.
Iterating List Sequence 2) 10x Faster in execution.
3) Saves memory
my_list = [1, 'hi', 3.4, [6, 7]]
Using for loop: Using List Comprehension:

my_list = [1, 'hi', 3.4, [6, 7]] [el*2 for el in my_list]


new_list = []
for el in my_list: Output:
new_list.append(el*2) [2, 'hihi', 6.8, [6, 7, 6, 7]]

print(new_list)

Output:
[2, 'hihi', 6.8, [6, 7, D.6, 7]]
Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Tuples
• An ordered (insertion order) collection of Lists vs Tuples
arbitrary objects.
Tuple creation techniques:
• Accessed by offset/index, i.e., supports
sequence operations. Tuple Version Interpretation
T = (), T = tuple() Empty tuple
• Immutable: fixed length. Applicable only
to top level. Not to it's content. T = (4, ) T = (4) Tuple with single element

• Iterable: can traverse through all elements T = (0, 3.4, 'hi', ('bye', 1)) Tuple with 4 elements and
nested tuple
• Nestable: can create tuple of tuple of T = tuple('spam') Tuple of items in an Iterable.
tuple, so on.
Tuple basic operations: Sequence operations
• Heterogeneous: can contain any type of
object as elements. Operation Interpretation
T[i], T[-i], T[i][j], Index, index of index, slicing
T[i:j], T[-i:]

Tuple methods T1 + T2 Concatenate

List method Interpretation T * 3 Repeat

T.index(el) Get the first index (from left) of element el. len(T) Length/size of tuple Results new
tuple, NO in
T.count(el) Get the count of element el. 'spam'
D. Chaitanya Reddy (IIT in T AI Expert)
Roorkee Alumni, Element existence test/finding place changes
1) Easy and Quick to write code.
Iterating Tuple Sequence 2) 10x Faster in execution.
3) Saves memory
my_tup = (1, 'hi', 3.4, [6, 7])
Using for loop: Using List Comprehension:
my_tup = (1, 'hi', 3.4, [6, 7])
new_list = [] tuple([el*2 for el in my_tup])
New_tup = ()
for el in my_tup: Output:
new_list.append(el*2)
(2, 'hihi', 6.8, [6, 7, 6, 7])

new_tup = tuple(new_list)
print(new_tup)

Output:
(2, 'hihi', 6.8, [6, 7, D.6, 7])
Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Sets
• An unordered collection of Ex:
unique and immutable objects.
s=set() #empty set
• Designed to support operations
s1=set([1, 7.4, True, 5]) #built-in call for set creation
corresponding to mathematical
s2={1, 'sp', 7, 'e'} #new literal for set creation
set theory.
s3=set('spa')
• Mutable: can grow and shrink on s3 prints
{'s', 'a', 'p'}
demand. s3.add('h'), s3 prints
{'s', 'h', 'a', 'p'}
• Iterable: can traverse through all s1&s2 prints
{1}
elements s1|s2 prints
{1, 5, 7, 7.4, 'e', 'sp'}
• All standard operations of Set s1-s2 prints {5, 7.4}
uses efficient algorithms and s1^s2 prints {5, 7, 7.4, 'e', 'sp'}
hence faster results s1.union(s2) is same as s1|s2
Mutable: value of the object can't be changed in place. s1.intersection(s2) is same as s1&s2
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Immutable: In place changes are allowed for object's value.
Contd…

Sets
• Frozenset: Same as Set behavior except immutable in nature.
Ex: s4 = frozenset([1, 5.6, 'rt', True])

• Can be used to filter duplicates out of other collections.


rl1 = random.sample(range(10, 20), 10)

• Can be used to isolate differences in other iterables like lists, strings, etc…

• Can be used to perform order neutral equality test.

• More suitable for large datasets if order does not matter to get faster results

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Iterating Set 1) Easy and Quick to write code.
2) 10x Faster in execution.
myset = {1, 7, 8, 9, 0, 5, -1}
Using for loop: Using Set comprehension:

newSet = set() {num*2 for num in myset}


for num in myset:
newSet.add(num*2) Output:
print(newSet) {-2, 0, 2, 10, 14, 16, 18}

Output:
{0, 2, 10, 14, 16, 18, -2}

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Dictionaries
• Every element/item is in key, value pair dict maintains
format. unique keys
• An ordered (from 3.7 version) collection Key: not only a string, any immutable objects allowed as key.
of arbitrary objects. Value: any arbitrary object is allowed as value.
• Accessed by key, instead of offset/index.
Dictionary creation techniques:
• Indexing (fetching element) is very fast.
Dictionary Version Interpretation
• Mutable: can grow and shrink on D = {}, D = dict() Empty dictionary
demand. D = {'name': 'Mahesh', 'age':40} Simple creation

• Iterable: can traverse through all E = {'CTO': {'name': 'Mahesh', 'age':40}} Nested dictionary
elements D = dict(name='Mahesh', age=40) Alternate creation

• Nestable: can contain dict in another D = dict([('name', 'Mahesh'), ('age', 40)]) Creation with key value pairs in list
dict. D = dict(zip(keylist, valuelist)) Creation with zipped key value lists

• Heterogeneous: can contain any type of D = dict.fromkeys(['name', 'age'], default?) Creation using keys and values with
objects. default (or None).

The keys are by default string. No other


• Does not support sequence operations.
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
types are allowed for keys in this technique.
Contd…

Dictionary methods Dictionaries


Dictionary method Interpretation Key: not only a string, any immutable object
D['name'] Indexing (fetching element) by key allowed for key.

E['CTO']['age'] Indexing (fetching element) by keys in nested Value: any arbitrary object is allowed for value.
dictionaries.
'age' in D key existence test/finding

D.keys() Dictionary keys view - Views also retain original order of dictionary.
D.values() Dictionary values view
- Reflect future changes to the dictionary
- Support set operations.
D.items() Dictionary items (key, value pairs) view

D.copy() Copy dictionary

D.clear() Remove all items in dictionary

D.update(D2) Merge by keys. Overwrites values of same key if clash


found. D2 overwrites D here.
D.get(key, default?) Fetch by key. If absent, default (or None)
Any operation/method call results
D.pop(key, default?) Remove by key. If absent, default (or error) in place change of the dictionary,
rather generating a new dictionary.
len(D), sorted(D) Length of dictionary (number items),
sorting dictionary items by keys
D[key]=42 Adding/Changing value by key
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
del D[key] Deleting item by key
Creating Dictionary using Comprehension
key_list = ['name', 'profression', 'age', 'location'] 1) Easy and Quick to write code.

value_list = ['Allu Arjun', 'hero', 35, 'hyd'] 2) 10x Faster in execution.


3) Saves memory

Using for loop: Using dictionary Comprehension:


my_dict = {} {key: value for (key, value) in zip(key_list,
for indx in range(len(key_list)): value_list)}
my_dict[key_list[indx]]=value_list[indx]

Output:
print(my_dict)
{'name': 'Allu Arjun', 'profression': 'hero',
'age': 35, 'location': 'hyd'}

Output:
{'name': 'Allu Arjun', 'profression': 'hero',
'age': 35, 'location': 'hyd'}

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Iterating Dictionary mapping
my_dict = {'name': 'Allu Arjun', 'profression': 'hero', 'age': 35, 'location': 'hyd'}

Using for loop: Using dictionary Comprehension:


for key in my_dict.keys():
if key!='age': {key:my_dict[key] for key in my_dict.keys() if key!='age'}
print(key, my_dict[key]) {key:my_dict[key] for key in my_dict.keys() if key!='age'}

for key in my_dict: {key:value for (key,value) in my_dict.items() if key!='age'}


if key!='age':
print(key, my_dict[key])
Output:
{'name': 'Allu Arjun', 'profression': 'hero', 'location': 'hyd'}
for (key,value) in my_dict.items():
if key!='age':
1) Easy and Quick to write code.
print(key, value)
2) 10x Faster in execution.

Output:
name Allu Arjun
profression hero
location hyd D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Named Tuples
• Same as tuple, except accessible by offset/index and/or keys.
>>> bob = ('Bob', 40.5, ['dev', 'mgr']) #tuple record

>>> bob[0], bob[2] # accessible by position

('Bob', ['dev', 'mgr'])

>>> bob = dict(name='Bob', age=40.5, jobs=[['dev', 'mgr']) # dictionary record

>>> bob[name], bob['jobs'] # accessible by key

('Bob', ['dev', 'mgr'])

>>> from collections import namedtuple


>>> Rec = namedtuple('my_nt', ['name', 'age', 'jobs'])
>>> bob = Rec('Bob', 40.5, ['dev', 'mgr']) # dictionary record

>>> bob[0], bob[2] # accessible by position

('Bob', ['dev', 'mgr'])


>>> bob.name, bob.age # accessible also by key/name

('Bob', 40.5)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Files
• To deal with files (reading, writing files)
• The built-in open function creates a python file object.
File methods (contd…)
• Serves as a link to a file residing on the machine.
File method Interpretation
File creation techniques: op.writelines(aList) Write all line strings in a list into
File creation Interpretation file.
op = open(r'C:\temp\spam.txt', 'w') Create output file ('w' means write) op.close() Manual closing file.

ip = open('ham.txt', 'r') Create input file ('r' means read). op.flush() Flush output buffer into disk.
Ip = open(r'C:\temp\ham.txt') Default mode is 'r'
any_file.seek(N) Change file position to offset N for
next operation.
File methods
File processing modes:
File method Interpretation
mode Interpretation mode Interpretation
aStr = ip.read() Read entire file into a string
r Read a text file. wb Write to binary file.
aStr = ip.read(N) Read upto next N chars (or bytes) into a string
w Write to a text file. + Read & write to
aStr = ip.readline() Read next line (including \n newline) into a string same file.
a Append text to end
aList = ip.readlines() Read entire file into list of strings (with \n) of file.
D. Chaitanya Reddy rb Read binary file.
op.write(aStr) Write a string of chars (or bytes) into file.(IIT Roorkee Alumni, AI Expert)
Storing objects in Files
My Data.txt

Any Single Object Same Single Object Pickle (using pickle module)

List List
Store / Save . Retrieve
object
object
.
.
Shelve (using shelve module)

my_list=[1, 'hi', 3.4, [6, 7]] my_file = open(r'C:\tmp\My Data.txt', 'rb')


import pickle saved_obj = pickle.load(my_file) Pickling & Unpickling
F = open(r'C:\tmp\My Data.txt', 'wb') print(saved_obj)
pickle.dump(my_list, F)
F.close()
Output:
[1, 'hi', 3.4, [6, 7]]
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…

Storing objects in Files


MyData

MyDa
ta.bak
Pickle (using pickle module)

multiple
multiple Store / Save
MyDa
Retrieve
objects,
ta.bat
objects access by
their key
MyDat
a.dir Shelve (using shelve module)

my_list=[1, 'hi', 3.4, [6, 7]] my_shelve = shelve.open('MyData')

my_map={'name': 'Allu Arjun', 'profression': my_saved_list = my_shelve['list_obj']


'hero', 'age': 35, 'location': 'hyd'}
my_saved_map = my_shelve['allu_info']
my_tup=('Bob', 40.5, ['dev', 'mgr'])
my_saved_tup = my_shelve['bob_details']
import shelve
Creates these 3 print(my_saved_list, my_saved_map, my_saved_tup) Shelve
my_data = shelve.open('MyData') files in CWD Technique
my_data['list_obj']=my_list
Output:
my_data['allu_info']=my_map Writes object
information to 3 [1, 'hi', 3.4, [6, 7]] {'name': 'Allu Arjun', 'profression':
my_data['bob_details']=my_tup files 'hero', 'age': 35, 'location': 'hyd'} ('Bob', 40.5, ['dev',
'mgr'])
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
my_data.close()
Open a file in required
File Context Managers
Read or write content to file
process mode based on process mode Close the file Simplified Corrected code
1 2 3 1 3 with open(r'C:\temp\hello.txt', 'r') as my_file:
for line in my_file:
2
print(line[:5])
Error prone code
1 my_file = open(r'C:\temp\hello.txt', 'r')

for line in my_file:


2
print(line[:5])
3
my_file.close()

Corrected code
1 my_file = open(r'C:\temp\hello.txt', 'r')
try:
2 for line in my_file:
print(line[:5])
finally:
3
my_file.close()
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Built-in Types Summary
Object Type Category Ordered? Mutable? Nestable? Elements Unique?
All Numbers Numeric N/A No N/A N/A
Strings Sequence Yes No N/A No
Lists Sequence Yes Yes Yes No
Dictionaries Mapping Yes (from 3.7) Yes Yes No
Tuples Sequence Yes No Yes No
Sets Set No Yes No Yes
Frozen sets Set No No Yes Yes
Files Extension N/A N/A N/A N/A
bytearray Sequence Yes Yes N/A No

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

Built-in Types Summary

Mutable Types Immutable Types

bytearray
List

frozenset
Numbers
Dictionary Set

String Tuple

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Garbage Collection
• Assignment Operator.
Definition:
Recap…. Claiming back the object's memory if no references (reference counter
• Variables are created and assigned header field value of the object must be ZERO) to that object.
to value when they are first assigned int

x = 42
1
a value. x 42

• Variable values are changed on


further assignments. int

• Variables are replaced with their x = 'spam' x X 42


0

values when used in expression. str


'spam' 1

• Variables must be assigned before


they use in expressions.

In memory… Header field of every object to int

store the type of the object.


x = 3.145 x X 42 0

Names References Objects str

X 'spam' 0

type designator
float

reference counter 3.145 1

a 3
int

x = {3, 9, 1} x X 42 0

str

1) Variable Names, Objects are saved in different parts of memory.


Header field of every object to
store number of references to
X 'spam' 0

object.
float

2) D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


References are links/pointers connecting those 2 parts of memories
set
1 set: {3, 9, 1} X 3.145 0
Shared References, Equality
Shared References: is operator
int
x = 3764 x 3764
a = 3 a 3 1

y = 3764 y 3764
int

b = a a 3 2

x is y prints False object equality check


b
x == y prints True value equality check

Definition:
If multiple variables are referring to same object (reference counter
header field value of the object is greater than ONE), then they shall
be called as shared reference x = 3764 x 3764

y = x y

str
spam 1

int
x is y prints True
a 3 1

a = 'spam' x == y prints True


b D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
References vs Copies
X = [1, 2, 3] [k] [y]
[0] [1] [2]
L = ['a', X, 'b']
L D
References

print(L)
[0] [1] [2]
['a', [1, 2, 3], 'b']
'a' X 'b' 2

D = {'k': X, 'y': 2}
References
print(D)
1 2 3
{'k': [1, 2, 3], 'y': 2}

X[1] = 'hi' [k] [y]


[0] [1] [2]
print(L)
L D
['a', [1, 'hi', 3], 'b']

[0] [1] [2]


print(D)
{'k': [1, 'hi', 3], 'y': 2}
'a' X 'b' 2

D. Chaitanya
1 Reddy (IIT'hi'
Roorkee Alumni,
3 AI Expert)
Contd…

References vs Copies
X = [1, 2, 3] [0] [1] [2] [x] [y]
[0] [1] [2]
L = ['a', X[:], 'b']
X L D
D = {'x': X.copy(), 'y': 2}
Copies [0] [1] [2] [0] [1] [2]
print(L) 'a' 'b'
1 2 3 2
['a', [1, 2, 3], 'b']

print(D)
1 2 3 1 2 3
{'x': [1, 2, 3], 'y': 2}

X[1] = 'hi' [0] [1] [2] [0] [1] [2] [x] [y]
print(X) X L D
[1, 'hi', 3]

[0] [1] [2] [0] [1] [2]


print(L) 1 'hi' 3 'a' 'b' 2
['a', [1, 2, 3], 'b']

print(D)
1 2 3 1 2 3
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
{'x': [1, 2, 3], 'y': 2}
Statements, Expressions & Syntax

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Program Hierarchy
• Programs are composed of modules Simple statements
Ex:
• Modules contains statements x = 1
• Statements contains expressions name = 'Mahesh'
print(name)
• Expressions create and process objects

Compound statements
Ex:
if x > 100:
if name == 'python':
print(name)
else:
print(x)

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Python Statements
Name Purpose / Meaning Example
Assignment Creating references a = 'good'
x = 42
Calls and other expressions Running functions log.write(“Hello World”)

print calls Printing objects print('The killer joke')

If/elif/else Selecting actions if 'python' in text:


print(text)
for/else Iteration for el in mylist:
print(el)
while/else General loops while x > y:
print('hello')
pass Empty place holder while True:
pass
break Loop exit while True:
if exittest(): break
continue Loop continue while True:
if skiptest(): continue
import Module access import sys

from Attribute access from sys import stdin

def Functions and methods def myMethod(a, b, c):


print(a+b+c)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Python Statements
Name Purpose / Role Example
return Functions results def newMethod(a, b, c):
return a+b+c

yield Generator functions def myGen(n):


for i in range(n): yield i*2

global Namespaces X = 'old'


def function():
global X,Y
X = 'new'

nonlocal Namespaces def outer():


x = 'old'
def inner():
nonlocal x; x = 'new'

class Building objects class subclass(superclass):


staticdata = []
def method(self): pass

try/except/finally Managing exceptions try:


action()
except:
print('action error')

raise Triggering exceptions raise myException('more details about error')

assert Debugging checks assert x > y, 'x too small'

with/as Context managers with open('data.txt') as myfile:


process(myfile)

del Deleting references delD. data[k]


Chaitanya Reddy
/ del(IIT data[i:j]
Roorkee Alumni,
/ AI Expert)
del obj.attr / del a
Assignment & Expression Statements
Assignment statement forms: Advantages:
Operation Interpretation • Less typing.
s1 = 'spam' Basic form • Faster in execution.
s1, s2 = 'spam', 'ham' Tuple assignment (positional) • Perform in place changes for mutable objects.
s1 += 42 Augmented assignment
[s1, s2] = ['spam', 'ham'] List assignment (positional)
a, b, c, d = 'spam' Sequence assignment (generalized)
a, *b = 'spam' Extended sequence unpacking
s1 = s2 = 'hello' Multiple target assignment

Both s1 & s2 objects referring to same


string object ('hello') in memory.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Variable Name Rules & Conventions
Rules Must starts with Must followed by Conventions
• Begin with underscore (_X) shall not imported by a
• Syntax: (Underscore or letter) + (any number from module import * statement.
of letters, digits or underscores)

Ex: _spam, spam, Spam_1 • Have 2 leading and trailing underscores (__X__) are
1_spam, spam$, @#! system defined names that have special meaning to
interpreter.
• Case sensitive.
Ex: SPam is not same as spam • Begin with 2 underscores and do not end with 2 more
self is NOT a reserved
(__X) are localized (mangled) to enclosing classes.
• Reserved words are off-limit. word in python.

• Just single underscore (_) retains the result of last


expression when working interactively.

• Class names starts with uppercase letter, Module


D. Chaitanya Reddy (IIT Roorkeename
Alumni, AIstarts
Expert) with lower case letter.
print operations
• print prints things to the standard output stream (called as stdout).
• Used heavily while debugging the code.
• Syntax:
print(object1, object2, ……[, sep=' '][, end='\n'][, file=sys.stdout][, flush=False])
Ex:
x = 42 print(x) prints
42
my_list = ['hi', 3.4, 5, {'a': '1'}] print(my_list) prints
['hi', 3.4, 5, {'a': '1'}]
print(x, my_list) prints
42 ['hi', 3.4, 5, {'a': '1'}]
print(x, my_list, sep='\t') prints
42 ['hi', 3.4, 5, {'a': '1'}]
print(x, my_list, sep='@', end='!!\n') prints
42@['hi', 3.4, 5, {'a': '1'}]!!
print(x, my_list, sep='#', end='…', file=open(r'C:\tmp\op.txt', 'w'))
print(x, my_list, sep='$', flush=true) prints
42$['hi', 3.4, 5, {'a': '1'}]
print() prints
empty line
name, age, weight = 'Mahesh', 45, 72.67
print('%s, age %i yrs, weight %0.2f kg' % (name, age, weight)) prints
Mahesh, age 45 yrs, weight 75.34 kg
print('{}, age {} yrs weight {} kg'.format(name, age, weight)) prints Mahesh, age 45 yrs, weight 75.34 kg
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
if–elif–else
Operator Meaning
if statement: x < y, x <= y, Magnitude comparison
1. Should evaluates to True/False.
syntax 2. Can use logical and, logical or for x > y, x >= y
combination of multiple conditions
if SOME_CONDITION: 3. () – parenthesis are optional. x == y, x != y Value equality operators
single or multi line code

1. Should evaluates to True/False. Object Interpretation Value


2. Can use logical and, logical or for
combination of multiple conditions.
if SOME_VARIABLE: 3. () – parenthesis are optional. 'spam' Non empty string True
single or multi line code '' Empty string False
Ex: [1, 2] Non empty list or some data structure True
if x>y: if age: [] Empty list or some data structure False
Indentation:
inside block x = 1 x = 1 {'a':1} Non empty dictionary True
y = 2 {} Empty dictionary False
1 Non zero number True
Ex: 0.0 Zero number False
if x>100 and y: None Not an object. Empty place holder False
print(name) D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
if–elif–else
if-else statement: None:
• An object and allocated a memory by python.
syntax
if SOME_CONDITION: if SOME_VARIABLE:

single or multi line code single or multi line code Ex:


else: else: k = None
single or multi line code single or multi line code my_list = [None] * 10
print(my_list)
Can be zero/single
else block [None, None, None, None, None, None,
None, None, None, None]

Ex:
if x or y<6:
print(name)
else:
print(x)

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

if–elif–else
if-elif-else statement: Ex:
if name=='python':
syntax
if SOME_CONDITION: print('beginning')
single or multi line code elif name=='machine':
elif SOME_CONDITION: Can be print('season-1')
zero/single/multi
single or multi line code elif blocks elif name=='deep':
else:
single or multi line code
print('season-2')
else:
print('conclusion')
If a single line code present in any block,
the below syntax also allowed:
Ex:
if SOME_CONDITION: single line code if name=='python': print('beginning')
elif SOME_CONDITION: elif name=='machine':
single or multi line code print('season-1')
else: single line code elif name=='deep': print('season-2')
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
else: print('conclusion')
Contd…

if–elif–else
Nested if statement: Nested if-else statement:

if x > 100: if x > 100:


if name == 'python': if name == 'python':
print(name) print(name)
if x > 110: else:
print('begining') if name == 'machine':
print('begining')
if name == 'deep':
print('conclusion')
else:
x = 78

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

if–elif–else
Nested if-elif-else statement: if-else ternary expression:
if x > 100:
if name=='python': if year<2022:

print('hi') movie = 'bahubali'

elif name=='machine': else:


print('pushpa') movie = 'RRR'
else:
print('RRR')
elif x==100:
print('bahubali') movie = 'bahubali' if year<2022 else 'RRR'
else:
if name == 'machine':
Syntax:
print('begining') var = VALUE1 if SOME_CONDITION else VALUE2
if name == 'deep':
print('conclusion')
else:
x = 78
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
print('Oscar')
while loop
1. Should evaluates to True/False.
2. Can use logical and, logical or for
combination of multiple conditions.
Syntax: 3. () – parenthesis are optional. Ex2:
while SOME_CONDITION: #loop test x = 'spam'
single or multi line code #loop body while x:
else: #optinal else print(x, end=' ')
single or multi line code #run if and only if loop exit normally. x = x[1:]

Output: spam pam am m


Ex1:
a, b = 0, 10 Ex3:
while a < b:
while True:
print(a, end=' ')
print('type Ctrl+C to stop me.')
a += 1

Output: type Ctrl+C to stop me.


Output: 0 1 2 3 4 5 6 7 8 9
.
.
.
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
break, continue, pass, loop else
• break – jumps out of the while True:
name = input('Enter name: ')
Output:
Enter name: bob
closest enclosing loop (skip if name=='stop': break Enter age: 20
else: Hello bob 40
the entire loop statements). age = input('Enter age:’) Enter name: stop
print('Hello', name, int(age)*2)

Output:
• continue – jumps to the x = 10
8 6 4 2 0
while x:
start of the closest x -= 1
enclosing loop (to the if x%2!=0: continue
loop's first line) print(x, end=' ')

x = 10 Output:
• pass – does nothing at all. while x: Infinite loop
It's an empty statement pass
placeholder. x = y // 2 Output:
while x > 1: Prints whether the
if y % x == 0: y is prime or not.
print(y, 'has factor', x)
• Loop else – runs if and break
only if loop is exited x -= 1
else: Reddy (IIT Roorkee Alumni, AI Expert)
D. Chaitanya
normally. print(y, 'is prime')
for loop
1. Any object that support iteration
protocol or indexing protocol. Ex3:
2. Loop iterates for every element in
object irrespective of any condition. movie = 'bahubali'
Syntax: for ch in movie: print(ch, end=' ')
for var in OBJECT: #assign OBJECT elements to var

single or multi line code #loop body


Output: b a h u b a l i
else: #optinal else
Ex4:
single or multi line code #run if and only if loop exit normally.
my_tup = ('I am', 2, 'times', 'good')
Like while loop, break, continue, pass, loop else for el in my_tup: print(el, end=' ')
are also applicable as it is to for loop too.
Ex1: Output: I am 2 times good

for x in ['spam', 'eggs', 'ham']:


print(x, end=' ') Ex5:
my_list = [(1, 2), (7, 14), (-2, -4)]
Output: spam eggs ham for (a, b) in my_list: print(a, b, sep='x2= ')
Ex2:
Output:
prod = 1
1x2= 2
for num in [1, 2, 3, 4, 5]: prod *= num
7x2= 14
print(prod)
-2x2= -4
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Output: 120
Contd…

for loop
Ex6: Ex9:
L1 = [(1, 2, 3), (7, 14, 21), (-2, -4, -6)] D1 = {'a': 2, 'b': 4, 'c': 16}
for (a, b, c) in L1: print(a, b, c, sep='>>') for k in D1:
print(k, D1[k], sep='=>', end=', ')
Output:
1 >> 2 >> 3 for k in list(D1.keys()):
7 >> 14 >> 21 print(k, D1[k], sep='=>', end=', ')
-2 >> -4 >> -6
Ex7: for (k, vl) in list(D1.items()):
L2 = [((1, 2), 3), ((7, 14), 21), ((-2, -4), -6)] print(k, vl, sep='=>', end=', ')
for ((a, b), c) in L2: print(a, b, c, end=', ')
Output: a=>2, b=>4, c=>16
Output:
Ex10:
1 2 3, 7 14 21, -2 -4 -6,
for line in open('c:\tmp\info.txt').readlines():
Ex8: print(line)
L3 = [(1, 2, 3, 4), (10, 20, 30, 40)]
for T in L3: for line in open('c:\tmp\info.txt', 'r'):
print(T[-1], T[1:], T[0:2], end=', ') print(line)

Output: Output: prints line by line the content


4 (2, 3, 4) (1, 2), 40 (20, 30, 40) D.(10, Reddy (IIT Roorkee Alumni,in
Chaitanya20), info.txt file.
AI Expert)
Nested for loop
A for loop inside another for loop inside another for loop soon…

Ex:
items = ['aaa', 111, (4, 5), 2.01] 1. Like for loop, nesting also applicable as it is to
tests = [(4, 5), 3.14] while loop too.
for key in tests:
for item in tests: 2. All the examples shown for for loop can also
if item==key: achieved with while loop, but needs more lines of
print(key, 'was found') code.
break
else: 3. for loop has many benefits (comprehensions, manual
print(key, 'not found!') indexing, etc…) compared to while loop in python.

Output:
(4, 5) was found
3.14 not found!

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Built-in functions used with for
range: built-in function produces a series of successively higher integers, which can be used
No need to write list(range(3))
as indexes in a for for i in range(3):
as range() support indexing protocol.
print(i**3, '% success', end=', ') S = 'abcdefghijk'
>>> range(5)
Output: 0 % success, 1 % success, 8 % for ch in S[0:len(S):2]:
range(0, 5)
success,
>>> list(range(5)) print(S[id], end=' ')

[0, 1, 2, 3, 4] Output: a c e g i k
X = 'spam'
>>>list(range(2, 5))
for ix in range(len(X)):
[2, 3, 4] S = 'abcdefghijk'
X = X[ix:] + X[:ix]
>>>list(range(0, 10, 2)) for ch in S[::2]:
print(X, end=' ')
[0, 2, 4, 6, 8] print(S[id], end=' ')
Output: spam, pams mspa amsp
>>>list(range(-3, 3)) Output: a c e g i k

[-3, -2, -1, 0, 1, 2, 3]


S = 'abcdefghijk'
>>> list(range(4, -5, -2))
for id in range(0, len(S), 2):
Same output, but multiple ways to
[4, 2, 0, -2, -4]
print(S[id], end=' ') write with for
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Output: a c e g i k
Contd…

Built-in functions used with for


zip: built-in function returns a series of parallel-item tuples which can be used to traverse
multiple sequences in a for S1='abc' If both sequences are not of same
length, zip truncates to shortest length
>>> L=[1, 2, 3, 4] S2='xyz123'
>>> LS=[1, 4, 9, 16] for (c1, c2) in zip(S1, S2):
>>> LQ=[1, 8, 27, 64] print(c1, c2, sep='=>', end=', ')
>>> zip(L, LS) Output: a=>x, b=>y, c=>z,
<zip at 0x1f3356f40c0>
>>>list(zip(L, LS)) keys=['spam', 'eggs', 'ham']
[(1, 1), (2, 4), (3, 9), (4, 16)] values=[1, 7, 11]
>>>list(zip(L, LS, LQ)) D = dict()
[(1, 1, 1), (2, 4, 8), (3, 9, 27), (4, 16, 64)] for (key, val) in zip(keys, values):
for (n, s, q) in zip(L, LS, LQ): D[key]=val
print(n, s, q, sep='=>') print(D)
Output: 1=>1=>1 No need to write Output: {'eggs': 7, 'ham': 11, 'spam': 1}
list(zip(L, LS, LQ))
2=>4=>8 … D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
as zip() is iterable.
Contd…

Built-in functions used with for


map: built-in function applies a passed-in filter: a built-in function applies a passed-
function to each element in iterable object in function to each element in iterable object
and returns a list contains all function call and returns a list contains all elements for
results. which the function call resulted to True.
>>> L=[-3, -6, 0, 9, 14] >>> L=[-3, -6, 0, 9, 14]
>>> map(abs, L) >>> filter(lambda x: x>0, L)
<map at 0x1f3369d84c0> <filter at 0x1c431b97e20>
>>> list(map(abs, L)) >>> list(filter(lambda x: x>0, L))
[3, 6, 0, 9, 14] [9, 14] No need to write list(filter(lamb…, LN))
No need to write
as filter() is iterable.
list(map(math.sqrt, LN))
as map() is iterable.
LN=[1, 4, 34, 56, 75] LN=[1, 4, 34, 56, 75]
for el in map(math.sqrt, LN): for el in filter(lambda x: x>10 and x<65, LN):
print(int(el, end=', ') print(el, end=',')
Output: 1.0, 2.0, 5.83, 7.48, 8.66, Output: 34,56,
map(math.pow, LN, [2, 3, 0, 1, 0.5])D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…

Built-in functions used with for


enumerate: built-in function generates reduce: a function present in functools
both the values and indexes of the items in an module that accepts a function and iterable,
iterable so we do not need count manually. will return a single element.
>>> L=[-3, -6, 1, 9, 14]
>>> S='pushpa'
>>> from functools import reduce
>>> enumerate(S)
reduce(lambda x, y: x+y, L)
<enumerate at 0x1f33568ff80>
Output: 15 15
>>>list(enumerate(S))
[(0, 'p'), (1, 'u'), (2, 's'), (3, 'h'), (4, 1 +
'p'), (5, 'a')] -8 +
No need to write
list(enumerate(S)) -9 +
for (i, v) in enumerate(S): as enumerate() is iterable.
+
print(v*i, end=', ')
-3 -6 1 9 14
Output: , u, ss, hhh, pppp, aaaaa,
>>> reduce(lambda x, y: x*y, L)
Output:
D. Chaitanya Reddy (IIT Roorkee 2268
Alumni, AI Expert)
Recap….
Iterables & Iterations
1. Any object that support iteration Z = zip([1, 2, 3], [11, 12, 13], [1, 4, 9])
protocol or indexing protocol.
Create Iterable object for Manual
2. Loop iterates for every element in IZ=iter(Z)
Syntax: object irrespective of any condition. range object. iterations

for var in OBJECT: #assign OBJECT elements to var


IZ.__next__(), IZ.__next__(), IZ.__next__()

single or multi line code #loop body (1, 11, 1), (2, 12, 4), (3, 13, 9)
else: #optinal else F=open(r'C:\tmp\info.txt') #call iter() directly
single or multi line code #run if and only if loop exit normally.
F.__next__(), F.__next__(), F.__next__()
Iteration Protocol: A Protocol that supports iter() and 1st line of file, 2nd line of file, 3rd line of file
__next__() calls.
Calling __next__() method raises a built-in exception:
Indexing Protocol: A Protocol that supports indexing StopIteration after the last element in iterable object.
operation like [0], [4].
M = map(math.pow, [1, 2, 3], [2, 3, 3])
R=range(-5, 0) Supporting indexing operation
IM = iter(M)
R[1], R[0], R[4] Output:-4, -5, -1 IM.__next__(), IM.__next__(), IM.__next__()
Can still create iterable object that
Manual (1.0, 8.0, 27.0)
supports indexing operation
I=iter(R) iterations
IM.__next__()
I.__next__(), I.__next__(), I.__next__() Raises
D. Chaitanya Reddy (IIT Roorkee StopIteration
Alumni, AI Expert) error
Protocols Summary
Indexing Protocol Iteration Protocol
• Protocol that supports indexing operation. • Protocol that supports iter() or __iter__()
and __next__() calls.

• Elements can be accessed using notation obj[0], • Elements can be accessed using __next__()
obj[1], etc… method call.

• Can access element at any index at any time. • Should start accessing the elements from the start and
access sequentially only using __next__() call.

• Elements in object can be accessed multiple times • Elements in object can be accessed only once. Need
without reinitializing object. to reinitialize the object to access elements again.

• Accessing elements with wrong index results into • Calling __next__() after fetching the last element
IndexError. results into StopIteration Error.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Comprehensions 1)
2)
Less coding
Run much faster.
List with for loop: List Comprehension:
L = list(range(0, 20)) print([x/2 for x in range(0, 20)])
LN = []
for x in L:
val = x/2
LN.append(val)
print(LN)
Output: [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5]

Set Comprehension:
print({int(math.pow(x, 3)/math.sqrt(x)) for x in range(1, 20)})
Output: {1024, 1, 129, 5, 15, 401, 32, 1573, 1191, 181, 55, 316, 88, 733, 1374, 609, 871, 498, 243}

Dictionary Comprehension:
print({x: int(math.pow(x, 3)/math.sqrt(x)) for x in range(1, 20)})
Output: {1: 1, 2: 5, 3: 15, 4: 32, 5: 55, 6: 88, 7: 129, 8: 181, 9: 243, 10: 316, 11: 401, 12: 498, 13: 609,
14: 733, 15: 871, 16: 1024, 17: 1191, 18: 1374, 19: 1573}
bahubali-2016
RRR-2023
With files: Pushpa-2022
[('2023' in line, line[:5]) for line in open(r'C:\tmp\test.txt')]
Output: [(False, 'bahub'), (True, 'RRR-2'), (False, 'Pushp'), (False, 'Avata')] Avatar-2021

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

Comprehensions
List with for loop with if condition: List Comprehension with if filter:
L = list(range(0, 20)) print([x/2 for x in range(0, 20) if x%2==0])
LN = []
for x in L:
if x%2==0:
val = x/2
LN.append(val)
print(LN)
Output: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

Set Comprehension:
print({int(math.pow(x, 3)/math.sqrt(x)) for x in range(1, 20) if x%2==0})
Output: {32, 1024, 5, 498, 181, 88, 316, 733, 1374}

Dictionary Comprehension:
print({x: int(math.pow(x, 3)/math.sqrt(x)) for x in range(1, 20) if x%2==0})
Output: {2: 5, 4: 32, 6: 88, 8: 181, 10: 316, 12: 498, 14: 733, 16: 1024, 18: 1374}
bahubali-2016
RRR-2023
With Files: Pushpa-2022
[('2023' in line, line[:5]) for line in open(r'C:\tmp\test.txt') if '???' not in line] Avatar-2021
Output: [(False, 'bahub'), (True, 'RRR-2'), (False, 'Pushp'), (False, 'Avata')] Pushpa2-???

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

Comprehensions
Nested loops: List Comprehension with nesting:
res = [] print([x+y for x in 'abc' for y in 'lmn'])
for x in 'abc':
for y in 'lmn':
res.append(x+y)

print(res)

Output: ['al', 'am', 'an', 'bl', 'bm', 'bn', 'cl', 'cm', 'cn']

Nesting with if filter: List Comprehension with nesting, if filter:


res = [] print([int(math.pow(x, y)/math.sqrt(x)) for x in range(1, 6) if
RL = [1, 0, 0, 2, 3] x%2==0 for y in RL if y>0])
L = range(1, 6)
for x in L:
if x%2==0:
for y in RL:
if y>0: res.append(int(math.pow(x, y)/math.sqrt(x)))
print(res)
Output: [1, 2, 5, 2, 8, 32]

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Documentation, Help
Option Role Example
dir function List of attributes available in objects dir([])
dir(tuple)
Docstrings:__doc__ In-file documentation attached to objects import collections
print(collections.__doc__)
print(list.__doc__)
help function Interactive help for objects help(list)
import sys
help(sys)
PyDoc: HTML reports Module documentation in a browser python –m pydoc –b (in cmd)

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Functions, Scopes & Arguments

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Functions def lambda

• A set of code statements so that it can


called/run multiple times in a program.
scope
• Optionally return result back to callers. scope
non local
function global
• Can be nested too.
• Most basic program structure python
using using
provides to maximize the code reuse. return yield

• Helps us to design complex programs


Result/None
• Allow us to split larger systems into
manageable parts.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

Functions
Syntax: • defs are also nothing but objects.
def name(arg1, arg2, ……, argN): def get_square(num):
... return num**2
... 1. Returning value is optional. sq_val = get_square(4)
2. If NO return means, return None
return value 3. Just return means, return None
my_func = get_square
result = my_func(5)
• defs can be nested
X = 99
• Can attach arbitrary attributes to defs to store some
def f1(): information.
name = 'Ganesh'
def f2():
get_square.last_num = 5
print('Hello World!')
get_square.list_nums = []
f2()
get_square.list_nums.append(4)
get_square.list_nums.append(5)
f1()

• defs are not evaluated until they are


reached to run.
• defs are not reached to run until they
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
are called.
Scopes
The scope of variable is determined only by L E G B rule
location of variables created in source code of
your program files.
name = 'Mahesh' # Global (module) scope name

def func():
name = 'Suresh' # Local(function) scope name : a different variable
print(name)

print(name)

func()

name = 'Mahesh' # Global (module) scope name

def bunc():
info = 'Suresh' # Local(function) scope name : a different variable
def junc():
age = 56
print(age)
print(info)
junc()
print(name)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
bunc()
Contd…

Example 1: No name collisions, Hiding


Scopes
Example 3: Do not want to hide names, create global differently
X = 99 X = 99
def f1():
name = 'Ganesh' def f1():
def f2(): global X
weight = 67.4 global Y
print('Hello World!') name, X, Y = 'Ganesh', 88, 0
print(X, name, weight) print('pushpa', X, name)
f2() Output: def f2():
Hello World! global X
f1() 99 Ganesh 67.4 global Y
global Z
Example 2: Names hided nonlocal name
X = 99 weight, name, X, Y, Z = 67.4, 'Suresh', 77, 1, 10.99
print('Hello World!')
def f1(): print(X, name, weight)
name, X = 'Ganesh', 88 f2()
print('pushpa', X, name) print('RRR', X, name, Y)
def f2():
weight, name, X = 67.4, 'Suresh', 77
f1()
print('Hello World!')
print(X, name, weight) print(X, Y, Z)
Output:
f2()
Output: pushpa 88 Ganesh
Pushpa 88 Ganesh Hello World!
f1() 77 Suresh 67.4
print(X) Hello World!
77 Suresh 67.4 RRR 77 Suresh 1
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
99 77 1 10.99
Accessing globals differently, Factory Functions
#thismod.py
def maker(N):
var = 99 def action(X):
return X**N
def local(): return action
var = 0

def glob1(): f = maker(2)


global var print(f)
var += 1 Output: <function maker.<locals>.action at 0x00000133177BE7A0>
def glob2():
var = 0 print(f(3))
import thismod Output: 9
thismod.var += 1
print(f(4))
def glob3(): Output: 16
var = 0
import sys g = maker(3)
mod_name = sys.modules['thismod'] print(g(4))
mod_name.var += 1 Output: 64
def test(): print(f(4))
print(var) Output: 16
local(); glob1(); glob2(); glob3()
print(var)
Output:
test() 99 D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
102
Arguments
#test1.py Function definition, arguments
• Immutable arguments are passed by value. def multiply(x, y):
y += 1
• Mutable arguments are passed by reference. if isinstance(x, list): x = x.copy(); x.pop(-1)
x.pop(-1) or
Names Objects elif isinstance(x, str): x = x[:-1]
x = x+' - good'
else:
x = x+1 Arguments matching
[3, 'hi', 4.5, 'bye'] by position
lis1
return x*y, x, y
caller
tim 2 lis1 = [3, 'hi', 4.5, 'bye']
Caller, arguments
tim = 2
res = multiply(lis1, tim)
print(res, lis1, tim)
x
Output: ([3, 'hi', 4.5, 3, 'hi', 4.5, 3, 'hi',
function 4.5], [3, 'hi', 4.5], 2)
y 2
s1 = 'Mahesh' Caller, arguments
tim = 2
result, s1_re, tim_re = multiply(s1, tim)
print(result, s1_re, tim_re)
Output: Mahesh - goodMahesh - goodMahesh - good
Mahesh - good 3
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Matching Args, Passing Args
res = fun(c=1, a=-11, b=4)
• Matching by position from left to right – positional args

• Matching by argument name – keyword args

def fun(a, b, c): res = fun(7, 0, -3)


• Specify default values for optional args return a+b+c

• Collect arbitrarily many positional or keyword args


res = nut(7, z=20)

• Pass arbitrarily many positional or keyword args


res = nut(7, 0)

• Args must be passed by name – keyword only args


def nut(x, y=3, z=0, w=-1): res = nut(7)
return x+y-z*w
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…
Matching Args, Passing Args
Output: (1, 6, 0, -7, 9)
gun(1, 6, 0, -7, 9)
• Matching by position from left to right – positional args Output: (7, -3)
gun(7, -3)

gun()
• Matching by argument name – keyword args Output: ()

def gun(*args): gun(7)


• Specify default values for optional args print(args) Output: (7,)

• Collect arbitrarily many positional or keyword args o/p: {'a':1, 'b':6, 'c':0, 'd':-7}
sun(a=1, b=6, c=0, d=-7)
o/p:{'a':7, 'b':-3}
sun(a=7, b=-3)
• Pass arbitrarily many positional or keyword args
sun()
Output: {}
• Args must be passed by name – keyword only args
def sun(**args): sun(a=1)
print(args) o/p: {'a':1}

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…
Matching Args, Passing Args
Output: 1 5 (2, 3) {'x': 7, 'y': 9}
bat(1, 2, 3, x=7, b=5, y=9)
• Matching by position from left to right – positional args

• Matching by argument name – keyword args

def bat(a, *pargs, b, **kargs):


• Specify default values for optional args print(a, b, pargs, kargs)

• Collect arbitrarily many positional or keyword args 1.


2.
Assign nonkeyword args by matching position
Assign keyword args by matching names
3. Assign extra nonkeyword args to *argname tuple
4. Assign extra keyword args to **argname dictionary
5. Assign default values to unassigned args in header.
• Pass arbitrarily many positional or keyword args

• Args must be passed by name – keyword only args

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…
Matching Args, Passing Args Output: 7 0 -3 4
args = (7, 0)
• Matching by position from left to right – Output: 7 0 -3 4
args += (-3, 4)
cat(*args)
positional args args = {'a': 7, 'b': 0}
Output: 7 0 -3 4
args['c']=-3
args['d']=4 cat(c=-3, a=7, d=4, b=0)
cat(**args)
• Matching by argument name – keyword args

def cat(a, b, c, d): cat(7, 0, -3, 4)


• Specify default values for optional args print(a, b, c, d) Output: 7 0 -3 4

cat(*(1, 2), **{'d':4, 'c':3}) # same as calling cat(1, 2, d=4, c=3)


Output: 1 2 3 4
• Collect arbitrarily many positional or keyword
args cat(1, *(2, 3), **{'d':4}) # same as calling cat(1, 2, 3, d=4)

Output: 1 2 3 4

cat(1, c=3, *(2,), **{'d':4}) # same as calling cat(1, 2, c=3, d=4)


• Pass arbitrarily many positional or keyword Output: 1 2 3 4
args
cat(1, *(2, 3), d=4) # same as calling cat(1, 2, 3, d=4)
Output: 1 2 3 4

• Args must be passed by name – keyword only cat(1, *(2,), c=3, **{'d':4}) # same as calling cat(1, 2, d=4, c=3)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI
1 Expert)
args Output: 2 3 4
Contd…
Matching Args, Passing Args
1. All args appear after * in function header are keyword only args.

• Matching by position from left to right – 2. keyword only args must be present before **args and after *args, when both are
present in function header.
positional args 3. Arg name appearing before *args are default args, not keyword only args.

veg(7, -1, 9)
Output: 7 -1 9 Type error: veg() takes 1
positional arg, but given 3
veg(c=9, a=7, b=-1)
• Matching by argument name – keyword args

def veg(a, *, b, c): veg(7, b=-1, c=9)


• Specify default values for optional args print(a, b, c) Output: 7 -1 9

• Collect arbitrarily many positional or keyword Output: 'CP' 1, 'SI'


args rat(c='SI', a='CP', b=1)
rat(1, 2)
Type error: rat() takes 1
positional arg, but 2 were given
Output: 1 'SP', 'IG'
• Pass arbitrarily many positional or keyword rat(a=1)
args

def rat(a, *, b='SP', c='IG'): res = rat(1)


• Args must be passed by name – keyword only print(a, b, c) Output: 1 'SP', 'IG'
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
args
Contd…
Matching Args, Passing Args
Summary of Functions arguments matching forms:

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Function Design Principles
• Use arguments for input and return for output.

• Use global variables only when truly necessary.

• Do not change mutable arguments unless caller expects it.

• Each function should have a single and unique logic.

• Function size should relatively small.

• Avoid changing variable in another module directly.


D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Function execution environment

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Recursive Function
Definition: A function that calls itself either directly or indirectly in order to loop.
Ex: sum of numbers in a list.
def mysum(L): def mysum(L):
if not L: return 0 if not L else L[0]+mysum(L[1:])
return 0
else: mysum([1, 2, 3, 4, 5])
return L[0] + mysum(L[1:]) Ouput: 15

mysum([1, 2, 3, 4, 5])
Ouput: 15

def normsum(L):
sum = 0
for val in L: sum += el
return sum

normsum([1, 2, 3, 4, 5])
Ouput: 15

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Function objects, Indirect calls
Every function is also an object. Function's built-in attributes Function's custom attributes
Ex: print(echo) echo.count = 0
echo.count += 1
def echo(msg): echo.__name__ print(echo.count)
print(msg)
dir(echo) echo.handles = 'Button'
echo('Direct Call') print(echo.handles)
Ouput: Direct Call echo.__code__
dir(echo) → lists custom attributes too
dir(echo.__code__)
X = echo
X('Indirect Call')
Output: Indirect Call

L = [(echo, 'spam!'), (echo, 'ham!')]


for func, arg in L:
func(arg)

Ouput:
spam!
ham!

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Function Annotations
• Definition: An arbitrary user defined data about function's arguments and result
• It is possible to attach function annotation to function object.
• Python does not do anything with function annotation. They are just display purpose.
• It's completely optional to create and attach annotation.
• If annotation available, can see them using __annotations__ attribute of function.

def enjoy(ch, i, d): def enjoy(ch: 'name', i: (1, 10), d: float) -> str:
return ch*i + str(d) return ch*i + str(d)

enjoy('Mahesh', 3, 10.5) enjoy('Mahesh', 3, 10.5)


Ouput: 'MaheshMaheshMahesh10.5' Ouput: 'MaheshMaheshMahesh10.5'

enjoy.__annotations__
Output: {'ch': 'name', 'i': (1, 10), 'd': float, 'return': str}
#Annotations for default values, return multiple values
def enjoy(ch: 'name' = 'Ganesh', i: (1, for arg in enjoy.__annotations__:
10) = 3, d: float) -> tuple[str, float] | print(arg, '=>', enjoy.__annotations__[arg], end='|')
None : Output: ch => name|i => (1, 10)|d => <class 'float'>|return =>
return ch*i + str(d), d**i <class
D. Chaitanya Reddy 'str'>|
(IIT Roorkee Alumni, AI Expert)
Anonymous Functions: lambda
• lambda is an unnamed function and often used to inline a function definition.
• lambda is an expression, not a statement LEGB scope rules applies
here too
• lambda's body is a single expression, not a block of statements.
def knights():
• lambda always return a function object title = 'sir'
action = (lambda x: title + ' ' + x)
• lambda can be nested too. return action
Syntax: act = knights()
lambda arg1, arg2, …, argN: expression using args msg = act('robin')
msg
Ex: Output: sir robin

def func(x, y, z): f = lambda x, y, z: x+y+z


L = [lambda x: x**2, lambda x: x**3, lambda x: x**4]
return x+y+z
f(2, 3, 4)
for f in L:
func(2, 3, 4) Ouput: 9 Args with default values
print(f(2))
Output: 9
Output:
x = lambda a='fee', b='fie', c='foe': a+b+c 4
8
x('wee') D. Chaitanya Reddy (IIT Roorkee Alumni,
16 AI Expert)
Output: weefiefoe
Generator Functions
yield vs return
• Coded as normal def statement that
return generator object def gensquares(N):
Generator Function

• but use yield statement to return for i in range(N):


yield i**2
results one at a time.
• Suspend and resume the their state G = gensquares(5)
G
Generator object
between each result return. Output: <generator object gensquares at 0x000001B65CB7CDD0>
Ex: Create iterable object
Normal Function G = iter(G)
def buildsquares(n): G.__next__(), G.__next__(), G.__next__()
res = []
for i in range(n): Manual
for i in gensquares(5): iterations
res.append(i**2) print(i, end=' : ')
return res
Output: 0 : 1 : 4 : 9 : 16 :
squares = buildsquares(5)
squares Why Generators?
Output: [0, 1, 4, 9, 16]
• Generators are better in terms of memory usage and performance
in larger programs.
• Very useful when result lists are larger or takes lot of computation
to produce each value.
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
next vs send
When generator sending the result, there is an option to share some information back to generator –
using send() def gen():
for i in range(10):
Ex: X = yield i
def gen(): print(X)
for i in range(10):
yield i G = gen()
print('hi') next(G) #it internally calls G.__next__()
Output: 0
G = gen()
G.send(77) next(G)
next(G) #it internally calls G.__next__()
Output: Output:
Output: 0
77 None
1 2
next(G)
Output:
hi G.send(88)
1 Output:
88
next(G) 3
Output:
hi next(G)
2 Output:
None
4
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Generator Expression
• The notions of generators and list comprehensions are combined in a new tool: generator expressions
• Syntactically just like list comprehensions, but enclosed in ().
Ex:
Typical list
L1 = [i**2 for i in range(4)] comprehension line = 'aa bbb c' using list
L1 ''.join([tx for tx in line.split(' ')]) comprehension
Output: [0, 1, 4, 9] Output: 'aabbbc'

Typical generator using generator


G1 = (i**2 for i in range(4)) expression ''.join((tx for tx in line.split(' '))) expression
G1 Output: 'aabbbc'
Output: <generator object <genexpr> at
0x000001E50A9F0740> Generator object
Create iterable object generator expression
G = iter(G1) ''.join(tx for tx in line.split(' ')) parentheses are
G.__next__(), G.__next__(), G.__next__() Output: 'aabbbc' optional often like this.
Manual
iterations
G1 = (i**2 for i in range(4))
list(G1) Automatic iterations
Output: [0, 1, 4, 9]

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Execution Time - timeit
• time.time() import time
start = time.time()
for i in range(10000000):
k = i+1
gets clock time in
end = time.time()
seconds
clock_time = end - start
print(clock_time)
• time.process_time() Output: 1.8710319995880127

import time
start = time.process_time()
for i in range(10000000):
• timeit module k = i+1
gets CPU execution time
end = time.process_time()
in seconds
exe_time = end - start
print(exe_time)

Output: 1.9375
• datetime module
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Execution Time - timeit Namespace which the
stmt code belongs to.
• time.time() import timeit
def addition():
print('addition:', sum(range(100000)))

result = timeit.timeit(stmt='addition()', globals=globals(), number=5)


print(result)

• time.process_time() Output:
addition: 4999950000
addition: 4999950000
addition: 4999950000
Avg time for executing
addition: 4999950000
stmt 5 times
addition: 4999950000
0.03184490000001006 Default runs: 7, default
loop count: 10,000
• timeit module import timeit
%timeit [x for x in range(1000)]

Output: 164.9 µs ± 7.15 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

import timeit
%timeit –r4 –n15 [x for x in range(1000)]
• datetime module
Output: 97.2 µs ± Reddy
D. Chaitanya 3.55(IITµs perAlumni,
Roorkee loopAI(mean
Expert) ± std. dev. of 4 runs, 15 loops each)
Execution Time - timeit
• time.time()

• time.process_time()

import datetime
start = datetime.datetime.now()
for i in range(10000000):
k = i+1
• timeit module
end = datetime.datetime.now()
exe_time = end-start
print(exe_time)

Output:
gets value in time format : HH:MM:SS
0:00:02.004631

• datetime module
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Modules

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Module and Uses
Program Hierarchy Recap…. Multiple modules in a program
• Programs are composed of modules Module
a.py b.py … k.py
• Modules contains statements
myfile.py
• Statements contains expressions
• Expressions create and process objects

Definition: It's just a .py extension file (source file) that contains the some python statements

• Code reuse

• Partitioning / grouping the tools/functionalities

• Sharing services or data


D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Program Structure
Modules
using

• Program contains a top level file (a.k.a Top Level


using
import
b.py import

script) and zero or more supplemental Standard


a.py
files (a.k.a modules). using
import
using
import
library
modules
using
b.py import

import c c.py
def spam(text):
print(text, 'spam') module is not imported any If the module is being
where in the same program and imported by some other
c.py may also imports some other modules of the same
import b modules of the same program. program.

def hello(text):
print('welcome', text)
a.py
import b
b.spam('hi') # prints “hi spam” D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
How import works?
First time import
Save module object into
Find Module file Compile to byte code Run byte code sys.modules

1 2 3 4
Find Compile Run Save

Further import

Fetch the saved module


from sys.modules Run byte code

1 2
Fetch Run

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

How import works – Step-1 (Find) 1 2 3 4

Manual configuration / configuration dependent.

• Using Module Search Path Auto configuration / system dependent.

Running programs
HD (top level script file path)
Home Directory / Current Working Directory.
Working in interactive sessions CWD
PYTHONPATH directories (if set).

"standard library” modules path.


Standard library directories. C:\Program Files (x86)\Python\Python310\Lib
a file with .pth extn, contains the
list of paths (one path per line) Should be present in either
python installation directory (C:\Program Files (x86)\Python\Python310)
Contents of any .pth files (if present). or
“site-packages” directory (C:\Program Files (x86)\Python\Python310\Lib\site-packages)

the “site-packages” sub directory.


site-packages home of third-party extensions. C:\Program Files (x86)\Python\Python310\Lib\site-packages

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

How import works – Step-1 (Find) 1 2 3 4

• All directories in sequence in all 5 components nothing but Module Search Path and saved
in sys.path

• sys.path is a mutable list of directory name strings.

• Python finds module file in the directory listed in the sys.path list from left to right.

• Fetches the first match found and stop search.

• sys.path list can be printed:


import sys
print(sys.path)
Output:
Ex: ['', 'C:\\Program Files (x86)\\Python\\Python310\\Lib\\idlelib', 'C:\\Program
Files (x86)\\Python\\Python310\\python310.zip', 'C:\\Program Files
(x86)\\Python\\Python310\\DLLs', 'C:\\Program Files (x86)\\Python\\Python310\\lib',
'C:\\Program Files (x86)\\Python\\Python310',
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert) 'C:\\Program Files
(x86)\\Python\\Python310\\lib\\site-packages']
Contd…

How import works – Step-1 (Find) 1 2 3 4

• Python exposes sys.path for 2 good reasons:


• Provides the way to verify the search path settings you made – if you don't see your
settings somewhere in this list, you need to recheck your work.

• Some programs really need to change sys.path. Also, sys.path.append or


sys.path.insert often suffice.
Ex: scripts running on webserver by guest user who has limited access to different folder on server.

• If 2 files (with different allowed extensions, ex: b.py, b.so) present in the
different directories of module search path (sys.path), python picks up the first
match found.

• If 2 files (with different allowed extensions, ex: b.py, b.so) present in the same
directory, Python picks up any one randomly.
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…

How import works – Step-2 (Compile) 1 2 3 4

byte code exists already byte code don't exist


.py
file

• Generates the byte code (.pyc file)


• Byte code gets generated in __pycache__
.py & .pyc have folder.
different timestamp
Check
timestamp • __pycache__ folder generates at same folder
where respective .py file exists.
.py & .pyc have • The file name of byte code is in format:
same timestamp
<MODULE_NAME>.<PYTHON_VERSION>.pyc
Do not
generate byte Check .pyc
code & use version .pyc version is different with local python version
existing.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

How import works – Step-3 (Run), Step – 4 (Save)


1 2 3 4

• Simply run the generated byte code (.pyc file)

• Saves the module object in sys.modules table.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Modes of import Python always finds the
respective module file in
Python always finds the The only difference is where Python finds the Same Package Folder of
respective module file in respective module file (STEP-1 : Find). And the rest of the file that contains this
Module Search Path the process (Compile, Run, Save) is the same. import statement.
(sys.path)

Absolute import Relative import


Fetches the module as a
whole. We must qualify Copies all names out
to fetch its names. of the module.
Copies specific names
out of the module.

import statement from statement from * statement from . statement from .. statement

import module1
from module1 import * from . import module1
module1.printer('hi')
print(count, purpose) print(module1.count)
print(module1.count)
printer(getCount()) print(module1.purpose)
val = module1.getCount()
setCount(112) printer(module1.getCount())
. from module1 import printer
. module1.setCount(112)
. printer('hi')
. .
. from .. import module1
. .
. print(module1.count)
. .
. print(module1.purpose)
printer(module1.getCount())
from module1 import printer, count module1.setCount(112)
printer('hi') from .module1 import count, .
print(count) purpose .
printer(count) print(count) .
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert) print(purpose) .
More about import
Import happens only once Reload modules
from importlib import reload
simple.py reload(simple) # load module (run module file) and saves in sys.modules table
print(simple.spam)
print('hello') .
.
spam = 1 .`

First Import

import simple # prints: hello


print(simple.spam) # prints: 1
.
.
imports can be coded/nested in if
. tests, defs, try blocks, etc…
simple.spam = 2 # change attribute in the loaded module object, available in sys.modules
import simple # just fetches from already loaded module, available in sys.modules table.
print(simple.spam) # attribute spam is not reinitialized. if x > 10: def sub(a, b):
print(x) import simple
import simple if a > b:
value = simple.spam return a-b
Second or
Later Import else:
return simple.spam + a - b

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…

More about import


Changing mutables of imported modules Cross module name changes
from small import x, y # copy two names out from small module.
small.py
x = 42 # changes local x only, not the x in small module.

x = 1
y = [1, 2] import small # get module name (from doesn't)
small.x = 42 # changes x in loaded module in sys.modules

from small import x, y # copy two names out from small module.
x = 42
y[0] = 42
# changes local x only.
# changes shared mutable in place
import and from equivalence
from module import name1, name2

Is equivalent to this
statement sequence
import small # get module name (from doesn't)
print(small.x) # prints 1.
print(small.y) # prints [42, 2] import module
name1 = module.name1
name2 = module.name2
del module

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Problems with from import, as extension
Variables with same names in from * statement can corrupt namespaces
importing module will be silently and also difficult to understand imported
overwritten by imported names. names.
M.py N.py Even as extension does not
help here.
def func(): def func():
print('in M Module') print('in N Module') MyModule.py
from moduleA import * # copies all names from moduleA to current module
O.py from moduleB import * # copies all names from moduleB to current module

from M import func from moduleC import * # copies all names from moduleC to current module

from N import func # This overwrites the one we fetched from M


func() # may overwrite and difficult to understand.

func() # calls N.func only!

O.py
import M, N # Get the whole modules, not their names
M.func() # calls func in M module
N.func() # Also, calls func from N module. No overwriting.

O.py O.py
from M import func as mfunc # Rename uniquely with 'as' import M as m # Rename uniquely with 'as'
from N import func as nfunc import N as n # Rename uniquely with 'as'
mfunc(); nfunc() # calls one or the other m.func(); n.func() # calls one or the other
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Module fundamentals
module1.py

count = 100
Module naming also should follow the same
rules outlined for normal variables:
purpose = 'manage count'
✓ Syntax: (underscore or letter) + (any number
of letters, digits or underscores)
def printer(x): ✓ Case sensitive.
print(x) ✓ Reserved words are off-limits.
Only count, printer, getCount, setCount
are attributes (names associated with this
module object (module1)) as they are def getCount():
defined at the top level of this module. return count This file is nothing
but a module.
def setCount(value):
global count But, confirm is not an attribute of
All names of a module can be accessed count = value this module (module1) as this
using __dict__ in built attribute of every function is not defined at top
module object. This always returns a def confirm(): level of this module, rather
dictionary. print('count updated!') nested in another function.

print(list(module1.__dict__.keys()))

O/P: ['__name__', '__doc__', '__package__', D. Chaitanya Reddy (IIT'__spec__',


'__loader__', Roorkee Alumni, AI'__file__',
Expert) '__cached__', '__builtins__', 'count',
'purpose', 'printer', 'getCount', 'setCount']
Module Design Principles
Module Execution Environment
• Every code in python must be in some module.

• Minimize the module coupling – global


variables.

• Modules should rarely change other module's


variables.

• Each module should have a specific purpose and


have that purpose related code.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Data hiding in modules – _X, __all__
_X names shall not imported with from * statement. someother.py
from topper import *
print(a, c)
another.py topper.py Output: 1, 3
from topper import a, _b, c, _d a, _b, c, _d = 1, 2, 3, 4
print(a, _d, c, _b) print(_b)
Output: 1, 4, 3, 2 Output: Name Error: name '_b' is not defined

__all__ is a list contains string names of module. Names present in this list only can be
imported with from * statement.
alls.py someother.py another.py
a, _b, c, _d = 1, 2, 3, 4 from alls import * import alls
__all__ = ['a', '_d'] print(a, _d) print(alls.a, alls._d, alls.c, alls._b)
Output: 1, 4 Output: 1, 4, 3, 2

print(c)
Output: Name Error: name 'c' is not defined

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Module usage modes
• Every module has __name__ built-in attribute.

• If running module as top level program, __name__ set to '__main__'

• If module is being imported, __name__ set to module name.

runme.py someother.py C:\Users\LENOVO>python runme.py


Hi, it a festival today!
def tester(): import runme
print('Hi, it a festival today!') runme.tester()
runme.developer()
def developer():
print('Hello, today is holiday.') Output:
Hi, it a festival today!
if __name__ == '__main__': Hello, today is holiday.
tester()

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Dynamic import
addme.py newmodule.py newmodule.py

name = 'Mahesh' import addme from addme import manage


addme.designer() manage()
def designer():
print('Cool, it's my first day.') Output: Cool, it's my first day. Output: Hey, join us!.

def manage():
print('Hey, join us!.')

Using __import__ built-in function Using importlib module

newmodule.py newmodule.py

mod_name = 'addme' import importlib


mod_obj = __import__(mod_name) mod_name = 'addme'
mod_obj.designer() mod_obj = importlib.import_module(mod_name)
mod_obj.manage()
Output: Cool, it's my first day.
Output: Hey, join us!.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Classes and OOP

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Classes basics, coding classes
mymodule.py someothermodule.py

count = 0 from mymodule import dog

def designer(): puppy = dog() Every Instance inherits (gets access) class
print('Cool, its my first day.') tommy = dog() attributes
tiger = dog()
def manage():
print('Hey, join us!.')
Dog class dog:
A new class 'dog'. This class is
print(tiger)
Output: <mymodule.dog object at 0x000001FB90A5AE30>
also an object of module
name = None print(tiger.name, tiger.color, tiger.breed, tiger.age)
Identified by Behavior Attributes of dog class
color = None Output: None None None 0
breed = None (class attributes)
name eat() age = 0
Accessing Dog class attributes using any
color bark() def eat(self): instance created from Dog class
print('wrote code logic on how to eat.')
methods of dog
breed sleep() def bark(self): class
print('wrote code/logic on how to bark.')
age play() Dog class puppy
def sleep(self, ihours):
print('wrote code/logic on how to sleep.')
- name (None) tommy
def play(self, location): - color (None)
print('wrote code/logic on how to play.') - breed (None)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert) - age (0) tiger
Contd…

Classes basics, coding classes


mymodule.py someothermodule.py

count = 0 import mymodule

def designer(): my_dog = mymodule.dog()


print('Cool, its my first day.') my_dog.set_details('tiger', 'white', 4)

def manage():
print('Hey, join us!.') print(my_dog)
Output: <mymodule.dog object at 0x000001FB90A5AE30>
class dog:
Dog print(my_dog.name, my_dog.color, my_dog.age,
name = None my_dog.breed)
color = None Output: tiger white 4 None
breed = None
Identified by Behavior age = 0 With these assignment to attributes of self, a
name eat() def set_details(self, dname, dcol, dage):
new set of these 3 attributes gets created and
self.name, self.color = dname, dcol
updated to values in instance (instance attributes),
color bark() self.age = dage not the class

breed sleep() def eat(self):


print('wrote code logic on how to eat.')
Dog class
age play() def bark(self): my_dog
print('wrote code/logic on how to bark.') - name (None) name (tiger)
- color (None) color (white)
def sleep(self, ihours): - breed (None) age (4)
print('wrote code/logic on how to sleep.') - age (0)

def play(self, D.location):


Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
print('wrote code/logic on how to play.')
Contd…

Classes basics, coding classes


mymodule.py someothermodule.py

count = 0 from mymodule import dog

def designer(): my_dog = dog('tiger', 'white', 4)


print('Cool, its my first day.')
print(my_dog)
def manage(): Output: <mymodule.dog object at 0x000001FB90A5AE30>
print('Hey, join us!.')
print(my_dog.name, my_dog.color, my_dog.age,
class dog: my_dog.breed)
Dog Output: tiger white 4 None
name = None
color = None
breed = None
Identified by Behavior age = 0 With these assignment to attributes of self, a set
name eat() def __init__(self, dname, dcol, dage):
of these 3 attributes created and updated to values
self.name, self.color = dname, dcol
in instance (instance attributes), not the class
color bark() self.age = dage

breed sleep() def eat(self):


print('wrote code logic on how to eat.')
Dog class
age play() def bark(self): my_dog
print('wrote code/logic on how to bark.') - name (None) name (tiger)
- color (None) color (white)
def sleep(self, ihours): - breed (None) age (4)
print('wrote code/logic on how to sleep.') - age (0)

def play(self, D.location):


Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
print('wrote code/logic on how to play.')
Contd…

Classes basics, coding classes


World's simplest python class
class rec: pass #empty class object.

rec.name = 'Bob' #attribute belongs to class.


rec.age = 40 #attribute belongs to class.

x = rec() #creating instance of class.


y = rec() #and inherits (get access) class attributes

print(x.name, y.name)
Output: Bob Bob

x.name = 'John' #creating new name attribute in instance.


print(rec.name, x.name, y.name)
Output: Bob John Bob

Modules Classes

• Implement data/logic packages • Implement new full featured objects

• Are created with python files (.py files) • Are created with class statements

• Are used by being imported • Are used by being called

• Form the top level in python program • Always live with in module
structure
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…

Classes basics, coding classes


class MyAttrs:
instance attributes class attributes
count = 0
title = 'gives demo on attributes'
• Attributes are generated by assignments to status = 'good' • Attributes created using assignment
self attributes in methods. statements in class.
def __init__(self, number, info):
• Can be accessible by that instance only. self.status = 'checking'
• Can be accessible by using class or any
self.title = info
• Can't be accessible by class and other instances self.display = number instance of the class.
of the same class. MyAttrs.count += 1
• But, can't be updated by using instances of
• If same attribute present in multiple instances the class.
of the class, means, every instance has it's own
copy of the attribute and value.

Summary
• Each class statement generates a new class object

• Each time a class is called, it generates a new instance of the class

• Instances are automatically linked to the classes from which they are created

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…
Classes basics, coding classes
class dog: tom = dog('tommy', 'black', 5, 'No')
tig = dog('tiger', 'grey', 6, 'Yes')
name = None tig.status = 'missing'
color = None
breed = 'Boxer' print(tom.name, tom.breed) Python performs new and
age = 0 Output: tommy Boxer independent search over tree
for each attribute fetch
def __init__(self, dname, dcol, dage, dvac):
self.name, self.color = dname, dcol print(tig.status, tig.breed, tig.vaccinated)
expression.
self.age, self.vaccinated = dage, dvac Output: missing Boxer Yes

def eat(self):
print('wrote code logic on how to eat.') print(tom.name, dog.name)
Attribute search logic: Output: tommy None
1. Accessing using instance
def bark(self):
print('wrote code/logic on how to bark.')
2 Search in Class print(tig.name, dog.age, dog.breed)
def sleep(self, ihours): Output: tiger 0 Boxer
print('wrote code/logic on how to sleep.')
Search logic directly search in
def play(self, location):
print('wrote code/logic on how to play.')
class as we accessing the
1 Search in instance attribute using class name.
tom
Dog class name (tommy) tig
color (black) name (tiger)
- name (None) print(dog.vaccinated)
age (5) color (grey) 2. Accessing using class
- color (None) Output: Error!!!
vaccinated age (6) Instance attributes can't
- breed (Boxer) (No) status (missing)
be accessed by class.
- age (0) vaccinated 1 Search in Class
(Yes)D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…
Classes basics, coding classes
class dog: tom = dog('tommy', 'black', 5, 'No')
name = None
tom.sleep(5) python converts internally to dog.sleep(tom, 5)
color = None
Output: wrote code/logic on how to sleep.
breed = 'Boxer'
age = 0

def __init__(self, dname, dcol, dage, dvac): dog.sleep(tom, 5)


self.name, self.color = dname, dcol Output: wrote code/logic on how to sleep.
self.age, self.vaccinated = dage, dvac

def eat(self): Python provided Class attributes Python provided Instance attributes
print('wrote code logic on how to eat.') dir(dog) dir(tom) tom.__dict__
['__class__', ['__class__', Output: {'name':
def bark(self): '__dict__', '__dict__', 'tommy', 'color':
print('wrote code/logic on how to bark.') . dir shows attributes & . 'black', 'age': 5,
. methods present in . 'vaccinated': 'No'}
def sleep(self, ihours): . class/object also inherited .
print('wrote code/logic on how to sleep.') 'age', 'age',
attributes, methods. __dict__ of an instance
'bark', 'bark',
def play(self, location): 'play', 'play', shows only attributes
print('wrote code/logic on how to play.') 'sleep'] 'sleep' present in that instance
'vaccinated'] only, does not show
• Logically, Methods provides behavior for instance dog.__name__
tom.__class__
attributes present in the
Output: 'dog' instance's class.
objects __main__.dog
dog.__module__
• Technically, methods work same as functions with a Output: mymodule tom.__class__.__name__
difference that, methods first argument always Output: 'dog'
instance object. dog.__dict__
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Output: <check in notebook> tom.__module__
Output: mymodule
Contd…

Classes basics, coding classes


instance methods static methods class methods

• The first argument in method should be • They are simple functions in class • The first argument in method should be
always instance (self) always class object.
• No extra argument required to pass.
• Can be called using instance or class name • By default, can be called using class name
• By default, can be called using class name only. Ex: methods.cmeth(methods, 15)
only.
class methods: • Need to declare it as classmethod if we
need to call it using instance as class
def imeth(self, x): • Need to declare it as static method if method.
print([self, x]) we need to call it using instance too.
• 2 ways to declare method as class
@staticmethod • 2 ways to declare method as static.
def smeth(x):
print([x]) cl_obj = methods()
Function cl_obj.imeth(5)
@classmethod Output: [<__main__.methods object at 0x0000021F2D1640D0>, 5]
def cmeth(cls, x):
decorators If not defined as classmethod,
then, this must be the syntax.
print([cls, x]) methods.imeth(cl_obj, 5)
Output: [<__main__.methods object at 0x0000021F2D1640D0>, 5]
#smeth = staticmethod(smeth) When declared as classmethod, can be
#cmeth = classmethod(cmeth) methods.smeth(7) methods.cmeth(methods, 9) accessible as class method with instance as well
Output: [7] [<class '__main__.methods'>, 9] as class (with syntax change)
If not defined as classmethod, still no
error by accessing it with object. But, python
obj2 = methods() obj3 = methods() will consider it as instance method while
No error only if method is obj2.smeth(7) obj3.cmeth(9)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert) / methdos.cmeth(9) accessing with instance.
declared as staticmethod Output: [7] Output: [<class '__main__.methods'>, 9]
Function decorators
Definition : A sort of runtime declaration about the function that follows. User defined function decorators
Syntax: starts with @ and followed by a class tracer:
class C: function name (meta function)
class C: def __init__(self, func):
@staticmethod Syntax has same effect as self.calls = 0
def meth(x): def meth(x): self.func = func
print([x]) print([x])
def __call__(self, *args):
meth = staticmethod(meth) self.calls += 1
print(self.calls, self.func.__name__)
return self.func(*args)

@tracer #same as spam = tracer(spam)


class D: def spam(a, b, c): means, now spam is a object of tracer.
class D:
return a+b+c
@classmethod Syntax has same effect as
def meth(cls, x): def meth(cls, x):
print([cls.__name__, x]) print([cls.__name__, x])
print(spam(1, 2, 3)) #triggers __call__ method
meth = classmethod(meth) Output: 1 spam

print(spam('a', 'b', 'c'))


Not calling as method, Output: 2 spam
rather calling as attribute.
class AClass:
obj = AClass()
@property Results to obj.meth
def meth(self): Output: AClass
print(self.__class__.__name__)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
OOP – Inheritance
• Definition: it is a capability of one class to derive or inherit the properties from another class

• Inheritance allow us to make changes in derived/inherited classes (also called subclasses), instead of changing existing
classes in place.

• The super classes are listed in parentheses in a class header. Ex: class Secondclass(Firstclass):
class Myclass(Firstclass, Seconclass):

• Subclass inherits (get access) attributes from their super classes

• Instances inherits (get access) attributes from all accessible classes (class tree hierarchy)

• Each object.attribute reference invoke new independent search.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


• Logic changes are made by subclassing, not by changing super classes
Contd…
OOP – Inheritance
Ex1: Ex2: Attribute search logic:
class Employee: 1. Accessing using instance
class FirstClass:
def __init__(self, name, job=None, pay=0):
def setdata(self, value): Search in super Classes
self.name = name 3
self.data = value (starting from left to right)
self.job = job
self.pay = pay
def display(self):
print(self.data)
def lastName(self):
return self.name.split(' ')[-1]
2 Search in Class
class SecondClass(FirstClass):
def giveRaise(self, percent):
def display(self):
self.pay = int(self.pay * (1 + percent))
print('current val =', self.data)
class Manager(Employee):
def giveRaise(self, percent, bonus=0.1):
z = SecondClass()
Employee.giveRaise(self, percent+bonus)
1 Search in instance
z.setdata(42)
print(z.data, z.display())
Output: 42 current val = 42 bob = Employee('Bob Smith')
sue = Employee('Sue Jones', job='dev', pay=100000)
print(bob.name, bob.job, bob.pay, bob.lastName()) 2. Accessing using class
Output: Bob Smith None 0 Smith
print(sue.name, sue.job, sue.pay, sue.lastName()) Search in super Classes
Output: Sue Jones dev 100000 Jones 2 (starting from left to right)
sue.giveRaise(0.1)
print(sue.name, sue.job, sue.pay, sue.lastName())
Output: Sue Jones dev 110000 Jones
tom = Manager('Tom Jones', 'mgr', 50000)
print(tom.name, tom.job, tom.pay, tom.lastName()) 1 Search in Class
Output: Tom Jones mgr 50000 Jones
tom.giveRaise(0.1)
print(tom.name,
D. Chaitanya Reddytom.job,
(IIT Roorkee tom.pay, tom.lastName())
Alumni, AI Expert)
Output: Tom Jones mgr 60000 Jones
Contd…
OOP – Inheritance
Ex3:
tom = Manager('Tom Jones', 50000)
class Employee: print(tom.name, tom.job, tom.pay, tom.lastName())
def __init__(self, name, job=None, pay=0): Output: Tom Jones mgr 50000 Jones
self.name = name
self.job = job tom.giveRaise(0.1)
self.pay = pay print(tom.name, tom.job, tom.pay, tom.lastName())
Output: Tom Jones mgr 60000 Jones
def lastName(self):
return self.name.split(' ')[-1]

def giveRaise(self, percent):


Deep Insights / Summary
self.pay = int(self.pay * (1 + percent))
class Employee:
def lastName(self):
class Manager(Employee): Customized
return self.name.split(' ')[-1]
def __init__(self, name, pay): constructor
def giveRaise(self, percent):
Employee.__init__(self, name, 'mgr', pay) self.pay = int(self.pay * (1 + percent))

def giveRaise(self, percent, bonus=0.1): Class Manager(Employee): # Inherit


Employee.giveRaise(self, percent+bonus) def giveRaise(self, percent, bonus=0.1): # Customize
A sub class
Employee.giveRaise(self, percent+bonus)
def promote(self, new_job): # Extend can…
bob = Employee('Bob Smith')
self.job = new_job
sue = Employee('Sue Jones', job='dev', pay=100000)
self.giveRaise(0.15, 0.05)
print(bob.name, bob.job, bob.pay, bob.lastName())
Output: Bob Smith Smith

print(sue.name, sue.job, sue.pay, sue.lastName())


Output: Sue Jones dev 100000 Jones

sue.giveRaise(0.1)
print(sue.name, sue.job, sue.pay, sue.lastName())
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Output: Sue Jones dev 110000 Jones
Contd…

Ex4:
OOP – Inheritance Ex6:
x = Super() class Super:
class A: x.method()
name = 'Mahesh' def method(self):
Output: in Super.method print('in Super.method') # default behavior
def method(self):
print('I am in method of Class A') def delegate(self):
x = Sub() self.action() # expected to be defined
x.method()
class B: Output:
name = 'Suresh' class Inheritor(Super): pass # inherit methods from Super
starting Sub.method
age = 40 in Super.method
def hello(self, msg): class Replacer(Super): # Replace method completely
ending Sub.method def method(self):
print(msg)
Inheriting Multiple print('in Replacer.method')
class C(A, B): Extender...
super classes
weight = 56.34 starting Extender.method class Extender(Super): # Extend method behavior
def sendoff(self): in Super.method def method(self):
print('Bye ', self.name) ending Extender.method print('starting Extender.method')
Super.method(self)
c = C() print('ending Extender.method')
c.sendoff() x = Provider()
Output: Bye Mahesh x.delegate() class Provider(Super): # Fill in a required method
Output: def action(self):
Ex5: Provider... print('in Provider.action')
in Provider.action
class Super: for klass in (Inheritor, Replacer, Extender):
def method(self): print('\n' + klass.__name__ + '...')
print('in Super.method') klass().method()
Can call super class method
class Sub(Super): output:
using it's class name.
def method(self): Inheritor...
print('starting Sub.method') in Super.method
Super.method(self)
print('ending Sub.method') Replacer...
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
in Replacer.method
Contd…
OOP – Inheritance
Ex7: selftest()

classtree.py output:
def classtree(cls, indent): Tree of <__main__.selftest.<locals>.B object at 0x00000198ECF2E5E0>
print('.'*indent + cls.__name__) ...B
List all classes
for supercls in cls.__bases__: ......A
inherited from
classtree(supercls, indent+3) .........object
Tree of <__main__.selftest.<locals>.F object at 0x00000198ECF2E5E0>
def instancetree(inst): ...F
print('Tree of %s' % inst) ......D
classtree(inst.__class__, 3) .........B
............A
...............object
def selftest(): A .........C
class A: pass ............A
class B(A): pass ...............object
class C(A): pass ......E
class D(B,C): pass .........object
class E: pass
class F(D,E): pass
B C
instancetree(B()) object class is super class for all classes if
instancetree(F()) they are not inherited

D E

F (IIT Roorkee Alumni, AI Expert)


D. Chaitanya Reddy
Contd…
OOP – Inheritance
Abstract class:
class Super:
• Definition: Class that expects part of its def method(self):
behavior to be provided by it's subclasses. print('in Super.method') # default behavior
def delegate(self):
self.action() # expected to be defined
• If an expected method is not defined in a
subclass, python raises an undefined name class Sub(Super):
exception as the search fails. def printer(self):
print('hi, I am good.')
class Super:
x = Super()
def method(self):
x.delegate()
print('in Super.method') # default behavior
Output: AttributeError: 'Super' object has no attribute 'action'
def delegate(self):
self.action() # expected to be defined
y = Sub()
y.delegate()
x = Super()
Ouput: AttributeError: 'Sub' object has no attribute 'action'
x.delegate()
Output: AttributeError: 'Super' object has no
attribute 'action' class Super:
def method(self):
print('in Super.method') # default behavior
def delegate(self):
self.action() # expected to be defined

class Sub(Super):
def action(self):
print('it is fine now.')

y = Sub()
y.delegate()
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Ouput: it is fine now.
OOP – Composition, Aggregation
Definition: a capability of an object nesting in Definition: a capability of an object has list of other objects in it.
another object. class Employee:
def __init__(self, name, job=None, pay=0):
class Employee: self.name = name
def __init__(self, name, job=None, pay=0): self.job = job
self.name = name self.pay = pay
self.job = job def giveRaise(self, percent):
self.pay = pay self.pay = int(self.pay * (1 + percent))

def lastName(self): class Manager(Employee):


return self.name.split(' ')[-1] def __init__(self, name, pay):
Employee.__init__(self, name, 'mgr', pay)
def giveRaise(self, percent): def giveRaise(self, percent, bonus=0.1):
self.pay = int(self.pay * (1 + percent)) Employee.giveRaise(self, percent+bonus)
Embedded a Employee object
class Department: Embedded a list of Employee objects
class Manager: inside Manager object.
def __init__(self, *args): inside Department object.
def __init__(self, name, pay):
self.members = list(args)
self.emp = Employee(name, 'mgr', pay)
def addMember(self, person):
self.members.append(person)
def giveRaise(self, percent, bonus=0.1):
def giveRaise(self, percent):
self.emp.giveRaise(percent+bonus)
for person in self.members:
person.giveRaise(0.1)
x = Manager('Mahesh', 100000)
print(x.emp.name, x.emp.job, x.emp.pay)
Output: Mahesh mgr 100000 bob = Employee('Bob Smith')
sue = Employee('Sue Jones', job='dev', pay=100000)
x.giveRaise(0.1, 0.15) tom = Manager('Tom Jones', 50000)
print(x.emp.pay) development = Department(bob, sue)
Output: 125000 development.addMember(tom)
development.giveRaise(0.1)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
OOP – Polymorphism
Definition: capability that allows us to define methods in the child class with the same name as defined in their parent class.
Which method (from parent or child class) shall be called based on the class from which the object instantiated.

class Employee: bob = Employee('Bob Smith')


def __init__(self, name, job=None, pay=0): sue = Employee('Sue Jones', job='dev', pay=100000)
self.name = name tom = Manager('Tom Jones', 50000)
self.job = job
self.pay = pay for obj in (bob, sue, tom): Which class's giveRaise() method shall be
obj.giveRaise(0.1) called based on the instance's type.
def lastName(self):
return self.name.split(' ')[-1]

def giveRaise(self, percent):


self.pay = int(self.pay * (1 + percent))

class Manager(Employee):
def __init__(self, name, pay):
Employee.__init__(self, name, 'mgr', pay)

def giveRaise(self, percent, bonus=0.1):


Employee.giveRaise(self, percent+bonus)

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Operator Overloading
class Indexer: • Definition: intercepting (or defining meaning) built-in operations in a
data = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
class's methods.
@staticmethod
def get_square(x):
return x**2
• Python automatically invokes these methods when instances of class
x = Indexer() appear in built-in operations.
print(x.data)
Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

print(x.get_square(5))
Output: 25 • Classes can also overload built-in operations such as printing, function
calls, attribute access, etc…
print(x[4]) -- ????
print(x+4) -- ???
print(x-2) -- ???
print(x) -- ???
print(len(x)) -- ??? • Overloading makes class instances act more like built-in types
print(5 in x) -- ???
print(bool(x)) -- ???

• Overloading is implemented by providing specially named methods in


a class.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…
Operator Overloading
class Indexer: L = [5, 6, 7, 8, 9]
data = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
L[0] Output: 5
def __getitem__(self, index): L[3] Output: 8
return self.data[index] L[2] Output: 7

x = Indexer() L[2:4] Output: [7, 8]


print(x[4], x[7]) L[2:] Output: [7, 8, 9]
Output: 16 49

L[2:4] L[slice(2, 4)]


y = Indexer() L[2:] L[slice(2, None)]
print(y[2:5], y[6:]) L[:-1] L[slice(None, -1)]
Output: [4, 9, 16] [36, 49, 64, 81, 100] L[::2] L[slice(None, None, 2)]

Other scenarios where __getitem__() is being called:


print(3 in y, 9 in y) # fallback to __contains__
Output: False True

[n for n in y] # fallback to __contains__

(a, b, c, d) = y # fallback to __iter__ & __next__

list(y), tuple(x) # fallback to __iter__ & __next__

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…
Operator Overloading
class Indexer: class Indexer:
data = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100] data = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

def __getitem__(self, index): def __getitem__(self, index):


return self.data[index] Intercepts + operator if
and only if the instance is return self.data[index]
at left side of the operator.
def __add__(self, value): def __add__(self, value):
return [x+value for x in self.data] Indexer.data = [x+value for x in self.data]
Intercepts – operator if instance return self Intercepts + operator if and only if the instance is
def __sub__(self, value): is at left side of the operator at right side of the operator and left side operator
return [x-value for x in self.data] def __radd__(self, value): is not instance of the class.
x = Indexer() Indexer.data = [x+value for x in self.data]
print(x-2) return self
Output: [-2, -1, 2, 7, 14, 23, 34, 47, 62, 79, 98] Intercepts += operator only. If not defined, calls
def __iadd__(self, value): __add__
print(x+5) Indexer.data = [x+value for x in self.data if x%2==0]
Output: [5, 6, 9, 14, 21, 30, 41, 54, 69, 86, 105] print(self.data)
Needs __radd__ method to intercept return self
print(10+x)
Output: TypeError: unsupported operand type(s) for +: def __sub__(self, value):
'int' and 'Indexer' Indexer.data = [x-value for x in self.data]
return self
Needs __rsub__ method to intercept
print(100-a)
a = Indexer()
Output: unsupported operand type(s) for -: 'int' and
print(10+a)
'Indexer'
Needs __iadd__ method to intercept. If not Output: <__main__.Indexer object at 0x000001439E2EFE50>
defined __add__ will be used to intercept
x += 2; print(x)
print((10+a).data)
Output: [2, 3, 6, 11, 18, 27, 38, 51, 66, 83, 102]
Output: [10, 11, 14, 19, 26, 35, 46, 59, 74, 91, 110]
x, y = Indexer(), Indexer()
a += 2
X += y
print(a.data) Also, try this: a += b
Output: TypeError: unsupported operand type(s) D.for
Chaitanya
+: Reddy (IIT Roorkee Alumni, AI Expert)
Output: [2, 6, 18, 38, 66, 102]
'int' and 'Indexer'
Contd…
Operator Overloading
class Indexer: class Indexer:
data = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100] data = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

x = Indexer() def __contains__(self, value): Intercepts in operator. If not defined,


print(x) __getitem__ used as fallback.
return value in self.data
Output: <__main__.Indexer at 0x27718801d60>
def __bool__(self):
class Indexer: sum = 0
Intercepts bool built-in function, any boolean evaluations
data = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100] for x in self.data:
Intercepts bulit-in print & str sum += x
def __str__(self): functions. return True if sum>200 else False
return 'Indexer with data: %s' % self.data
def __len__(self): return len(self.data) Intercepts len built-in funciton
x = Indexer()
print(x)
Intercepts instance calls
Output: Indexer with data: [0, 1, 4, 9, 16, 25, 36, def __call__(self, *pargs, **kargs):
49, 64, 81, 100] print('Called:' + pargs, kards)
class Indexer:
data = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
k = Indexer()
def __str__(self): print(len(k)) Output: 11
return 'Indexer with data: %s' % self.data if x: print('hi') Output: hi
Intercepts everything except built-in print(5 in x) Output: False
print & str functions. Also, works as
def __repr__(self): fallback if NO __str__ defined m = Indexer() # m is a callable object.
return '[Value: %s]' % self.data m(1, 2, 3)
Output: Called: (1, 2, 3)
>>> import Indexer
>>> x = Indexer() m(1, 2, 3, a=4, b=5)
>>> x Output: Called: (1, 2, 3) {b=5, a=4}
>>> Output: [Value: [0, 1, 4, 9, 16, 25, 36, 49, 64,
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
81, 100]]
Contd…
Operator Overloading

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…
Operator Overloading

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Classes - Special Points
• Every instance is made from a class and type(obj) built-in function class A: pass class A: pass
tells us obj instance is made from which class. class B(A): pass class B: pass
class C(A): pass class C(A): pass
class D(B,C): pass class D(B): pass
• We can also use obj.__class__ to know the class from which the class E: pass class E(C,D): pass
obj instance is made. class F(D,E): pass
Object
Object class
class
O
O
• Every class is also an object (instance). All classes are instantiated
from class type (instances of type class).
class D: pass
A B
print(type(D), D.__class__) A
Output: <class 'type'> <class 'type'>
I = D() Object
class
print(type(I), I.__class__)
Output: <class '__main__.D'> <class '__main__.D'>
B C O C D
• If no super class is mentioned, every class by default, inherits from
object super class though the object class is NOT mentioned as
super class explicitly.
D E E

• Attribute/method search logic in inheritanceD.search shall(IITvary based F


Chaitanya Reddy Roorkee Class
Alumni, AI tree
Expert)
Class tree
on the diamond, non-diamond class trees formed in tree hierarchy.
Contd…
Classes - Special Points
class A: pass class A: pass class A: pass class A: pass
class B(A): pass class B(A): pass class B: pass class B(A): pass
class C: pass class C(B): pass class C(A): pass class C(B): pass
class D(B,C): pass class D(B,C): pass class D(B: pass class D(A): pass

O
O O O

A
A A B A

B
B D
B C C D
C
C
D
D

Class tree Class tree Class


D. Chaitanya Reddy (IIT Roorkee treeAI Expert)
Alumni, Class tree
Inheritance search logic
Recap…. Ex:
Search logic name: MRO
Search Order
Attribute search logic:
(Method Resolution Order) class A: attr=1
1. Accessing using instance class B(A): pass C
Search in super Classes class C(A): attr=3
3 (starting from left to right) class D(B,C): pass
X = D() B
print(X.attr)
2 Search in Class
Output: 3
This inheritance search
logic is applicable only for Object D
Diamond shape class trees class
O
Diamond shape
class tree. MRO
1 Search in instance is applicable.
X
A
2. Accessing using class

Search in super Classes B


2 (starting from left to right)
C

D
1 Search in Class

Class tree
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…
Inheritance search logic
Search logic name: DFLR
Ex: X = E()
Attribute search logic:
1. Accessing using instance
(Depth First Left Right) class A: attr=1 X.attr
Search in super Class class B: attr=2 Output: 1
3 (goes all level up of tree) class C(A): pass
class D(B): attr=4 Search Order

class E(C,D): pass


A
2 Search in Class

This inheritance search


logic is applicable only for Object
Non Diamond shape class class C
trees
O
1 Search in instance

E
2. Accessing using class A B
Non Diamond shape class
Search in super Classes tree. DFLR is applicable.
2 (goes all level up of tree)
X
C D
1 Search in Class

E
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…
Inheritance search logic
Ex:
class A: attr=1 X = F() K = D() print(F.__mro__)
class B(A): pass X.attr K.attr Output:
class C(A): attr=3 Output: 3 Output: 3 (__main__.F,
class D(B,C): pass __main__.D,
class E: attr=5 __main__.B,
Search Order Search Order
class F(D,E): pass __main__.C,
Object __main__.A,
class C C
O __main__.E,
object)

A B B
print(D.__mro__)
Output:
Diamond shape class tree. D D (__main__.D,
B C MRO is applicable.
__main__.B,
__main__.C,
F K __main__.A,
D E object)
Non Diamond shape class
tree. DFLR is applicable.
X
F D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Class tree
Advanced Classes: Pseudo private class attribute
class C1:
def meth1(self): self.X = 88
• Name Mangling: Any attribute or method starts with “__” and not end with “__”
def meth2(self): print(self.X) are automatically expanded to include the name of enclosing class at their front.
class C2:
def metha(self): self.X = 99 class spam:
def methb(self): print(self.X) __X = 88

class C3(C1, C2): I = spam()


def __init__(self): self.X = 111 print(I.__X)
Output: AttributeError: 'spam' object has no attribute '__X'

I = C3() print(I._spam__X)
print(I.X) Output: 88
Output: 111

I.meth1() • Name mangling happens only for names (attributes/methods) appear inside a
print(I.X) class statement's code.
Output: 88

I.metha() • Name mangling is applicable for both class attributes and method and instance
print(I.X) attributes which are prefixed with “__”
Output: 99
• These mangled names sometimes misleadingly called as private attributes. But,
they are really not private attributes. Hence, named as Pseudo private attributes.
• There is no restriction for other classes to access these attributes and hence
these are not really private attributes.
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
• The purpose of these mangled attributes is to avoid attribute name collisions
Contd…
Advanced Classes: Pseudo private class attribute
class C1:
def set_value(self, val): self.__X = val
def get_value(self): return self.__X
Mangled names are NOT required use to
class C2: access the attributes inside the class's
def set_info(self, info): self.__X = info statement.
def get_info(self): return self.__X

class C3(C1, C2):


def __init__(self): self.__X = 111

I = C3()
I._C1__X = 25
I._C2__X = 42 One way of accessing the pseudo private
Mangled names are required to access the attributes from outside of the class.
attributes outside the class's statement.

print(I._C1__X, I._C2__X, I._C3__X)


Output: 25, 42, 111

J = C3()
J.set_value(55)
J.set_info(10)
Other way of accessing the pseudo private
attributes from outside of the class. Encapsulation
print(J.get_value(), J.get_info())
Output: 55, 10
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Advanced Classes: Attribute namespaces, Slots
Attribute Namespaces: __dict__ Slots: Technique that allows us to assign a sequence/list of
class limiter:
Attribute name space attribute names (in string format) to a special __slots__
min_age = 34
Class attributes
class attribute in order to limit and fix the attributes
count_limit = 100 present in every instance of class.
max_age = 72
Every instance of limiter class must have only 3 attribute with
def __init__(self, username, designation): these names in it with no default values assigned.
Ex:
self.name = username But, limiter class allows
self.job = designation Instance attributes attributes (class attributes)
class limiter:
__slots__ = ['age', 'name', 'job'] with any names.
print(limiter.__dict__) Shows list of all class attributes (both user defined and
Output: python default provided def __init__(self, username, designation):
{'__module__': '__main__', 'min_age': 34, 'count_limit': 100, self.name = username
'max_age': 72, '__init__': <function limiter.__init__ at self.job = designation
0x0000019AD7DDA040>, '__dict__': <attribute '__dict__' of
'limiter' objects>, '__weakref__': <attribute '__weakref__' of
x = limiter('mahesh', 'developer')
'limiter' objects>, '__doc__': None}
print(x.name, x.job)
Output: mahesh developer
Shows list of all x instance attributes
x = limiter('mahesh', 'developer') Instance attribute must also assigned with some value
print(x.__dict__) print(x.age) before being used/referenced.
Output: {'name': 'mahesh', 'job': 'developer'} AttributeError : age
Another Instance attribute.
y = limiter('david', 'manager') Shows list of all y instance attributes x.age = 40
print(y.__dict__) print(x.age)
Output: {'name': 'david', 'job': 'manager'} Output: 40
Instance can’t have any attribute apart from defined slot
attributes: age, name, job.
x.city
D. Chaitanya Reddy (IIT Roorkee = Expert)
Alumni, AI 'Mumbai'
Attribute Error: 'limiter' object has no attribute 'city'.
Contd…
Advanced Classes: Attribute namespaces, Slots
class slotful: class slotdic:
__slots__ = ['age', 'name', 'job'] __slots__ = ['age', 'name', 'job', '__dict__']
lmt = 120 lmt = 120
ret_age = 75 ret_age = 75

def __init__(self, username, designation): def __init__(self, username, designation):


self.name = username self.name = username
self.job = designation self.job = designation
self.country = 'india'
print(slotful.__dict__)
Output: print(slotdic.__dict__)
{'__module__': '__main__', '__slots__': ['age', 'name', 'job'], Output:
'lmt': 120, 'ret_age': 75, '__init__': <function {'__module__': '__main__', '__slots__': ['age', 'name', 'job',
slotful.__init__ at 0x0000019AD98B28B0>, 'age': <member 'age' '__dict__'], 'lmt': 120, 'ret_age': 75, '__init__': <function
of 'slotful' objects>, 'job': <member 'job' of 'slotful' slotdic.__init__ at 0x0000019AD98FE5E0>, 'age': <member 'age'
objects>, 'name': <member 'name' of 'slotful' objects>, of 'slotdic' objects>, 'job': <member 'job' of 'slotdic'
'__doc__': None} objects>, 'name': <member 'name' of 'slotdic' objects>,
Class that contains __slots__ can not '__dict__': <attribute '__dict__' of 'slotdic' objects>,
x = slotful('suresh', 'tester') have attribute namespace (__dict__) by '__doc__': None}
print(x.__dict__) default.
Output: AttributeError: 'slotful' object has no attribute z = slotdic('naresh', 'team leader’)
'__dict__' print(z.__dict__)
Output: {'country': 'india'}
print(slotful.__slots__)
Output: ['age', 'name', 'job'] print(slotdic.__slots__)
Output: ['age', 'name', 'job', '__dict__']

print(x.__slots__)
Output: ['age', 'name', 'job'] print(z.__slots__)
Output: ['age', 'name', 'job', '__dict__']
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…
Advanced Classes: Attribute namespaces, Slots
class E: Slots Usage Rules
__slots__ = ['age', 'name']
• Slots in sub classes are meaningless when absent in its super
class D(E): classes.
__slots__ = ['job', '__dict__']
class C: pass
class D(C): __slots__ = ['a']
X = D()
X.age = 45; X.name='Ramesh'; X.job = 'anchor'
X = D()
X.a = 1; X.b = 2
print(E.__dict__) print(X.__dict__)
Output: {'__module__': '__main__', '__slots__': ['age', Output: {'b': 2}
'name'], 'age': <member 'age' of 'E' objects>, 'name':
<member 'name' of 'E' objects>, '__doc__': None}

print(D.__dict__) • Slots in super classes are meaningless when absent in its sub
Output: {'__module__': '__main__', '__slots__': ['job', classes
'__dict__'], 'job': <member 'job' of 'D' objects>,
'__dict__': <attribute '__dict__' of 'D' objects>, class C: __slots__ = ['a']
'__doc__': None} class D(C): pass

print(X.__dict__) X = D()
Output: {'age': 45, 'name': 'Ramesh', 'job': 'anchor'} X.a = 1; X.b = 2
print(X.__dict__)
Output: {'b': 2}
print(E.__slots__)
Output: ['age', 'name']

print(D.__slots__) or print(X.__slots__)
Output: ['job', '__dict__'] D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…
Advanced Classes: Attribute namespaces, Slots
Slots Usage Rules Benefits of Slots
• Overriding Slots in sub classes makes super classes slots • Python reserves just enough space in each instance to
meaningless. hold a value for each slot attribute along with
class C: __slots__ = ['a'] inherited attributes in the super class.
class D(C): __slots__ = ['a']

X = D()
X.a = 1
print(X.__slots__) • Helps python to mange the memory very effectively.
Output: ['a']

• Speeds up the code execution.


• Slots prevents/conflicts class attributes.
class C:
__slots__ = ['a'] Error: 'a' in __slots__ conflicts with
a = 99 class variable
• Best suited for scenarios where large number of
instances with only few attributes to be created.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Advanced Classes : super()
class C:
Calling super class’s method class A: With multiple super classes
def act(self): def act(self): print('A')
print('spam') class B:
def act(self): print('B')
class D(C): class C(A, B):
def act(self): Syntax to call super class’s method using super class def act(self):
C.act(self) super().act() Which super class’s act() method will be called?
name.
print('eggs') print('C')
Need to pass self as calling super method with class
name.
X = D() X = C() Rule: Python always picks the left most super
X.act() X.act() class having that method. Technically, the 1st class
Output: Output: in MRO search having that method.
spam A
eggs C

class C: class A: Best Practice:


def act(self): def act(self): print('A')
print('spam') class B: 1) If the class have only single super
def act(self): print('B') class and no multiple super classes
class D(C): class C(A, B):
def act(self): Syntax to call super class’s method using super() def act(self):
comes in future too, user super()
super().act()
No need to pass self, because method is being B.act(self) to call super class methods.
print('eggs') print('C')
called with magical proxy super class object.

X = D()
2) If the class have multiple super
X = C()
X.act() X.act() classes, always use class names to
Output: Output: call specific super class method.
spam B
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
eggs C
Exceptions

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Exceptions Default Exception Handler

• If any error found while running def fetcher(obj, index):


return obj[index]
fetcher(x, 4)
Output:
code, python triggers that error as x = 'spam'
IndexError
Traceback (most recent call last)
exception. fetcher(x, 3)
Output: 'm'
Input In [2], in <cell line: 2>()
1 x = 'spam'
----> 2 fetcher(x, 4)

Input In [1], in fetcher(obj, index)


• The triggered exception can be 1 def fetcher(obj, index):
----> 2 return obj[index]
intercepted/caught by code.
IndexError: string index out of range

def fetcher(obj, index):


return obj[index]

x = 'spam'
try:
fetcher(x, 4)
except IndexError:
print('got Index err')

Output: got Index err

Own exception handler


D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Contd…
Exceptions
try statement syntax
try block which contains the A try block can associate with either with zero or one or
try: code which may causes some multiple exception handlers (except block).
errors while running it.
statement(s) # run this main action first Can't exists without associated try
except name1: # catch a specific exception only. if a single except block is present, python checks
whether the except block handles the raised exception
statement(s) # run if name1 is raised during try block or not.
except (name2, name3): # catch any of the listed exceptions If multiple except blocks are present, python finds the
first matching except block to handle the exception and
statement(s) # run if any of these exceptions occurs
the further except blocks are ignored.
except name4 as var: # catch a specific exception and assign it's instance
default except: must be always at last in except block.
statement(s) # run if name4 is raised, assign instance raised to var
except (name5, name6) as var: # catch any of the listed exceptions and assign it's instance
Can have zero or one else block
statement(s) # run if any of these exception occurs, assign instance raised to var
Can't exists without at least one exception handler
except: # catch all (or all other) exceptions
Can have optional else block if at least one exception handler
statement(s) # run for all other exceptions raised exists.

else: Code in else block shall execute if and only if no exception


raised in try block code.
statement(s) # run if no exception was raised during try block
finally: Can have zero or one finally block

statement(s) # always run this code in any case. Must exists if try does not have at least one exception handler.
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Can be optional if try have at least one exception handler.
Contd…
Exceptions
Ex:
def action(x, y):
print(x + y)

try:
action([1, 2, 3], 6)
except NameError:
print('got Name Error')
Output:
except TypeError as err:
got Type Error.
print('got Type Error.')
taking care of clean up code here
except:
After the try statement.
print('got some different error')
else:
print('No Error found.')
finally:
print('taking care of clean up code here')
print('After the try statement.')

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Exceptions – try statement formats
Possible-1 Possible-3 Possible-5 Possible-7
try: try: try: try:
statement(s) statement(s) statement(s) statement(s)
except: except name1: except name1: except (name5, name6) as var:
statement(s) statement(s) statement(s) statement(s)
else: else: finally:
Possible-2 statement(s) statement(s) statement(s)
try: finally:
statement(s) Possible-4 statement(s) Possible-8
except name1: try: try:

statement(s) statement(s) Possible-6 statement(s)


except (name2, name3): try: except (name5, name6) as var:
except (name2, name3):
statement(s) statement(s) statement(s)
statement(s)
except name4 as var: finally: except Exception:
except name4 as var:
statement(s) statement(s) statement(s)
statement(s)
except (name5, name6) as var: except name1: except:

statement(s) statement(s) statements(s)

except: else: finally:


D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
statement(s) statement(s) statement(s)
Contd…
Exceptions – try statement formats
Possible-9 Try statement can be nested in Possible-10
try: try:
statement(s) • try block try: statement(s)
except (name5, name6) as var:
statement(s)
• all of the except block(s), except: statement(s)
except (name5, name6) as var:
except name1: • else block, try: statement(s)
statement(s) except: statement(s)
except (name2, name3):
• finally block else: statement(s)
statement(s) else:
except name4 as var: try: statement(s)
statement(s) except: statement(s)
else: else: statement(s)
statement(s) finally: statement(s)
finally: finally:
statement(s) try: statement(s)
except: statement(s)
finally: statement(s)
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
Flow passing
without Exception Exceptions – code flow
Flow passing
with Exception
Flow passing
With/Without if NO exception Skip the rest of
try block if exception
Exception occurred
occurred the code in try
code
block
else
No Yes
block at least one
exists? No
except block
Execute else exists?
block code
Yes

matching
No
except block
The finally block gets executed always: No
finally found?
block Yes
1) Exception occurred and handled
exists?
2) Exception occurred and not handled Execute matched
Yes except block code
3) No exception occurred.
Execute finally to terminate the
4) New exception triggered in except
blocks/else blocks if present. block code raised exception
End of the try Skip the rest of the code after try
statement. Starts statement and the unterminated
No Exception Yes
executing code after exception propagated to caller
exists? D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
the try statement. code/top level code.
Exceptions – Examples
Ex1:
def action(x, y):
print(x + y)

try:
print('try block starting...')
action([1, 2, 3], 6)
print('try block ending...')
Output:
except NameError: print('got Name Error')
try block starting...
except (IndexError, KeyError):
got Type or ZeroDivError.
print('got Index or key error')
taking care of clean up code here
except AttributeError as var:
After the try statement.
print('got Attr Error:', var)
except (TypeError, ZeroDivisionError) as err:
print('got Type or ZeroDivError.')
except: print('got some different error')
else: print('No Error found.')
finally:
print('taking care of clean up code here')

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


print('After the try statement.')
Contd…
Exceptions – Examples
Ex2:
def action(x, y): Output:
try: try block starting...
print('try block starting...') taking care of clean up code here
print(x + y) -------------------------------------------------------------------
print('try block ending...') TypeError Traceback (most recent call last)
except NameError: print('got Name Error') Input In [9], in <cell line: 4>()
except (IndexError, KeyError): 4 try:
print('got Index or key error') 5 print('try block starting...')
except AttributeError as var: ----> 6 action([1, 2, 3], 6)
print('got Attr Error:', var) 7 print('try block ending...')
except (OverflowError, ZeroDivisionError) as err: 8 except NameError: print('got Name Error')
print('got Type or ZeroDivError.')
else: print('No Error found.') Input In [9], in action(x, y)
finally: 1 def action(x, y):
print('taking care of clean up code here') ----> 2 print(x + y)

print('After the try statement.') TypeError: can only concatenate list (not "int") to list

action([1, 2, 3], 6) D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


except block matching process
Ex2: 1
def action(x, y):
2
This line in try block causes Create a new instance for TypeError class and
try: TypeError and reason for pass that new instance to variable present in as
print('try block starting...') TypeError is can only clause in except block.
concatenate list (not "int") to
print(x + y) list X = TypeError('can only concatenate
print('try block ending...')
list (not "int") to list')

except NameError: exception class mentioned in except block raise X


print('got Name Error') must be either same as error instance's class
or super class of error instance's class.

except AttributeError as var:


This is called implicit exception raising:
print('got Attr Error:', var) 1) Python internally choose the right exception class to raise.
2) Python internally creates an instance for exception class.
except (IndexError, KeyError):
print('got Index or key error')

except (OverflowError, TypeError) as err:


print('got Type or ZeroDivError.') Output:
finally: print('all clean up code here') try block starting...
print('After the try statement.') got Type or ZeroDivError.
all clean up code here
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
action([1, 2, 3], 6) After the try statement.
Exceptions – raise statement
def action(x, y): def action(x, y): raise statement is used to raise
try: try: exceptions explicitly.
We explicitly should check the
print(x + y) if isinstance(x, str):
potential failure condition
except (AttributeError) as err: raise TypeError('Trying to add wrong types. please fix it.')
print('got Type Error.') else: print(x + y) Should explicitly
raise the exception. Should explicitly
finally: print('all clean up code here') except (AttributeError) as err:
give some more
print('After the try statement.') print('got Type Error.') meaningful error
finally: print('taking care of clean up code here') messasge
action('mahesh', 4)
action('mahesh', 4)

Output: Output:
all clean up code here taking care of clean up code here
---------------------------------------------------- -----------------------------------------------------------------
TypeError Traceback (most recent call last) TypeError Traceback (most recent call last)
Input In [12], in <cell line: 1>() Input In [14], in <cell line: 1>()
----> 1 action('mahesh', 4) This is implicit exception ----> 1 action('mahesh', 4)
and we do not have any
Input In [11], in action(x, y) control on the message in Input In [13], in action(x, y)
1 def action(x, y): implicit exceptions. 1 def action(x, y):
2 try: 2 try:
----> 3 print(x + y) ----> 3 if isinstance(x, str): raise TypeError('you are tyring to
4 except (AttributeError) as err: add wrong types. please fix it.') This exception raised
5 print('got Type Error.') 4 else: print(x + y) explicitly and hence have
5 except (AttributeError) as err: full control on the message.
TypeError: can only concatenate str (not "int") to str
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
TypeError: you are tyring to add wrong types. please fix it.
Contd…
Exceptions – raise statement
Output:
class MyExc(Exception): pass
taking care of clean up code here
def action(x, y): ---------------------------------------------------------------
MyExc Traceback (most recent call last)
try: We can raise exception Input In [18], in <cell line: 11>()
belongs to any exception 8 print('got Type Error.')
if isinstance(x, str): class. 9 finally: print('taking care of clean up code here')
raise MyExc('Error found. Fix it.') ---> 11 action('mahesh', 4)
else: print(x + y)
Input In [18], in action(x, y)
except (AttributeError) as err: 3 try:
4 if isinstance(x, str):
print('got Type Error.') ----> 5 raise MyExc(Error found. Fix it.')
finally: print('taking care of clean up code here') 6 else: print(x + y)
7 except (AttributeError) as err:

MyExc: Error found. Fix it.


action('mahesh', 4)

This exception raised explicitly and


hence have full control on the type
of exception too.

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


raise statement forms
class MyExc(Exception): pass class MyExc(Exception): pass
Form-1: raise statement followed by instance Form-1 (alternate): raise
of some exception class. statement followed by instance of
def action(x, y): def action(x, y): some exception class.
try: Here, instance is created within the raise try:
statement. Here, instance is created before the
if isinstance(x, str): if isinstance(x, str): raise statement.

raise MyExc(Error found. Fix it.') exc = MyExc(Error found. Fix it.')
else: print(x + y) raise exc
except MyExc as err: else: print(x + y)
print('got Type Error.') except MyExc as err:
finally: print('all clean up code here') print('got Type Error.')
finally: print('all clean up code here')
action('mahesh', 4)
action('mahesh', 4)
Output:
got Type Error. Output:
all clean up code here got Type Error.
all clean up code here

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Contd…
raise statement forms
Form-2: raise statement followed by
def action(x, y): name of some exception class. def action(x, y):
try: try:
Here, No instance for any exception
if isinstance(x, str): class gets created. if isinstance(x, str):
raise TypeError raise TypeError('spam')
However, python creates instance for
else: print(x + y) the exception class with empty error else: print(x + y)
message.
except AttributeError as err: except TypeError as err:
print('got Attribute Error.') print('propagating Type Error')
finally: print('all clean up code here') raise
Form-3: simple raise statement.
action('mahesh', 4)
It will re raise the most recent exception
Output: action('mahesh', 4)
all clean up code here Output:
--------------------------------------------------- propagating Type Error
TypeError Traceback (most recent call last) -----------------------------------------------------
Input In [25], in <cell line: 10>() TypeError Traceback (most recent call last)
7 print('got Attribute Error.') Input In [26], in <cell line: 12>()
8 finally: print('all clean up code here') 9 print('propagating Type Error')
---> 10 action('mahesh', 4) 10 raise
---> 12 action('mahesh', 4)
Input In [25], in action(x, y)
2 try: Input In [26], in action(x, y)
3 if isinstance(x, str): 4 try:
----> 4 raise TypeError 5 if isinstance(x, str):
5 else: print(x + y) ----> 6 raise TypeError('spam')
6 except AttributeError as err: 7 else: print(x + y)
8 except TypeError as err:
TypeError: D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
TypeError: spam
raise statement – multiple args
Multiple values can be passed while
raising exception.
class MyExc(Exception): pass def action(x, y):
def action(x, y): try:
Built-in Exception class
Custom/own Exception class
try: if isinstance(x, str):
if x < 0: raise MyExc('negative number', x, 'addition') raise TypeError('not a number', x, 'addition')
else: print(x + y) else: print(x + y)
except MyExc as ex: except Exception as ex:
print(ex.args) All these multiple values are saved in args print(ex.args) All these multiple values are saved in args
attribute of error instance as tuple. attribute of error instance as tuple.
print(ex.args[0], ex.args[1]) print(ex.args[1], ex.args[2])

action(-2, 4) action('mahesh', 4)

Output: Output:
('negative number', -2, 'addition') ('not a number', 'mahesh', 'addition')
negative number -2 mahesh addition

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


raise from statement
class MyExc(Exception): pass Output:
propagating Type Error.
all clean up code here
def action(x, y): Explicit Exception Chaining --------------------------------------------------------------
TypeError Traceback (most recent call last)
try: Input In [28], in action(x, y)
4 try:
print(x + y) ----> 5 print(x + y)
except TypeError as err: 6 except TypeError as err:

print('propagating Type Error.') TypeError: can only concatenate str (not "int") to str
raise MyExc('Bad Types') from err
The above exception was the direct cause of the following exception:
finally: print('all clean up code here')
MyExc Traceback (most recent call last)
Input In [28], in <cell line: 11>()
action('mahesh', 4) 8 raise MyExc('Bad Types') from err
9 finally: print('all clean up code here')
---> 11 action('mahesh', 4)

Raising a new exception from another Input In [28], in action(x, y)


exception which is called exception 6 except TypeError as err:
chaining. 7 print('propagating Type Error.')
----> 8 raise MyExc('Bad Types') from err
9 finally: print('all clean up code here')
Since, we are explicitly raising new
exception from another exception, this is MyExc: Bad Types
called explicit exception chaining

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)


Implicit Exception Chaining
def action(x, y): propagating Type Error.
all clean up code here
try: -------------------------------------------------------------
print(x + y) Implicit Exception Chaining TypeError Traceback (most recent call last)
Input In [29], in action(x, y)
except TypeError as err: 2 try:
----> 3 print(x + y)
print('propagating Type Error.') 4 except TypeError as err:
cnt = len(x)
TypeError: can only concatenate str (not "int") to str
cnt -= 6
res = 100/cnt During handling of the above exception, another exception occurred:

finally: print('all clean up code here') ZeroDivisionError Traceback (most recent call last)
Input In [29], in <cell line: 11>()
8 res = 100/cnt
action('mahesh', 4) 9 finally: print('all clean up code here')
---> 11 action('mahesh', 4)

Input In [29], in action(x, y)


Python automatically, raises a new 6 cnt = len(x)
exception while terminating the previous 7 cnt -= 6
exception. ----> 8 res = 100/cnt
9 finally: print('all clean up code here')
Since, python automatically raising new
ZeroDivisionError: division by zero
exception while handling another
exception, this is called implicit exception
chaining
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
assert statement
assert statement is nothing but conditional raise assert is mostly intended for trapping user-defined
statement. constraints, not for catching genuine programming errors.
class MyExc(Exception): pass
This is not a programming error. Syntax: assert test, data data is an optional
def action(x, y): Raising exception based on user
try: defined constraint.
def action(x, y):
if x < 0: raise MyExc('negative number') try: 1) Evaluates the test
else: print(x + y) condition (x>0).
assert x>0, 'negative number'
2) If False, then raises always
except TypeError as err: print(x + y) AssertionError.
print('propagating Type Error') except TypeError as err:
action(-2, 4) print('propagating Type Error')
Output: action(-2, 4)
-----------------------------------------------------
Output:
MyExc Traceback (most recent call last)
---------------------------------------------------
Input In [7], in <cell line: 9>()
AssertionError Traceback (most recent call last)
6 except TypeError as err:
Input In [14], in <cell line: 8>()
7 print('propagating Type Error')
6 print('propagating Type Error')
----> 9 action(-2, 4)
----> 8 action(-2, 4)
Input In [7], in action(x, y)
Input In [14], in action(x, y)
2 def action(x, y):
1 def action(x, y):
3 try:
2 try:
----> 4 if x < 0: raise MyExc('negative number')
----> 3 assert x>0, 'negative number'
5 else: print(x + y)
4 print(x + y)
6 except TypeError as err:
5 except TypeError as err:
MyExc: negative number D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
AssertionError: negative number
Built-in Exception Classes
Default super class for
any class. 1. Super class for every built-in exception classes except
object system exit events (SystemExit,
1. Top level root superclass of exceptions. KeyboardInterrupt, GeneratorExit)
2. Conventionally, not supposed to be directly 2. Conventionally, used to be inherited by all user defined
inherited by user defined exception classes. exception classes.
3. Constructor (__init__) and printing BaseException
(__str__) behavior is defined.

Exception

Superclass for all numeric errors Superclass for all indexing errors
for both sequences, mappings

ArithmeticError LookupError ...


Overflow
Error
Index
Error
ZeroDivision
Error ... Key
Error
FloatingPoint
Error
...
D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)
END

D. Chaitanya Reddy (IIT Roorkee Alumni, AI Expert)

You might also like