0% found this document useful (0 votes)
16 views167 pages

Python Identifiers and Data Types Guide

Uploaded by

kumargpc7
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views167 pages

Python Identifiers and Data Types Guide

Uploaded by

kumargpc7
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Identifiers:

==========
-->A name in the python program is called as identifiers.
-->It can be a class name or function or module name or variable name.
Ex:
x = 10
def f():
class Test:

Rules to define identifiers in python:


[Link](a-z/A-Z)
[Link](0-9)
[Link](_)

IDLE:Integrated Development and Learning Environment

Ex:
cash = 100 #Valid
cas$h = 100 #Invalid

-->Identifier should not start with digit.


total123 = 100 #valid
123total = 100 #invalid

-->Identifiers are case sensitive:


total = 100
TOTAL = 300

Note:
--------
[Link] is no length limit for python identifiers. But not recommended to
use too lengthy identifiers.
[Link]($) symbol is not valid in python.
[Link] identifiers with underscor(_) then it indicates as protected.
[Link] an identifiers starts with two underscores(__) then it is private.
[Link] can't use reserved word as identifiers.

Reserved words/keywords
----------------------------------------
>>>import keyword
>>>[Link]

['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await',


'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except',
'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda',
'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while',
'with', 'yield']

[Link] any method before and after two underscores( ) then those methods
are known as magic methods.
Ex:
add (),__sub (),__mul__()..................

Data Types:
==========
[Link] DT's:statically typed programming language
int a;
float b;
string c;
-->C,C++,Java,.net languages supports static data types.
[Link] DT's:dynamically typed programming language
x = 10==>int
y = 10.0==>float
z = '10'==>str
-->Python and java script supports dynamic data types.

Python data types:


[Link] DT's:
int,float,bool,complex,str

[Link] DT's:
bytes,bytearray,list,tuple,set,range,frozenset,dict,None

22/10/24
--------------
Python & Full Stack Python @ 6:00 PM (IST) by [Link]
Day-1 [Link]
Day-2 [Link]
Day-3 [Link]
Day-4 [Link]

Data Types:
[Link] DT's:statically typed programming language
int a,
float b;
string c;
C,C++,Java, .Net are supports static DT's

[Link] DT's:dynamically typed programming language


x = 10==>int
y = 1.0==>float
z = 'sunny'==>str
Python and Javascript supports dynamic DT's

Python data types:


[Link] DT's:
int,float,bool,complex,str

[Link] DT's:
bytes,bytearray,list,tuple,range,set,frozenset,dict,None

[Link] data type:


We can use int data type to represent whole numbers(integral
values)
Ex:
a = 10
type(a)

We can represent int values in 4-ways.


[Link] Form
[Link] Form
[Link] Form
[Link] Decimal Form

1).Decimal Form(Base-10):
---------------------------------------
It is the default number system in python
The allowed digits are:0 to 9
Ex:
x = 100

2).Binary Form(Base-2):
-----------------------------------
The allowed digits are:0 & 1
Literal value should be prefixed with 0b or 0B.
Ex:
a = 0b1010 #Valid
a = 0B1010 #Valid
a = 0b123 #Invalid

3).Octol Form(Base-8):
----------------------------------
The allowed digits are:0 to 7
Literal value should be prefixed with 0o or 0O.
Ex:
a = 0o10
a = 0O10
a = 0o786 #Invalid

4).Hexa Decimal Form(Base-16):


------------------------------------------------
The allowed digits are:0 to 9,a-f/A-F
Literal value should be prefixed with 0x or 0X.
Ex:
a = 0XFACE
a = 0xBeef
a = 0XBeer #Invalid

Note:
Being a programmer we can specify literal values in decimal,
binary, octol and hexa decimal forms, but PVM will always provide values
in decimal form
Ex:
a = 10
b = 0b10
c = 0o10
d = 0x10
a #10
b #2
c #8
d #16

Base Conversions
--------------------------
bin(),oct(),hex()

bin(10)#'0b1010'
oct(10)#'0o12'
hex(10)#'0xa'
hex(20)#'0x14'

[Link] data type:


--------------------------
To represent floating point values(decimal values)

f = 1.234
type(f) #<class 'float'>
-->We can also represent floating point values by using exponential
form(Scintific notation)
Ex:
f = 1.2e3
print(f)#1200.0

Note:Instead of 'e' we can use 'E'


Ex:
f = 1.2E3
-->The main advantage of exponential form is we can represent big values
in less memory.

[Link] data type:


Acomplex is the form of
a + bj
a-->Real part
b-->Imaginary part
j--->sqrt(-1)
-->a & b contains integers or floating point values.
-->In the real part if we use int values then we can specify that either
by decimal, octol binary or hexa decimal form.
-->But imaginary part should be specified only by using decimal form.

Ex:
a = 3 + 4j
a = 1.5 + 2.5j
a = 3 + 0b1010j #Invalid
a = 0b1010 + 3j
Ex:
c = 10.5 + 3.6j
[Link] #10.5
[Link] #3.6

4).bool data type:


The only allowed values are:True and False
Ex:
10 < 20 #True
10 > 20 #False

-->Internally python represents True as 1 and False as 0.


>>>True + True #2
>>>True - False #1

23/10/24
---------------
Python & Full Stack Python @ 6:00 PM (IST) by [Link]
Day-1 [Link]
Day-2 [Link]
Day-3 [Link]
Day-4 [Link]
Day-5 [Link]

Python Data Types:


------------------------------
[Link] DT's:
int,float,bool,complex,str

[Link] DT's:
bytes,bytearray,list,tuple,range,set,frozenset,dict,None
[Link] data type:
a = 10
-->Decimal Form:Base-10; 0 to 9
-->Binary Form:Base-2; 0 & 1; 0b/0B
-->Octol Form:Base-8; 0 to 7; 0o/0O
-->Hexa Decimal Form:Base-16; 0-9, a-f/A-F; 0x/0X

Base conversion:
bin(), oct(), hex()

[Link] data type:


f = 1.234
f = 1.2e3
f = 1.2E3

[Link] data type:


a + bj

[Link] data type:


True and False
True==>1
False==>0

[Link] data type:


-----------------------
-->str represents String data type.
-->A string is a sequence of characters within the single quotes or
double quotes or triple quotes.
Ex:
s = 'sunny'
s = "sunny"
s = '''sunny'''
s = """sunny"""

Slicing of string:
-------------------------
-->Slice means a piece.
-->[:] is called as slice operator, whuch can be used to retrieve parts
of string.
-->In python string follows zero based index.
-->The index can be either +ve or -ve.
-->+ve index means forward direction from left to right.
-->-ve index means backward direction from right to left.
Ex:
s = 'python'
s[0] #p
s[-1] #n
s[10] #IndexError

Syn:
s[begin:end]===>begin to end-1

Ex:
s = 'learning python is very easy'
s[1:5]#'earn'
s[:5]#'learn'
s[5:]#'ing python is very easy'
s[:]#'learning python is very easy'
s[::]#'learning python is very easy'
s[::-1]#'ysae yrev si nohtyp gninrael'
s[0:100]#'learning python is very easy'

Type Casting:
--------------------
We can convert one type to other type. This conversion is called as type
casting or type coersion.
int(), float(), bool(), complex(), str()
[Link]():
To convert values from other types to int.
Ex:

int(12.99) #12
int(True)#1
int(False)#0
int("10")#10
int(10+3j) #Invalid
int('10.5') #Invalid
int('0B1010')#Invalid
int(0B1010)#10

[Link]():
To convert other type values to float type.

float(10)#10.0
float(True)#1.0
float(False)#0.0
float('10')#10.0
float('10.5')#10.5
float(10+3j)#Invalid

[Link]():
To convert other type to bool type.

-->0 means False


-->non-zero means True
-->Empty string always False

bool(1)#True
bool(0)#False
bool(10)#True
bool(0.1)#True
bool(0.0)#False
bool(10+3j)#True
bool(0+0j)#False
bool(' ')#True
bool('')#False
bool(None)#False
bool('True')#True

24/10/24
--------------
Python Data Types:
-----------------------------
[Link] DT's:
int,float,bool,complex,str

a = 10
type(a)#<class 'int'>
b = 1.2
type(b)#<class 'float'>
c = 10+3j
type(c)#<class 'complex'>
d = True
type(d)#<class 'bool'>
e = 'sunny'
type(e)#<class 'str'>

Type Casting:
int(), float(), bool(), complex(), str()

4).complex():
-------------------
Form-1:complex(x):
To convert x into complex number with real part x and imaginary
part 0.

complex(10)#(10+0j)
complex(10.5)#(10.5+0j)
complex(True)#(1+0j)
complex(False)#0j
complex('10')#(10+0j)

Form-2:complex(x,y):
To convert x and y into complex number such that x will be real
part and y will be imaginary part

complex(10,3)#(10+3j)
complex(10,-2)#(10-2j)
complex(True,False)#(1+0j)

[Link]():
To convert other type values to str type.

str(10)#'10'
str(10.5)#'10.5'
str(True)#'True'
str(10+3j)#'(10+3j)'

Fundamental Data Types vs Immutability:


All fundamental data types are immutable.

2).Collection DT's:
bytes,bytearray,list,tuple,range,set,frozenset,dict,None

[Link] data type:


To represents a group of byte numbers just like an array.

x = [10,20,30,40]
b = bytes(x)
type(b)#<class 'bytes'>
b[0]#10
b[-1]#40
for i in b:print(i)

Conclusion-1:
The only allowed values for byte data type are 0 to 256.

x = [10,20,30,300]
b = bytes(x)#ValueError: bytes must be in range(0, 256)
Conclusion-2:
Once we create bytes data type, we can't change it values.
It is immutable.

x = [10,20,30]
b = bytes(x)
b[0] = 100 #'bytes' object does not support item assignment

2).bytearray data type:


It is exactly same as bytes data type except that it is mutable.

x = [10,20,30,40]
b = bytearray(x)
type(b)
for i in b:print(i)
10
20
30
40
b[1] = 100
for i in b:print(i)
10
100
30
40

3).list data type:


-------------------------
-->Values should be enclosed with square brackets [ ].
-->Insertion order is preserved.
-->Hetrogenious objects are allowed.
-->Duplicates are allowed.
-->Indexing and slicing are supported.
-->Growable in nature.
-->It is mutable.
Python Data Types:
[Link] DT's:
int,float,bool,complex,str

[Link] DT's:
bytes,bytearray,list,tuple,range,set,frozenset,dict,None

[Link] data type:


--------------------------
-->Values should be enclosed with parenthesis ( ) is an optional.
-->Insertion order is preserved.
-->Hetrogenious objects are allowed.
-->Duplicates are allowed.
-->Indexing and slicing are supported.
-->Growable nature is not applicable.
-->It is immutable.

[Link] data type:


----------------------------
Range data type represents a sequence of numbers.

Ex:
range(10):generates 0 to 9
range(10,20):generates 10 to 19
range(10,50,5):generates 10,15,20,25,30,35,40,45

-->The elemnts present in the range data type are not modifiable. i.e
range data type is immutable.

[Link] data type:


-----------------------
-->Values should be enclosed with curly braces { }.
-->Insertion order is not preserved.
-->Hetrogenious objects are allowed.
-->Duplicates are not allowed.
-->Indexing and slicing are not supported.
-->Growable in nature.
-->It is a mutable.

[Link] data type:


---------------------------------
-->It is exactly same as set except that it is immutable.
-->Hence we cant use add or remove functions.

s = {10,20,30}
fs = frozenset(s)
type(fs)
[Link](40)#'frozenset' object has no attribute 'add'
[Link](10)# 'frozenset' object has no attribute 'remove'

[Link] data type:


-------------------------
-->If we want to represent a group of values as key-value pairs then we
should go for dict data type.
d = {k-v,k-v,k-v,....}
Ex:
d = {100:'sunny',200:'bunny',300:'vinny'}
type(d)#<class 'dict'>
d[100]#'sunny'
d[400]#KeyError: 400
-->Duplicate keys are not allwoed but values can be duplicated. If we are
trying to insert an entry with duplicate key then old value will be
replaced with new value.

d[100] = 'pinny'

-->We can create an empty dictionary as:


d = {}
type(d)
d[key] = value

[Link] data type


-------------------------
-->None means nothing or no value associated.
-->If the value is not available, then to handle such type of cases None
introduced.
-->It is something like null value in java.

a = None
type(a)#<class 'NoneType'>

Escape Characters:
In string literals we can use escape characters to associate
special meaning

s = 'Naresh IT'
print(s)#Naresh IT
s = 'Naresh\nIT'
print(s)
Naresh
IT
s = 'Naresh\tIT'
print(s)#Naresh IT

Constants:
-----------------
-->Constant concept is not applicable in python.
-->But it is convention to use only upper case characters if dont want to
change.
MAX_VALUE = 100
-->It is just convention but we can change the value.

[Link]
[Link]/Reserved words
[Link] types
[Link] chars
[Link]
Python & Full Stack Python @ 6:00 PM (IST) by [Link]
Day-1 [Link]
Day-2 [Link]
Day-3 [Link]
Day-4 [Link]
Day-5 [Link]
Day-6 [Link]
Day-7 [Link]
Day-8 [Link] Data Types:

OPERATORS:
============
Who is an operator?
Any person who is doing certain activity is called as an operator.

What is an operator?
Operator is a symbol that performs certain operations.

1).Arithmetic operators:
+, -, *, /, %, //, **
Ex:
a = 10
b = 2
a+b #12
a-b #8
a*b #20
a/b #5.0
a%b #0
a//b #5
a**b #100

Note:
--------
-->/ operator always performs floating point arithmetic, Hence it will
always returns float value.
-->But floor division(//) can perofrm both floating point and integral
arithmetid. If args are int type then result is int type. If atleast one
argument is float type then the result is float type.

10/2 #5.0
10//2 #5
10.0/2 #5.0
10.0//2 #5.0

-->If we want to use + operator for str type then both args should be str
type only otherwise we will get an error

Ex:
'sunny' + 3 #Invalid
'sunny' + '3' #sunny3

-->If we use * operator for str type then one argument should be int and
other argument should be str type.
Ex:
'sunny' * '3' #invalid
'sunny' * 3 #valid
3 * 'sunny' #valid
'sunny' * 2.5 #invalid
Note:For any number x,
x/0 and x%0 always raise ZeroDivisionError.

2).Relational Operators:
<, <=, >, >=
Ex:
a = 10
b = 20
a < b #True
a <= b #True
a > b #False
a >= b #False

-->We can apply relational operators for str type also.


Ex:
'sunny' > 'mahesh' #True
'mahesh' > 'sunny' #False

Ex:
True > True #False
True >= True #True
10 > True #True
False > True #False
10 > 'a' #Invalid

Relational Chaining:
------------------------------
In the chaining, if all comparisions returns True then only result
is True. If atleast one comparision False then the result is False.

Ex:
10<20<30<40<50 #True
10<20<30<40<50>60 #False

3).Equality Operators:
==, !=
-->We can apply these operators for any type even for incompatible types
also.

10 == 20 #False
10 != 20 #True
10 == True #False
False == False #True
'sunny' == 'sunny' #True
10 == 'sunny' #False
10 == 10.0 #True
10.1 == 10 #False
10 == '10' #False
10.10 == 10.1 #True
1 == True #True
10+3j == 10+5j #False
10+3j == 10+3j #True

Equality chaining:
10 == 20 == 30 == 40 #False
10 == 5+5 == 3+7 == 2*5 #True

4).Logical operators:
and, or, not
For boolen types behaviour:
and==>If both args are True then only result is True
or==>If one argument is True then result is True
not==>Complement

Ex:
True and False #False
True or False #True
not True #False
not False #True
Operators:
==========
[Link] operators:
+,-,*,/,%,//,**

[Link] operatords:
<,<=,>,>=

[Link] operators:
==, !=

[Link] operators:
and, or , not

For non-boolean types behaviours:


----------------------------------------------------
-->0 means False
-->non-zero means True
-->Empty string is always False

x and y:
------------
If x evaluates to False return 'x' otherwise return 'y'

Ex:
10 and 20 #20
0 and 20 #0

-->If the first argument is zero then result is zero otherwise result is
y.

x or y:
----------
If x evaluates True then result is x otherwise result is y.
Ex:
10 or 20 #10
0 or 20 #20

not x:
---------
If x evaluates to False then result is True otherwise False.
Ex:
not 10 #False
not '' #True

Ex:
'mahesh' and 'sunny' #sunny
'' and 'sunny' #''
'radhika' or 'lilly' #radhika
'' or 'lilly' #lilly
not 'radhika' #False
10 or 10/0 #10
0 or 10/0 #ZeroDivisionError

[Link] operators:
-----------------------------
-->We can apply these operators bitwise.
-->These operators are applicable only for int and boolean types.
&, |, ^, ~, <<, >>
&==>If both bits are 1 then only result is 1 otherwise result is 0
|==>If atleast one bit is 1 then the result is 1 otherwise result is 0
^==>x-or==>If bits are different then only result is 1 otherwise result
is 0
~==>bitwise complement operator
1===>0 & 0===>1

0 & 0==>0 0 | 0==>0 0 ^ 0==>0


0 & 1==>0 0 | 1==>1 0 ^ 1==>1
1 & 0==>0 1 | 0==>1 1 ^ 0==>1
1 & 1==>1 1 | 1==>1 1 ^ 1==>0

Ex:
4 & 5 #4
4 | 5 #5
4 ^ 5 #1
~4 #-5

<< left shift operator:


10 << 2 #40

>> right shift operator:


10 >> 2 #

Ex:
True & False #False
True | False #True
True ^ False #True
~True #-2
True << 2 #4
True >> 2 #0

Q. Consider the following code:


-----------------------------------------------
v1 = 1
v2 = 0
v1 = v1 ^ v2
v2 = v1 ^ v2
v1 = v1 ^ v2
print(v1)

What is the result?

A) 0
B) 1
C) 2
D) 3

Answer:A

6).Assignment operators:
-------------------------------------
-->We can use assignment operator to assign a value to the variable.
Ex:
x = 10

-->We can combine assignment operator with some other operator to form
compound assignment operator.
Ex: x += 10===>x = x + 10
The possible compound assignment operators in python are:
+=, -=, *=, /=, %=, **=.............

No increment opoerators in python:


x++(Invalid)
x--(Invalid)
++x(Valid)
--x(Valid)

7).Ternary operator:
------------------------------
In java we can use:
x = (condition)?first value:second value
Ex:
x = (10<20)?30:40
SyntaxError: invalid syntax

In python we can use ternary operator:


x = first value if condition else second value
Ex:
x = 30 if 10 < 20 else 40
x #30
x = 30 if 10 > 20 else 40
x #40

pow(2,3,5)#3

-->Firstvalue if condition-1 else Secondvalue if condition-2 else


Thirdvalue
Ex:
x = 10 if 20<30 else 40 if 50<60 else 70
x #10
x = 10 if 20>30 else 40 if 50<60 else 70
x #40
x = 10 if 20>30 else 40 if 50>60 else 70
x #70

Q.
a = 2
b = 3
a**b*a**b

Q.
x,y = 4,3
z = (x--x) + (y--y)
print(z)

Q.
>>> a = 1_2
>>> b = a*2
>>>b
Operators:
=========
[Link] operators:
+,-,*,/,%,//,**

[Link] operators:
<,<=,>,>=

[Link] operators:
==, !=

[Link] operators:
and, or , not

[Link] operators:
&,|,^,~, <<, >>

[Link] operators:
=
+=, -=, *=, /=, **=...........

No increment operators:
x++
x--
++x
--x

[Link] operator:
x = first value if condition else second value

[Link] operators:
[Link] operators
[Link] operators

[Link] operators:
It is for address comparision. 2-identity operators are available.
-->is
-->is not
-->r1 is r2 returns True if botha r1 and r2 are pointing to the same
object.
-->r1 is not r2 returns True if both r1 and r2 are not pointing to the
same object.

Ex:
a = 10
b = 10
a is b #True
Ex:
x = False
y = False
x is y #True
Ex:
a = 'sunny'
b = 'sunny'
a is b #True

Ex:
l1 = ['one','two','three']
l2 = ['one','two','three']
print(l1 is l2) #False
print(l1 is not l2) #True
print(l1 == l2) #True

Note:
we can use is operator for address comparision where as == operator
for content comparision.

2).Membership operators:
--------------------------------------
To check whether the given object present in the given collection.(It may
be string,list,tuple,set or dict)

in==>Returns True if the given object present in the specified


collection.
not in==>Returns True if the given object not present in the specified
collection.

Ex:
l = [10,20,30]
10 in l #True
50 in l #False
10 not in l #False
50 not in l #True

Ex:
s = 'python is very easy'
'p' in s #True
'python' in s #True
'java' in s #False

Opeartor Precedence:
--------------------------------
If multiple operators present then which operator will be evaluated first
decided by operator precedence.

Ex:
3+10*2 #23
(3+10)*2 #26
Ex:
a = 30
b = 20
c = 10
d = 5
(a+b)*c/d #100.0
(a+b)*(c/d) #100.0
a+(b*c)/d #70.0

Ex:
3/2*4+3+(10/5)**3-2
3/2*4+3+2.0**3-2
3/2*4+3+8.0-2
1.5*4+3+8.0-2
6.0+3+8.0-2
15.0

Input & Output streams:


=====================
Reading dynamic input from the keyboard:
----------------------------------------------------------------
[Link]():
This function always reads the data from the keyboard in the form
of string format. We have to convert that string to our required type by
using the corresponding type casting methods.

Ex:
x = input('Enter some value:')
print(type(x)) ==>It always print str type only for any input type.

Q.w.a.p to read 2-numbers from the keyboard and print sum


-------------------------------------------------------------------------
-----------------
x = int(input('Enter first number:'))
y = int(input('Enter second number:'))
print('Sum is:',x+y)

or

print('Sum is:',int(input('Enter first number:'))+int(input('Enter second


number:')))

Q.w.a.p to read employee data from the keyboard and print that data
-------------------------------------------------------------------------
-----------------------------
eno = int(input('Enter Employee No:'))
ename = input('Enter Employee Name:')
esal = float(input('Enter Employee Salary:'))
eaddr = input('Enter Employee Address:')
emarried = eval(input('Enter Employee Married?[True|False]:'))
print('Confirm Information')
print('Employee No:',eno)
print('Employee Name:',ename)
print('Employee Salary:',esal)
print('Employee Address:',eaddr)
print('Employee Married?:',emarried)

eval():
eval() function take as tring and evaluated the result.

x = '10+20+30'
print(x) #'10+20+30'

x = eval('10+20+30')
print(x) #60
Command Line Arguments:
-----------------------------------------
-->The arguments which are passing at the time of execution are called as
command line args.
Ex:
D:\Mahesh_Classes>py [Link] 10 20 30 40

-->Within the python program this command line args are available in
argv. Which is present in sys module.

Note:
argv[0] represents name of the program, but not the first command
line argument.
argv[1] represents first command line argument.

Ex:To check type of argv from sys


---------------------------------------------------
from sys import argv
print(type(argv))

w.a.p to display command line args


-----------------------------------------------------
from sys import argv
print('The number of command line args:',len(argv))
print('The list of command line args:',argv)
print('Command line args one by one:')
for i in argv:
print(i)

Note:
Within the python program command line args are available in the
string form. Based on our requirement, we can convert into corresponding
type by using type casting methods.

from sys import argv


print(argv[1] + argv[2])
print(int(argv[1]) + int(argv[2]))

Ex:Sum of command line args


---------------------------------------------
from sys import argv
sum = 0
args = argv[1:]
for x in args:
sum += int(x)
print('The sum is:',sum)

Note:
Usually space is a separator between command line args. Iff our
command line args itself contains space then we should enclosed with
double quotes(but not in single quotes)

Ex:
from sys import argv
print(argv[1])

D:\Mahesh_Classes>py [Link] "sunny leone"


sunny leone

How to read multiple values from the keyboard in a single line


-------------------------------------------------------------------------
--------------------
a,b = [int(x) for x in input('Enter two numbers:').split()]
print(a+b)
Output streams:
==============
We can print() function to display output.

Form-1:print() without argument


-------------------------------------------------
Just it prints new line character.

Form-2:print(string)
------------------------------
print('Hello World')
print('Hello\nWorld')
print('Hello\tWorld')
print('Hi '*10)
print(10*'hi ')
print('Hello'+'World')
print('Hello','World')

Form-3:print() with variable number of args


----------------------------------------------------------------
a,b,c = 10,20,30
print('The values are:',a,b,c)

-->Bydefault output values are separated by space. If we want we can


specify separator by using 'sep' attribute.

a,b,c = 10,20,30
print(a,b,c,sep=':')#10:20:30
print(a,b,c,sep='-')#10-20-30

Form-4:print() with end attribute


-------------------------------------------------
print('Hello')
print('Radhika')
print('Happy Diwal!!!!')

-->If we want toutput in the same line with space.

print('Hello',end=' ')
print('Radhika',end=' ')
print('Happy Diwal!!!!')

Form-5:print(object) statement:
----------------------------------------------
We can pass any object(like list,tuple set etc...) as argument to the
print statement.
Ex:
l = [10,20,30]
t = (20,30,40)
print(l)
print(t)

Form-6:print(string,variable list)
-------------------------------------------------
s = 'Mahesh'
a = 50
s1 = 'Python'
s2 = 'Django'
print('Hello',s,'your age is:',a)
print('You are teaching',s1,'and',s2)
Form-7:print(formatted string)
---------------------------------------------
%d==>int
%f==>float
%s==>string type
Syn:
print('formatted string'%(variable list))
Ex:
a = 10
b = 20
c = 20

print('a value is %d'%a)


print('b value is %d and c value is %d'%(b,c))

Ex:
s = 'Mahesh'
l = [10,20,30]
print('Hello %s......The list of values are %s'%(s,l))

Form-8:print() with replacement operator {}


-----------------------------------------------------------------
name = 'Mahesh'
sal = 10000
gf = 'Sunny'
print('Hello {} your salary {} and your GF {} is
waiting'.format(name,sal,gf))
print('Hello {0} your salary {1} and your GF {2} is
waiting'.format(name,sal,gf))
print('Hello {n} your salary {s} and your GF {g} is
waiting'.format(s=sal,g=gf,n=name))

FLOW CONTROL
==============
-->Flow control describes the order in which statements will be executed
at runtime.

1).Conditional Statements:
-->if
-->if-else
-->if-elif-else

2).Iterative Statements:
-->for loop
-->while loop

3).Transfer Statements:
-->break
-->continue
-->pass

[Link] statements:
---------------------------------------
[Link]:
if condition:statement
or
if condition:
stmt-1
stmt-2
stmt-3
-->If condition is True then statements will be executed.

name = input('Enter Name:')


if name == 'sunny':
print('Hello sunny good evening....')
print('How R U?')

[Link]-else:
if condition:
Action-1
else:
Action-2
-->If condition is True Action-1 will be executed otherwise Action-2 will
be executed.

name = input('Enter Name:')


if name == 'sunny':
print('Hello sunny good evening....')
else:
print('Hello guest good evening....')
print('How R U?')

[Link]-elif-else:
------------------
if condition-1:
Action-1
elif condition-2:
Action-2
elif condition-3:
Action-3
else:
Default Action

-->Based on condition the corresponding action will be executed.

brand = input('Enter your favourite brand:')


if brand == 'RC':
print('It is a childrens brand')
elif brand == 'KF':
print('It is not that much kick')
elif brand == 'Boom Boom':
print('Buy one get one free')
else:
print('Other brands are not recommended')

w.a.p to find biggest of given 3-numbers


------------------------------------------------------------
n1 = int(input('Enter 1st Number:'))
n2 = int(input('Enter 2nd Number:'))
n3 = int(input('Enter 3rd Number:'))
if n1 > n2 and n1 > n3:
print('Biggest number is:',n1)
elif n2 > n3:
print('Biggest number is:',n2)
else:
print('Biggest number is:',n3)

Q.w.a.p to check whether the given number is in between 1-10?


-------------------------------------------------------------------------
----------------------
n = int(input('Enter Number:'))
if n >= 1 and n <= 10:
print('The number',n,'is in between 1 to 10')
else:
print('The number',n,'is not in between 1 to 10')
Flow Control:
============
[Link] statements:
-->if
-->if-else
-->if-elif-else

[Link] statements:
-->for loop
-->while loop

[Link] statements:
-->break
-->continue
-->pass

Iterative Statements:
-------------------------------
If we want to execute a group of statements multiple times then we should
go for iterative statements.

[Link] loop:
---------------
If we want to execute some action for every element present in some
sequence(It may be string or collection) then we should go for 'for
loop'.
Syn:
for variable in sequence:
body
------
-------

Ex:To print the characters present in the given string


-------------------------------------------------------------------------
------
s = 'sunny leone'
for x in s:
print(x)

Ex:To print characters present in string index wise


-------------------------------------------------------------------------
---
s = 'radhika'
i = 0
for x in s:
print('The character present at',i,'index:',x)
i += 1

Ex:To print 'hello' 10 times


-----------------------------------------
for x in range(10):
print('hello')

To display numbers from 0-9


-------------------------------------------
for x in range(10):
print(x)

To display odd numbers from 0-20


---------------------------------------------------
for i in range(21):
if i%2 != 0:
print(i)
or

for i in range(1,21,2):
print(i)

To display numbers from 10-1 in descending order


-------------------------------------------------------------------------
--
for x in range(10,0,-1):
print(x)

Ex:
-----
n = int(input('Enter Number:'))#3
for i in range(1,11):
print(i,'*',n,'=',i*n)

Ex:
-----
a = [0,1,2,3]
for a[-1] in a:
print(a[-1])

Ex:
a = [1,2,3,4,5]
for i in a:
[Link](i)
print(a)#[2,4]

Ex:
s = 'python'
for i in range(len(s)):
print(s)
s = 'a'
Flow Control:
--------------------
[Link] statements:
-->if
-->if-else
-->if-elif-else

[Link] statements:
-->for loop
-->while loop

[Link] statements:
-->break
-->continue
-->pass

while loop:
----------------
If we want to execute a group of statements iteratively until some
condition False, then we should go for while loop.
Syn:
while condition:
body

To print numbers from 1 to 10 by using while loop


-------------------------------------------------------------------------
--
x = 1
while x <= 10:
print(x)
x += 1

To display the sum of first 'n' numbers


----------------------------------------------------------
n = int(input('Enter Number:'))#10
sum = 0
i = 1
while i <= n:
sum += i
i += 1
print('The sum of first',n,'numbers is:',sum)

Ex:w.a.p to prompt user to enter some name until entering 'sunny'


-------------------------------------------------------------------------
-------------------------
name = ''
while name != 'sunny':
name = input('Enter Name:')
print('Thanks for confirmation')

Ex:w.a.p to prompt user to enter name & pwd until 'mahesh' & 'python'
-------------------------------------------------------------------------
---------------------------------
name = ''
pwd = ''
while name != 'mahesh' or pwd != 'python':
name = input('Enter Correct Name:')
pwd = input('Enter Correct password:')
print('Thanks for confirmation')
Infinite loops:
---------------------
i = 0
while True:
i += 1
print('Hi',i)

Ex:
n = 6
while n>0:
print(n)
n -= 2 if n%3==0 else 1

o/p:6 4 3 1

Ex:
name = 'Python'
if name == 'java' or 'html' or 'css':
print('login successful')
else:
print('Not valid')

Nested loops:
--------------------
-->Sometimes we can take a loop inside another loop, which are also known
as nested loops.

Ex:
for i in range(4):#0,1,2,3
for j in range(3):#0,1,2
print('i=',i,'j=',j)

Ex:n = 5
-------------
*
* *
* * *
* * * *
* * * * *

n = int(input('Enter some number:'))#5


for i in range(1,n+1):#1,2,3,4,5
for j in range(1,i+1):
print('*',end=' ')
print()

or

n = int(input('Enter some number:'))#5


for i in range(1,n+1):#1,2,3,4,5
print('* '*i)

w.a.p to display *'s in below format


----------------------------------------------------
n=1
-----
*

n = 2
-------
* *
* *

n = 3
--------
* * *
* * *
* * *

n = int(input('Enter some number:'))#5


for i in range(n):
print('* '*n)
Transfer Statements:
--------------------------------
[Link]:
To break the loop execution based on some condition.

Ex:
for i in range(10):
if i == 3:
print('Processing is enough....pls break')
break
print(i)

Ex:
cart = [10,20,600,30,40,550,60,70]
for item in cart:
if item > 500:
print('To place this order insurance must be required')
break
print(item)

[Link]:
To skip current iteration and continue next iteration.

Ex:
for i in range(10):
if i%2 == 0:
continue
print(i)

Ex:
cart = [10,20,600,60,70,550,40,50]
for item in cart:
if item > 500:
print("We can't process this item:",item)
continue
print(item)

Ex:
numbers = [10,20,0,5,0,25]
for n in numbers:
if n == 0:
print("How we can devide with zero...Just skipping")
continue
print("100/{} = {}".format(n,100/n))

loops with else block:


--------------------------------
-->Inside loop execution, if break statement not executed, then only else
part will be executed.

cart = [10,20,50,30,40]
for item in cart:
if item > 500:
print("We can't process this order")
break
print(item)
else:
print('Congrats all items processed successfully.....')

[Link] is difference between for loop and while loop in python?


-->We can use loops to repeat code execution.
-->Repeat code for item in sequence==>for loop
-->Repeat code as long as condition is True==>while loop

[Link]:
In our program syntactically if a block is required which wont do
anything then we can define that empty block with pass keyword.

pass:
-->It is an empty statement
-->It is null statement
-->It wont do anything

Ex:
if True:pass
def f1():pass
Ex:

for i in range(100):
if i%9 == 0:
print(i)
else:
pass

del statement:
----------------------
-->del is keyword in python.
-->After using a variable, it is highly recommended to delete that
variable if it is no longer required, so that corresponding object is
eligible for garbage collection. We can delete variable by using del
statement.

Ex:
x = 10
print(x)
del x
print(x)#NameError: name 'x' is not defined

Note:
We can delete variables which are pointing to immutable objects.
But we cant delte the elements present inside the immutable object

Ex:
s = 'sunny'
del s #valid
del s[0] #invalid
String Data Type:
-------------------------
What is a string?
Any sequence of characters within either single quotes or double
quotes triple quotes is considered as a string.
Ex:
s = 'suuny'
s = "sunny"
s = '''sunny'''
s = """sunny"""

How to access characters of a string:


-------------------------------------------------------
[Link] using index:
-->Python supports both +ve and -ve index
-->+ve index means left to right(forward direction)
-->-ve index means right to left(backward direction)
Ex:
s = 'sunny'
s[0] #s
s[-1] #y
s[10] #IndexError

w.a.p to accept some string from the keyboard and display its characters
by index wise(both +ve and -ve)

s = input('Enter some string:')


i = 0
for x in s:
print('The character present at +ve index:{} and -ve index {}
is:{}'.format(i,i-len(s),x))
i += 1

2).Accessing characters by using slice operator:


-----------------------------------------------------------------------
Syn:
s[begin index:end index:step]
Ex:
----

s = 'learning python is very easy'


s[1:7:1] #'earnin'
s[1:7] #'earnin'
s[:7] #'learnin'
s[7:] #'g python is very easy'
s[:] #'learning python is very easy'
s[::] #'learning python is very easy'
s[::-1] #'ysae yrev si nohtyp gninrael'

1).If step is +ve:


2).If step is -ve:
-------------------------
------------------------
-->Forward direction(left to right) -->Backward
direction(right to left)
-->Begin to end-1
-->Begin to end+1
-->Bydefault begin value:0 --
>Bydefault begin value:-1

Note:
[Link] the forward direction if end value is 0 then result is always
empty.
[Link] the backward direction if end value is -1 then result is
always empty.
Ex:
-----
s = '0123456789'
s[2:8:1] #'234567'
s[2:8:-1]#''
s[-1:-6:-1]#'98765'
s[2:-5:1]#'234'
s[-5:0:-1]#'54321'
s[:0:-1]#'987654321'

Case Study:
------------------
>>> s="abcdefghij"
>>> s[1:6:2]#'bdf'
>>> s[::1]#'abcdefghij'
>>> s[::-1]#'jihgfedcba'
>>> s[3:7:-1] #''
>>> s[7:4:-1]#'hgf'
>>> s[0:1000:1]#'abcdefghij'
>>> s[-4:1:-1] #'gfedc'
>>> s[-4:1:-2] #'gec
>>> s[5:0:1] #''
>>> s[9:0:0] #Error
>>> s[0:-10:-1]#''
>>> s[0:-11:-1]#'a'
>>> s[0:-12:-1]#'a'
>>> s[0:0:1]#''
>>> s[0:-9:-2] #''
>>> s[-5:-9:-2] #'fd'
>>> s[9:-1:-1] #''
Q.w.a.p to access each characters of string in forward direction and
backward direction by using while loop?

s = input('Enter some string:')


n = len(s)
i = 0
print('Forward Direction:')
while i < n:
print(s[i],end='')
i += 1
print()
print('Backward Direction:')
i = -1
while i >= -n:
print(s[i],end='')
i -= 1
print()
print('Backward Direction:')
i = n-1
while i >= 0:
print(s[i],end='')
i -= 1

By using for loop:


--------------------------
s = input('Enter some string:')
print('Forward Direction:')
for i in s:
print(i,end='')
print()
print('Forward Direction:')
for i in s[::]:
print(i,end='')
print()
print('Backward Direction:')
for i in s[::-1]:
print(i,end='')

Checking membership:
----------------------------------
s = input('Enter main string:')
subs = input('Enter sub string:')
if subs in s:
print(subs,'is found in main string')
else:
print(subs,'is not found in main string')

Comparision of strings:
-----------------------------------
s1 = input('Enter first string:')
s2 = input('Enter second string:')
if s1 == s2:
print('Both strings are equal')
elif s1 < s2:
print('First string is less than second string')
else:
print('First string is greater than second string')

Ex:
-----
l1 = ['A','B','C']
l2 = ['A','B','C']
l3 = l2
print(l1 is l2)#False
print(l2 is l3)#True
print(l1 == l2)#True

Removing spaces from the string:


--------------------------------------------------
[Link]()==>To remove spaces at right hand side.
[Link]()==>To remove spaces at left hand side.
[Link]()==>To remove spaces both sides.

city = input('Enter Your City:')


scity = [Link]()
if scity == 'hyderabad':
print('Hello Hyderabadi...gud mng')
elif scity == 'chennai':
print('Hello Madarsi....Vanakkam')
elif scity == 'bangalore':
print('Hello Kannadiga....subhodaya')
else:
print('Your entered city is invalid')

Counting substring in the given string:


----------------------------------------------------------
[Link](substring)==>It will search through out the string
[Link](substring,begin,end)==>It will search from begin to end-1
index.

Ex:
s = 'ababababaababa'
[Link]('a')
[Link]('ab')
[Link]('a',3,10)
Finding Substrings:
-----------------------------
For forward direction: For backward
direction:
-->find()
-->rfind()
-->index()
-->rindex()

find():
[Link](substring):
Returns index of the first occurence of the given substring.
If it is not available then we will get -1

index():
index() method exactly same as find() method except that if the
specified substring is not available then we will get ValueError.

Ex:
s = 'learning python is very easy'
[Link]('e') #1
[Link]('e') #1
[Link]('z')#-1
[Link]('z')#ValueError
[Link]('e')#24
[Link]('e')#24
[Link]('z')#-1
[Link]('z')#ValueError

Note:
Bydefault find() method can search total string. We can also
specify the boundaries to search.
Syn:
[Link](substring,begin,end)

s = 'learning python is very easy'


print([Link]('e',3,22))#20
print([Link]('e',3,12))#-1

Q.w.a.p to display all positions of substring in a given main string.

s = input('Enter main string:')


subs = input('Enter sub string:')
flag = False
pos = -1
n = len(s)
while True:
pos = [Link](subs,pos+1,n)
if pos == -1:
break
print('Found at position:',pos)
flag = True
if flag == False:
print('Not Found')

Replacing a string with another string:


---------------------------------------------------------
Syn:
[Link](oldstring,newstring)
-->Inside s, every occurence of old string will be replaced with new
string.

Ex:
s = 'learning python is difficult'
s1 = [Link]('difficult','easy')
print(s1)

[Link] objects are immutable then how we can change the content by
using replace() method?
Once we create string object, we cant change the content. This non
changable behaviour is nothing but immutability. If we are trying to
change the content by using any method, then with those changes a new
object will be created and changes wont be happended in existing object.
Hence with replace() method also a new object got created but
existing object wont be changed.

Ex:
s = 'abab'
s1 = [Link]('a','b')
print(s,'is available at:',id(s))
print(s1,'is available at:',id(s1))

Splitting of string:
---------------------------
We can split the given string according to specified separator by using
split() method.
Syn: l = [Link](separator)
-->The default separator is space. The return type of split() method is
list.

s = 'Naresh IT Technologies'
l = [Link]()
print(type(l))
print(l)
for i in l:
print(i)

Ex:
s = '08-11-2024'
l = [Link]('-')
for i in l:
print(i)

Joining of strings:
----------------------------
We can join a group of strings(list or tuple) w.r.t the given separator
Syn: s = [Link](group of strings)

Ex:
l = ['sunny','bunny','vinny']
print(':'.join(l))
print('-'.join(l))

Changing cases of a string:


----------------------------------------
s = 'learning Python is very Easy'
print([Link]())
print([Link]())
print([Link]())
print([Link]())
print([Link]())

Checking starting and ending part of the string


----------------------------------------------------------------------
-->startswith()
-->endswith()

s = 'learning ython is very easy'


print([Link]('learning'))
print([Link]('learning'))
print([Link]('easy'))
To check type of characters present in a string:
----------------------------------------------------------------------
print('abc123'.isalnum())
print('abc123'.isalpha())
print('abc'.isalpha())
print('abc'.isdigit())
print('123'.isdigit())
print('abc'.islower())
print('abc123'.islower())
print('ABC'.isupper())
print('Learning Python Is Easy'.istitle())
print(' '.isspace())

Ex:
s = input('Enter any character:')
if [Link]():
print('Alpha Numeric Character')
if [Link]():
print('Alphabet Character')
if [Link]():
print('Lower case alphabet character')
else:
print('Upper case alphabet character')
else:

print('It is a digit')
elif [Link]():
print('It is a space character')
else:
print('Special character')

w.a.p to reverse the given string


------------------------------------------------
1st way
-----------
s = input('Enter some string:')
print(s[::-1])

2nd way
------------
s = input('Enter some string:')
for x in reversed(s):
print(x,end='')

3rd way:
-------------
s = input('Enter some string:')
print(''.join(reversed(s)))

4th way
-----------
s = input('Enter some string:')#sunny
i = len(s)-1
target = ''
while i >= 0:
target += s[i]
i -= 1
print(target)

Q.w.a.p to reverse order of words


-------------------------------------------------
i/p:'learning python is very easy'
o/p:'easy very is python learning'

s = input('Enter some string:')


l = [Link]()
l1 = [ ]
i = len(l)-1
while i >= 0:
[Link](l[i])
i -= 1
print(' '.join(l1))

w.a.p to reverse internal content of each word


---------------------------------------------------------------------
i/p:'learning python is very easy'
o/p:'gninrael nohtyp si yrev ysae'

s = input('Enter some string:')


l = [Link]()
l1 = [ ]
i = 0
while i < len(l):
[Link](l[i][::-1])
i += 1
print(' '.join(l1))

Q.w.a.p to print characters at odd position and even position for given
string
-------------------------------------------------------------------------
------------------------------------------
s = 'sunny'
even:'sny'
odd:'un'

1st way
-----------
s = input('Enter some string:')
print('Characters at even position:',s[0::2])
print('Characters at even position:',s[1::2])

2nd way
-------------
s = input('Enter some string:')
i = 0
print('Characters at even position:')
while i < len(s):
print(s[i],end='')
i += 2
print()
i = 1
print('Characters at odd position:')
while i < len(s):
print(s[i],end='')
i += 2

w.a.p to merge characters of 2-strings into a single string by taking


characters alternatively
s1 = 'mahesh'
s2 = 'sunny'
o/p:'msauhnensyh'
s1 = input('Enter first string:')
s2 = input('Enter second string:')
output = ''
i,j = 0,0
while i < len(s1) or j < len(s2):
if i < len(s1):
output += s1[i]
i += 1
if j < len(s2):
output += s2[j]
j += 1
print(output)

w.a.p to sort the characters of the string and first alphabates followed
by numbers
-------------------------------------------------------------------------
--------------------------------------------------
i/p:'B4A1D3'
o/p:'ABD134'

s = input('Enter some string:')


s1 = s2 = output = ''
for x in s:
if [Link]():
s1 += x
else:
s2 += x
for x in sorted(s1):
output += x
for x in sorted(s2):
output += x
print(output)

w.a.p for the following requirement


----------------------------------------------------
i/p:'a4b3c2'
o/p:'aaaabbbcc'

w.a.p to perform following activity


---------------------------------------------------
i/p:'a4k3b2'
o/p:'aeknbd'

w.a.p to remove the duplicate characters from the given string?


i/p:'ABBBABCBABABCDBBA'
o/p:'ABCD'
w.a.p for the following requirement
----------------------------------------------------
i/p:'a4b3c2'
o/p:'aaaabbbcc'

s = input('Enter some string:')


output = ''
for x in s:
if [Link]():
output += x
previous = x
else:
output += previous * (int(x)-1)
print(output)

w.a.p to perform following activity


---------------------------------------------------
i/p:'a4k3b2'
o/p:'aeknbd'

s = input('Enter some string:')#'a4b3c2'


output = ''
for x in s:
if [Link]():
output += x
previous = x
else:
output += chr(ord(previous)+int(x))
print(output)

w.a.p to remove the duplicate characters from the given string?


i/p:'ABBBABCBABABCDBBA'
o/p:'ABCD'

1st way
-----------
s = input('Enter some string:')
print(''.join(set(s)))

2nd way
------------
s = input('Enter some string:')
l = [ ]
for x in s:
if x not in l:
[Link](x)
print(''.join(l))

List Data Structure:


=================
Creation of list:
------------------------
1). l = [ ]

2). l = [10,20,30,40]

3).Dynamic list:
l = eval(input('Enter List:'))
print(type(l))
4).with list() function:
--------------------------------
l = list(range(10))
print(l)

s = 'mahesh'
l = list(s)
print(l)

5).with split() function


----------------------------------
s = 'python is very easy'
l = [Link]()
print(type(l))
<class 'list'>

Accessing elements of list:


---------------------------------------
[Link] using index:
l = [10,20,30,40]
l[0] #10
l[-1] #40
l[10]#IndexError

[Link] using slice operator:


n = [1,2,3,4,5,6,7,8,9,10]
n[2:7:2]#[3 5 7]
n[4::2]#[5 7 9]
n[3:7]#[4 5 6 7]
n[8:2:-2]#[9 7 5]
n[4:100]#[5 6 7 8 9 10]

List vs Mutability:
---------------------------
Once we create a list object, we can modify its content. Hence list
objects are mutable.

n = [10,20,30,40]
print(n)
n[1] = 333
print(n)#[10,333,30,40]

Traversing the elements of list:


-----------------------------------------------
The sequential access of each element in the list is called as traversal

[Link] using while loop:


--------------------------------
n = [0,1,2,3,4,5,6,7,8,9,10]
i = 0
while i < len(n):
print(n[i])
i += 1

[Link] using for loop:


------------------------------
n = [0,1,2,3,4,5,6,7,8,9,10]
for i in n:
print(i)
To display elements by index wise
----------------------------------------------------
l = ['A','B','C']
x = len(l)#3
for i in range(x):#0,1,2
print(l[i],'is available at +ve index:',i,'and at -ve index:',i-x)

Functions of list:
--------------------------
1).len():
Returns number of elements present in the list

2).count():
Returns the number of occurences of specified item in the list.

3).index():
Returns index of the first occurence of the specified element.

4).append():
To add item at end of the list.

l = [10,20,30]
[Link](40)
l #[10, 20, 30, 40]

To add all elements to list upto 100 which are divisbile by 10


-------------------------------------------------------------------------
------------------
l = [ ]
for i in range(101):
if i%10 == 0:
[Link](i)
print(l)

5).insert():
To insert an item at specified index position.

n = [1,2,3,4]
[Link](1,333)
print(n)#[1, 333, 2, 3, 4]

Note:
If the specified index is greater than max index then element will
be inserted at last position. If the specified index is smaller than min
index then element will be inserted at first position.

n = [1,2,3,4]
[Link](10,999)
[Link](-10,333)
print(n)#[333,1,2,3,4,999]

[Link] between append() and insert()?


-----------------------------------------------------------------
append():
In list when we add any element it will come in last. i.e it will
be last element.
insert():
In list we can insert any element in a particular index number.

6).extend():
To add all items of one list to another list.
Syn: [Link](l2)
All items present in l2 will be added to l1.

order1 = ['Chicken','Mutton','Fish']
order2 = ['RC','KF','MH']
[Link](order2)
print(order1)

order1 = ['Chicken','Mutton','Fish']
[Link]('Prawns')
print(order1)

7).remove():
To remove specified item from the list. If the item present
multiple times then only first occurence will be removed.

Ex:
n = [10,20,30,10,20]
[Link](10)
print(n)#[20,30,10,20]

-->If the specified element not present in the list then we will get
ValueError.
[Link](50) #ValueError: [Link](x): x not in list

Note:
Before using remove() method first we have to check specified
element present in the list or not by using 'in' operator.

Ex:
l = [10,20,30,40]
x = int(input('Enter element to be removed:'))
if x in l:
[Link](x)
print('Removed successfully.....')
else:
print('Specified element is not available')

8).pop():
It removes and returns the last element of the list.

n = [10,20,30,40]
print([Link]())#40
print([Link]())#30
print(n)

-->If the list is empty then pop() function raises IndexError.


n = [ ]
print([Link]())#IndexError: pop from empty list
Note:
-------
-->In general we can use append() and pop() functions to implement stack
data structure by using list, which follows LIFO(Last In First Out)
order.

[Link](index)==>To remove and return element present at specified index.


[Link]()==>To remove and return last element of the list.

Ex:
n = [10,20,30,40,50,60]
print([Link]())#60
print([Link](1))#20
print([Link](10))#IndexError

[Link] between remove() and pop()?


---------------------------------------------------------------
remove()
pop()
-------------
--------
[Link] remove specified element from the list. [Link] remove last element
from the list.

[Link] cant return any value. [Link]


returned removed element.

[Link] specified element not available then we [Link] list is empty then we
will get an
will get ValueError.
IndexError.

Note:
List objects are dynamic, i.e based on our requirement we can
increase and decrease the size.

append(),insert(),extend()===>For increasing size/growable nature


remove(),pop()==>For decreasing/shrinking nature

Ordering elements of the list:


-------------------------------------------
[Link]():
-----------------
n = [10,30,20,40]
[Link]()
print(n)#[40,20,30,10]

[Link]():
------------
n = [20,10,40,30]
[Link]()
print(n)#[10,20,30,40]

Ex:
n = ['Banana','Apple','Cat']
[Link]()
print(n)#['Apple', 'Banana', 'Cat']

Note:
To use sort() function, list should contain only homogenious
elements otherwiwe we will get TypeError.

n = [20,'B',10,'A']
[Link]()#TypeError: '<' not supported between instances of 'str' and
'int'

Descending order:
---------------------------
n = [10,40,20,30]
[Link]()
print(n)
[Link](reverse=True)
print(n)
[Link](reverse=False)
print(n)

Aliasing and Cloning of list objects:


-----------------------------------------------------
The process of giving another reference variable to the existing
list is called as aliasing.

Ex:
x = [10,20,30,40]
y = x #Aliasing
y[1] = 333
print('x:',x) #[10, 333, 30, 40]
print('y:',y) #[10, 333, 30, 40]

-->The problem in this approach is by using one reference variable if we


are changing content, then those changes will be reflected to other
reference variable.
-->To overcome this problem we should go for cloning.
-->The process of creating exactly duplicate independent object is called
as cloning.
-->We can implement cloning by using slice operator or by using copy()
function.

[Link] using slice operator 2).By using


copy() function
------------------------------------- -----
-----------------------------------
x = [10,20,30,40] x =
[10,20,30,40]
y = x[:]
y = [Link]()
y[1] = 999
y[1] = 333
print('x:',x)
print(x)
print('y:',y)
print(y)

[Link] between = operator and copy() function?


= operator meant for aliasing
copy() function means cloning

[Link] between shallow cloning and deep cloning?

Mathematical operators for list object:


---------------------------------------------------------
1). + operator:
To concatenate 2-lists into a single list.

a = [10,20,30]
b = [40,50,60]
c = a + b
print('c:',c)#[10, 20, 30, 40, 50, 60]

Ex:
a = [10,20,30]
b = [40,50,60]
c = [Link](b)
print('a:',a)# [10, 20, 30, 40, 50, 60]
print('b:',b)#[40,50,60]
print('c:',c)#None

Note:
To use + operator both args should be list objects, otherwise we
will get an error.
Ex:
a = [10,20,30]
c = a + 40 #Invalid
c = a +[4] #Valid

2). * operator:
---------------------
To repeat the lements of the list specified number of times.

x = [10,20,30]
y = x * 3
print(y)#[10, 20, 30, 10, 20, 30, 10, 20, 30]

Comparing list objects:


-----------------------------------
x = [50,40,30]
y = [10,20,30,40,50,60]
print(x < y)#False
print(x > y)#True

Nested List:
------------------
n = [10,20,[30,40]]
print(n[0])
print(n[1])
print(n[2][0])
print(n[2][1])

Nested list as matrix:


--------------------------------
In python we can represent matrix by using nested lists.

n = [[10,20,30],[40,50,60],[70,80,90]]
print(n)
print('Elements by row wise:')
for r in n:
print(r)
print('Elements by matrix style:')
for i in range(len(n)):#0,1,2
for j in range(len(n[i])):#0,1,2
print(n[i][j],end=' ')
print()
List Comprehensions:
---------------------------------
It is very easy and compact way of creating list objects from any
iterable objects(like list,tuple,dict,range etc...) based on some
condition.
Syn:
l = [expression for variable in sequemnce if condition]

Ex:Print first 10-numbers squares in list format


o/p:[1,4,9,16,..............100]

Normal program
-------------------------
l = [ ]
for i in range(1,11):
[Link](i*i)
print(l)

By using comprehension
-------------------------------------
l = [i*i for i in range(1,11)]
print(l)

Print only even numbers


-------------------------------------
l = [i*i for i in range(1,11) if i%2 == 0]
print(l)

Ex:Print starting letter of each word


-------------------------------------------------------
words = ['Chiranjeevi','Nag','Venkatesh','Balaiah']
o/p:['C','N','V','B']

l = [x[0] for x in words]


print(l)

Ex:
num1 = [10,20,30,40]
num2 = [30,40,50,60]

o/p:[10,20]
o/p:[30,40]

num3 = [x for x in num1 if x not in num2]


print(num3)
num4 = [x for x in num1 if x in num2]
print(num4)

Ex:
word = 'the quick brown fox jums over the lazy dog'
o/p :[['THE',3],['QUICK',5],['BROWN',5],..............['DOG',3]]

words = [Link]()
l = [[[Link](),len(i)] for i in words]
print(l)

Ex:w.a.p to display unique vowels present in the given string.


-------------------------------------------------------------------------
------------------
i/p:'naresh it technologies'
word = input('Enter the word to search for vowels:')#naresh it
technologies
vowels = ['a','e','i','o','u']
found = [ ]
for letter in word:
if letter in vowels:
if letter not in found:
[Link](letter)
print(found)

Ex:
list = [1,0,2,0,3,0]
for i in list:
if i == 0:
[Link](i)
[Link](i)
print(list)

Ex:
str1 = 'PYTHON'
output = [chr(ord(char)-5) for char in str1]
print(''.join(output))

A).python
B).KTOCJI
C).LUPDKJ
D).PQRST

Q. Consider the code


s='AB CD'
list=list(s)
[Link]('EF')
print(list)

What is the result?


A)('A','B',' ','C','D','EF')
B)['A','B','C','D','EF']
C)['A','B','C','D','E','F']
D)['A','B',' ','C','D','EF']
E){'A','B',' ','C','D','EF'}

Q. Consider the code:


x='ACROTE'
y='APPLE'
z='TOMATO'

Which of the following won't print 'CAT' to the console

A) print(x[1]+y[0]+z[0])
B) print(x[2]+y[1]+z[1])
C) print(x[-5]+y[0]+z[0])
D) print(x[-5]+y[0]+z[-2])

Tuple Data Structure:


===================
Tuple creation:
----------------------
1. t = ()
2.t = (10,) or t = 10,

3.t = (10,20,30) or t = 10,20,30

4. l = [10,20,30]
t = tuple(l)
print(t)

Accessing elements of tuple:


[Link] using index
[Link] using slice operator

-->Tuple is Immutable

1).+ operator for tuple:


------------------------------------
t1 = (10,20,30)
t2 = (40,50,60)
t3 = t1 + t2
print(t3)

2).* operator:
--------------------
t = (10,20,30)
t1 = t * 2
print(t1)

Functions in tuple:
----------------------------
[Link]()
[Link]()
[Link]()
[Link]():After sorting it will return as list
[Link]() and max()

Tuple Packing and Unpacking:


---------------------------------------------
We can create a tuple by packing a group of variables.

a = 10
b = 20
c = 30
d = 40
t = a,b,c,d
print(t)

-->Here a,b,c,d are packed into a tuple t. This is nothing but tuple
packing.

-->Tuple unpacking is the reverse process of tuple packing.


-->We can unpack a tuple and assign its values to different variables.

t = (10,20,30,40)
a,b,c,d = t
print('a=',a,'b=',b,'c=',c,'d=',d)

Note:
At the time of tuple unpacking the of variables and number of
values should be same. Otherwise we will get an error.
a,b,c = t #ValueError: too many values to unpack (expected 3)
a,b,c,d,e = t # ValueError: not enough values to unpack (expected 5, got
4)

Tuple comprehensions:
-----------------------------------
Tuple comprehension is not possible.
Ex:
x = (i*i for i in range(1,6))
-->Here we are not getting tuple object and we are getting generator
object.

Ex:
x = (i*i for i in range(1,6))
print(type(x))#<class 'generator'>
for i in x:
print(i)
Set data structure:
----------------------------
Creation of set object:
---------------------------------
1).s = {10,20,30,40}
type(s)

2).l = [10,20,30]
s = set(l)
type(s)

3) s = { }
type(s) #dict

s = set()
type(s) #<class 'set'>

Functions of set:
-------------------------
[Link](x):
Add item x to the set.

s = {10,20,30}
[Link](40)
print(s)

[Link](x,y,z):
-->To add multiple items to the set.
-->Args are not individual elements and these are iterable elements
like list, range etc...
-->All elements present in the given iterable object will be added
to the set.

s = {10,20,30}
l = [40,50,60]
[Link](l,range(5))
print(s)

[Link] is difference between add() and update() functions in set?


-------------------------------------------------------------------------
------------------------
-->We can use add() to add individual items to the set, where as we can
use update function to add multiple items to the set.
-->add() function can take only one argument where as update function can
take any number of args but all args should be iterable objects.

[Link] are valid?


[Link](10) #valid
[Link](10,20,30) #invalid
[Link](30) #invalid
[Link](range(10))#valid

[Link]():
-->Returns copy of the set.
-->It is cloned object

s = {10,20,30}
s1 = [Link]()
print(id(s))
print(id(s1))
[Link]():
It removes and returns some random element from the set.

s = {10,30,20,40,50}
print(s)
print([Link]())
print(s)

[Link](x):
-->It removes specified element from the set.
-->If the specified element not present in the set then we will get
KeyError.

s = {10,20,30,40}
[Link](20)
print(s)
[Link](50) #KeyError: 50

[Link](x):
->It removes specified element from the set.
-->If the specified element not present in the set then we won't
get any error.

s = {10,20,30,40}
[Link](20)
[Link](50)
print(s)

[Link]():
To remove all elements from the set.

s = {10,20,30}
print(s)
[Link]()
print(s)

Mathematical operations on the set:


------------------------------------------------------
1).union():
To return all elements present in the both sets.
Syn:
[Link](y) or x | y
Ex:

x = {10,20,30,40}
y = {30,40,50,60}
print([Link](y))
print(x | y)

2).intersection():
[Link](y) or x & y
Returns common elements present in both x and y.

Ex:
x = {10,20,30,40}
y = {30,40,50,60}
print([Link](y))
print(x & y)

3).difference():
[Link](y) or x-y
Returns the lements present in x but not in y.

x = {10,20,30,40}
y = {30,40,50,60}
print([Link](y))
print(x - y)
print([Link](x))
print(y - x)

4).symmetric_difference():
x.symmetric_difference(y) or x ^ y
Returns element present in either x or y but not in both

x = {10,20,30,40}
y = {30,40,50,60}
print(x.symmetric_difference(y))
print(x ^ y)

Q.w.a.p to eliminate duplicates present in the list.


-------------------------------------------------------------------------
--
1st way
-----------
l = eval(input('Enter list of values:'))
s = set(l)
print(s)

2nd way
------------
l = eval(input('Enter list of values:'))
l1 = [ ]
for x in l:
if x not in l1:
[Link](x)
print(l1)

Q.w.a.p to print different vowels in the given word?


-------------------------------------------------------------------------
---
w = input('Enter word to search for vowels:')
s = set(w)
v = {'a','e','i','o','u'}
d = [Link](v)
print('The different vowels present in',w,'are:',d)

Set comprehensions:
-------------------------------
-->set comprehensions is possible

l = {i*i for i in range(5)}


print(type(l))
print(l)

Dictionary Data Structure:


=======================
-->We can use list, tuple and set to represent a group of individual
objects as a single entity.
-->If we want to represent a group of objects key-value pairs then we
should go for dictionary.
Ex:
rollno --- name
phone number --- address
ip address --- domain name

-->Duplicate keys are not allowed but value can be duplicated.


-->Hetrogenious objects are allowed for both key and values.
-->Insertion order is preserved.
-->Dict is mutable.
-->Dict is dynamic.
-->Indexing and slicing concept are not applicable.

Note:
In C++ and Java dict is known as 'Map' where as in perl and
Ruby it is known as 'Hash'.

How to create dictionary?


-------------------------------------
d = { } or d = dict()

d = {}
d[100] = 'sunny'
d[200] = 'bunny'
d[300] = 'vunny'
print(d)
print(d[100])#sunny
print(d[400])#KeyError:400

Q.w.a.p to enter name and percentage of marks in a dictionary and display


information on the screen.
rec = { }
n = int(input('Enter number of students:'))#3
i = 1
while i <= n:
name = input('Enter student name:')
marks = int(input('Enter % of marks:'))
rec[name] = marks
i += 1
print('Name of the student','\t','% of marks')
for x in rec:
print('\t',x,'\t\t',rec[x])
Functions in dictionary:
------------------------------------
[Link]():
To create a dictionary

d1 = dict({100:'sunny',200:'bunny',300:'vinny'})
print(d1)
d2 = dict([(111,'katrina'),(222,'katrina'),(333,'deepika')])
print(d2)
d3 = dict((('a','apple'),('b','banan'),('c','cat')))
print(d3)

[Link]():
Returns the number of items in the dictionary.

[Link]():
To remove all the elements from the dictionary.

[Link]():
To get value associated with the key.

[Link](key):
If the key is available then return the corresponding value
otherwise returns None. It wont raise any error.

[Link](key,defaultvalue):
If the key is available then returns the corresponding value
otherwise returns default value.

d = {100:'sunny',200:'bunny',300:'vinny'}
print(d[100])#sunny
print(d[400])#keyerror
print([Link](100))#sunny
print([Link](400))#None
print([Link](100,'pinny'))#sunny
print([Link](400,'pinny'))#pinny

5).pop():
pop(key):
It removes the entry associated with the specified key and
returns the corresponding value.
If the specified key is not available then we will get
KeyError.

d = {100:'sunny',200:'bunny',300:'vinny'}
print([Link](300))
print(d)
print([Link](400))

6).popitem():
It removes an arbitrary item(key-value) from the dict and return
it.

d = {100:'sunny',200:'bunny',300:'vinny'}
print([Link]())
print(d)

-->If the dictionary is empty then we will get KeyError.


d = { }
print([Link]())
7).keys():
Returns all keys associated with dictionary.

d = {100:'sunny',200:'bunny',300:'vinny'}
print([Link]())
for k in [Link]():
print(k)

8).values():
Returns all values associated with dictionary.

d = {100:'sunny',200:'bunny',300:'vinny'}
print([Link]())
for v in [Link]():
print(v)

9).items():
It returns list of tuples represented key-value pairs.
[(k,v),(k,v),(k,v)]

d = {100:'sunny',200:'bunny',300:'vinny'}
for k,v in [Link]():
print(k,'--->',v)

10).copy():
To create exactly duplicate dictionary(cloned copy)

d = {100:'sunny',200:'bunny',300:'vinny'}
d1 = [Link]()
print(id(d))
print(id(d1))

11).setdefault():
[Link](k,v):
-->If the key is available then this function returns the
corresponding value.
-->If the key is not available then the specified key-value
will be added as new item to the dictionary.

d = {100:'sunny',200:'bunny',300:'vinny'}
print([Link](100,'chinny')
print(d)#{100: 'sunny', 200: 'bunny', 300: 'vinny'}
print([Link](400,'chinny')
print(d)#{100: 'sunny', 200: 'bunny', 300: 'vinny', 400: 'chinny'}

12).update():
[Link](x):
All items in the dictionary 'x' will added to dict 'd'

d = {100:'sunny',200:'bunny'}
d1 = {'a':'apple','b':'banana'}
[Link](d1)
[Link]([(333,'A'),(999,'B')])
print(d)

Q.w.a.p to find number of occurances of each letter present in the given


string
-------------------------------------------------------------------------
---------------------------------------------
i/p:'missisippi'
o/p: m occurs 1 time
i occurs 4 times
s occurs 3 times
p occurs 2 times

word = input('Enter any word:')#missisippi


d = {}
for x in word:
d[x]= [Link](x,0) + 1
for k,v in [Link]():
print(k,'occurs',v,'times')

Q.w.a.p to find number of occurances of each vowel present in the given


string
-------------------------------------------------------------------------
--------------------------------------------
word = input('Enter any word:')#missisippi
vowels = {'a','e','i','o','u'}
d = {}
for x in word:
if x in vowels:
d[x]= [Link](x,0) + 1
for k,v in [Link]():
print(k,'occurs',v,'times')
Q.w.a.p to accept student name ans marks from the keyboard and creates a
dictionary, also display student marks by taking student name as input?
-------------------------------------------------------------------------
-----------------------------------------
n = int(input('Enter the number of students:'))
d = {}
for i in range(n):
name = input('Enter student name:')
marks = int(input('Enter marks:'))
d[name] = marks
while True:
name = input('Enter student name to get marks:')
marks = [Link](name,-1)
if marks == -1:
print('Student not found')
else:
print('The marks of',name,'are:',marks)
option = input('Do you want to find another student
marks[Yes|No]:')
if option == 'No':
break
print('Thanks for using our application.....')

Dictionary comprehensions:
------------------------------------------
-->Comprehension concept applicable for dictionary also.

squares = {i:i*i for i in range(1,6)}


print(squares)
doubles = {i:2*i for i in range(1,6)}
print(doubles)

FUNCTIONS
===========
-->If a group of statements repeatedly required then it is not
recommended to write these statements every time separately. We have to
define these statements as a single unit and we can call that unit any
number of times based on our requirement without re-writting. This unit
is nothing but a function.
-->The main advantage of functions is code re-usability.
Note:
In other languages functions are known as methods, procedures,
subroutines etc...

Python supports 2-types of function:


-------------------------------------------------------
1).Built-in functions:
The functions which are coming along with python s/w automatically,
are called as built-in functions or pre-defined functions.
Ex:
id(),type(),input(),eval().............

2).User defined functions:


The functions which are developed by programmers explicitly
according to business requirements, are called as user defined functions.
Syn:
def func_name(parameter):
body
------
-----
return value
Ex:
def wish():

print('Hello good evening.....')


wish()

Parameters:
------------------
Parameters are inputs to the function. If a function contains
parameters, then at the time of calling, we should provide values,
otherwise we will get an error.

Ex:
def wish(name):
print('Hello',name,'good evening.....')
wish('radhika')
wish('lilly')

[Link] a function to take number as input and print its aquare value
-------------------------------------------------------------------------
------------------------------
def squareit(n):
print('The square of',n,'is:',n**2)
squareit(4)
squareit(5)

return statement:
---------------------------
Function can take input values as parameters and executes business
logic, and returns output to the caller with the return statement.

Ex:
def add(x,y):
return x+y
result = add(10,20)
print("The sum is:",result)
print("The sum is:",add(20,30))

-->If we are not writing return statement then default return value is
None.

def f1():
print('Hi')
print(f1())

Q.w.a.p to check whether the given number is even or odd?


-------------------------------------------------------------------------
----------------
def even_odd(num):
if num%2 == 0:
print(num,'is even number')
else:
print(num,'is odd number')
even_odd(10)
even_odd(15)

[Link] a function to find factorial of give number


-------------------------------------------------------------------------
--
def fact(num):
result = 1
while num >= 1:
result *= num
num -= 1
return result
for i in range(1,6):
print('The factorial of',i,'is:',fact(i))

Returning multiple values from a function:


----------------------------------------------------------------
-->In other languages like C,C++ and java function can return atmost one
value. But in python a function can return any number of values.

def sum_sub(a,b):
sum = a+b
sub = a-b
return sum,sub
x,y = sum_sub(100,50)
print('Sum is:',x)
print('Sub is:',y)

Ex:
def calc(a,b):
sum = a+b
sub = a-b
mul = a*b
div = a/b
return sum,sub,mul,div
x = calc(100,50)
print(type(x))#<class 'tuple'>
print('The results are:')
for i in x:
print(i)
Types of args:
---------------------
def f1(a,b):
--------
--------
f1(10,20)

-->a,b are formal args where 10,20 are actual args.

-->There are 4-types of actual args are allowed in python.


-->positional args
-->keyword args
-->default args
-->variable length args

1).positional args:
---------------------------
These are the args passed to function in correct positional order.

def sub(a,b):
print(a-b)
sub(200,100)
sub(100,200)

-->The number of args and position of args must be matched. If we change


the order then the result may be changed.
-->If we change the number of args then we will get an error.

sub(100)#TypeError: sub() missing 1 required positional argument: 'b'


sub(10,20,30)#TypeError: sub() takes 2 positional arguments but 3 were
given

2).keyword args:
------------------------
We can pass argument values by keyword i.e by parameter name.

def wish(name,msg):
print('Hello',name,msg)
wish(name='radhika',msg='good evening')
wish(msg='good evening',name='radhika')

-->Here the order of args is not important but number of args must be
matched.

Note:
We can use both positional and keyword args simultaneously. But
first we have to take positional args the take keyword args, otherwise we
will get an error.

Note:
wish('radhika','good evening')#Valid
wish('radhika',msg='good evening')#Valid
wish(name='radhika','good evening')#Invalid

3).default args:
-----------------------
Sometimes we can provide default values for our positional args.

def wish(name='radhika'):
print('Hello',name,'good evening.....')
wish()
wish('lilly')

-->If we are not providing any name then only default value will be
considered.

4).variable length args:


-----------------------------------
-->Sometimes we can pass any number of args to our function, such type of
args are called as variable length of args.
-->We can declare a variable length argument with * symbol as:
Syn: def f1(*n):pass
-->We can call this function by passing any number of args including zero
number, internally all these values represented in the form of tuple.

def sum(*n):
total = 0
for i in n:
total += i
print('Sum is:',total)
sum()
sum(10,20,30)
sum(10)
sum(10,20)

Ex:
def f1(n1,*s):
print(n1)
for i in s:
print(i)
f1(10)
f1(10,20,30,40)
f1(10,'A',30,'B',40)

Note:
After variable length argument, if we are taking any other args
then we should provide values as keyword args.

def f1(*s,n1):
for i in s:
print(i)
print(n1)
f1(10,20,30,n1=40)

-->We can declare keyword variable length args also. For this we have to
use **.
Syn: def f1(**n):pass
-->We can call this function by passing any number of keyword args.
Internally these keyword args will be stored inside a dictionary.

def display(**kwargs):
for k,v in [Link]():
print(k,'=',v)
display(n1=10,n2=20,n3=30)
display(rno=100,name='sunny',marks=90,subject='python')

Case Study:
------------------
def f(arg1,arg2,arg3=4,arg4=8):
print(arg1,arg2,arg3,arg4)
f(3,2)#3 2 4 8
f(10,20,30,40)#10 20 30 40
f(25,50,arg4=100)#25 50 4 100
f(arg4=2,arg1=3,arg2=4)#3 4 4 2
f()# Invalid
f(arg3=10,arg4=20,30,40)#Invalid
f(4,5,arg2=6)#Invalid
f(4,5,arg3=5,arg5=6)#Invalid

Function vs Module vs Package vs Library:


---------------------------------------------------------------
-->A group of lines with some name is called as function.
-->A group of functions saved to a file is called as module.
-->A group of modules is nothing but a package.
-->A group of packages is nothing but library.

Types of variables:
----------------------------
-->Global variables
-->Local variables
Types of variables:
----------------------------
[Link] variables:
---------------------------
-->The variables which are declared outside the function are called as
global variables.
-->These variables can be accessed in all functions of that mosule.

Ex:
a = 10 #global variable
def f1():
print('f1:',a)
def f2():
print('f2:',a)
f1()
f2()

[Link] variables:
--------------------------
-->The variables which are declared inside a function are called as local
variables.
-->Local variables are available only for the function in which we
declared it. i.e from outside of function we can't access.

def f1():
a = 10 #local variable
print('f1:',a)
def f2():
print('f2:',a)#NameError: name 'a' is not defined
f1()
f2()

Ex:
a = 10
def f1():
a = 333
print('f1:',a)
def f2():
print('f2:',a)
f1() #333
f2() #10

global keyword:
------------------------
-->To declare global variable inside a function.
-->To make global variable available to the function so that we can
perform required modifications.

Ex:
a = 10
def f1():
global a
a = 333
print('f1:',a)
def f2():
print('f2:',a)
f1() ==>333 f2() ==>10
f2() ==>333 f1() ==>333

Note:
If the global variable and local variable having same name then we
can access global variable inside a function by using globals() function.

a = 10 #global variable
def f1():
a = 333 #local variable
print('f1:',a)
print(globals()['a'])
f1()

Recursive Functions:
--------------------------------
A function that calls itself is known as recursive function.

Ex:
factorial(3):3*factorial(2)
:3*2*factorial(1)
:3*2*1*factorial(0)
factorial(n):n*factorial(n-1)

The main advantage of recursive functions are:


[Link] can reduce length of the code and improve readability
[Link] can solve complex problems very easily.

write a function to find factorial of given number with recursion


-------------------------------------------------------------------------
-----------------------
def factorial(n):
if n == 0:
result = 1
else:
result = n*factorial(n-1)
return result
print('Factorial of 5 is:',factorial(5))
print('Factorial of 0 is:',factorial(0))

Ex:w.a.p to find factorial of the given number


---------------------------------------------------------------------
import math
def factorial_logic1(n):
f = 1
i = 1
while i <= n:
f *= i
i += 1
return f

def factorial_logic2(n):
if n == 0:
return 1
else:
return n*factorial_logic2(n-1)

def factorial_logic3(n):
return [Link](n)

#main code
for i in range(11):
print(i,factorial_logic1(i),factorial_logic2(i),factorial_logic3(i)
,sep='\t\t')
Anonymous Functions:
----------------------------------
-->Sometimes we can declare a function without name, such type of
nameless functions are called as anonymous functions or lambda functions.
-->The main advantage of anonymous function is just for instant use(i.e
for one time usage)

Syn: lambda argument_list:expression

Note:By using lambda functions we can write concise code so that


readability of the program will be improved.

Ex:To create a lambda function to find square of given number


-------------------------------------------------------------------------
--------------------
s = lambda n:n*n
print('The square of 3 is:',s(3))
print('The square of 5 is:',s(5))

Ex:Lambda function to find sum of 2-given numbers


-------------------------------------------------------------------------
-----
s = lambda a,b:a+b
print('The sum of 10 and 20 is:',s(10,20))
print('The sum of 100 and 200 is:',s(100,200))

Ex:Lambda function to find biggest of given numbers


-------------------------------------------------------------------------
------
s = lambda a,b:a if a > b else b
print('The biggest of 10 and 20 is:',s(10,20))
print('The biggest of 200 and 100 is:',s(200,100))

Note:
Lambda function internally returns expression value and we are not
required to write return statement explicitly.
Some times we can pass function as argument to another function. In such
case lambda functions are best choice.

We can use lambda functions very commonly with filter(), map() and
reduce() functions, bcoz these functions expect function as argument.

[Link]() function:
To filter values from the given sequence based on some condition.
Syn:
filter(function,sequence)

-->Where function argument is responsible to perform conditional check,


sequence can be list or tuple or string.

w.a.p to filter even numbers from the list by using filter()


-------------------------------------------------------------------------
------------
without lambda function
-------------------------------------
l = [0,5,10,15,20,25,30]
def is_even(n):
if n%2 == 0:
return True
else:
return False
print(list(filter(is_even,l)))

with lambda function


--------------------------------
l = [0,5,10,15,20,25,30]
l1 = list(filter(lambda x:x%2 == 0,l)
print(l1)#[0, 10, 20, 30]
l2 = list(filter(lambda x:x%2 != 0,l)
print(l1)#[5, 15, 25]

[Link]() function:
For every element present in the given sequence, apply some
functionality and generate new element with the required modifications.
For this we should go for map() function.
Syn:
map(function,sequence)
-->The function can be applied for sequence and generates new sequence.

Ex:For every element present in the list perform double and generate new
list of doubles.

without lambda
-----------------------
l = [1,2,3,4,5]
def doubleit(x):
return 2*x
print(list(map(doubleit,l)))

with lambda
------------------
l = [1,2,3,4,5]
print(list(map(lambda x:2*x,l)))#[2, 4, 6, 8, 10]
print(list(map(lambda x:x*x,l)))#[1, 4, 9, 16, 25]
-->We can apply map() function on multiple lists also, but make sure all
lists should have same length.
Syn:
map(lambda x,y:x*y,l1,l2)
x is from l1 and y is from l2

l1 = [1,2,3,4]
l2 = [2,3,4,5]
print(list(map(lambda x,y:x*y,l1,l2)))#[2, 6, 12, 20]

[Link]() function:
It reduces sequence of elements into single element by applying the
specified function.
Syn: reduce(function,sequence)
-->reduce() function present in functools module.

Ex:
from functools import reduce
l = [10,20,30,40,50]
result = reduce(lambda x,y:x+y,l)
print(result)

Nested functions:
--------------------------
def f1():
def inner(a,b):
print('Sum is:',a+b)
print('Product is:',a*b)
print()
inner(10,20)
inner(20,30)
inner(30,40)
f1()

Ex:
----
def wish():
print('Hello good mng.....')
greet = wish #aliasing
del wish
sunny = greet #aliasing
del greet
sunny()#function call

Ex:
def outer():
print('Outer function started')
def inner():
print('Inner function started')
print('Outer function returning inner function')
return inner
f1 = outer()
f1()

f1 = outer() #Function call


f1 = outer #Function aliasing
Function Decorators:
==================
Decorator is a function which can take a function as a argument and
extend its functionality and returns modified function with extended
functionality.

i/p function ------>Decorator Function---->o/p function


with extended func

The main objective of decorator function is we can extend the


functionality of existing functions without modifies that function.

Decorators help to make our code very shorter. This concept is very
helpful while developing web applications with Django.

Ex:
def wish(name):
print('Hello',name,'good mng.....')

-->This function can always prints same output for any name.
'''
Hello mahesh good mng.....
Hello naresh good mng.....
Hello sunny good mng.....'''

-->But we want to modify this function to provide different message if


name is 'sunny'. We can do this without touching wish() function by
using decorator.

Ex:
def decor(func):
def inner(name):
if name == 'sunny':
print('Hello sunny very very good mng....')
else:
func(name)
return inner
@decor
def wish(name):
print('Hello',name,'good mng.....')
wish('mahesh')
wish('sunny')
wish('naresh')

How to call same function without decorator?


--------------------------------------------------------------------
decorfunction = decor(wish)
decorfunction('mahesh')
decorfunction('sunny')

Ex:
----
def smart_division(func):
def inner(a,b):
print('We are deviding',a,'with',b)
if b == 0:
print("OOP's....Can't devide with zero")
else:
return func(a,b)
return inner
@smart_division
def division(a,b):
return a/b
print(division(20,2))
print(division(20,0))

Decorator Chaining:
------------------------------
We can define multiple decorators for the same function and all these
decorators will perform decorator chaining.

Ex:
@decor1
@decor
def num():

-->For num() function we are applying 2-decorator functions. First inner


decorator will work and then outer decorator.

def decor(func):
def inner():
x = func()
return x*x
return inner
def decor1(func):
def inner():
x = func()
return 2*x
return inner
@decor1
@decor
def num():
return 10
print(num())

Patterns:
-------------
n = 3
-------
* * *
* * *
* * *
n = int(input('Enter no of rows:'))#5
for i in range(n):
print('* '*n)

Ex:n=3
----------
1 1 1
2 2 2
3 3 3
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print((str(i+1)+' ')*n)

Ex:n=3
----------
A A A
B B B
C C C
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print((chr(65+i)+' ')*n)

Ex:n=3
-----------
3 3 3
2 2 2
1 1 1
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print((str(n-i)+' ')*n)

Ex:n=3
---------
C C C
B B B
A A A
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print((chr(64+n-i)+' ')*n)

Ex:n=3
----------
1 2 3
1 2 3
1 2 3

Ex:
----
A B C
A B C
A B C

Ex:
----
3 2 1
3 2 1
3 2 1

Ex:
---
C B A
C B A
C B A
Generators:
==========
-->Generator is a funtion which is responsible to generate a sequence of
values.
-->We can write generator function just like ordinary functions, but it
uses yield keyword to return values.
yield ---->Generator------>A sequence
of values
Ex:
def mygen():
yield 'A'
yield 'B'
yield 'C'
g = mygen()
print(type(g))
print(next(g))
print(next(g))
print(next(g))

Ex:generate the numbers from 5 to 1


-------------------------------------------------------
def countdown(num):
print('start countdown')
while num > 0:
yield num
num -= 1
values = countdown(5)
for i in values:
print(i)

Ex:To generate fibonacci numbers................


-------------------------------------------------------------------
def fib():
a,b = 0,1
while True:
yield a
a,b = b,a+b
for x in fib():
if x>100:
break
print(x)

Advantages of generator functions:


----------------------------------------------------
[Link] compared with class level iterations, generators are very easy to
use.
[Link] memory utilization and performance.
[Link] are best suitable for reading data from large number of
large files.
[Link] utilization, bcoz we are not required to store all values at a
time.

MODULES:
----------------
-->A group of functions, variables and classes saved into a file, which
is nothing but module.
-->Every python file(.py) acts as module.
-->Advantages of modules are:Readability, Reusability & Maintainability.

Ex:[Link]
----------------------------
x = 333
def add(a,b):
return a+b
def product(a,b):
return a*b

-->maheshmath module contains one variable and 2 functions.


-->If we want to use members of the module in our program then we should
import that module.
import modulename
-->We can access members by using modulename.
[Link]
[Link]()
[Link]
----------
import maheshmath
print(maheshmath.x)
print([Link](10,20))
print([Link](10,20))

Renaming a module at the time of import(module aliasing):


-------------------------------------------------------------------------
---------------
Ex:
import maheshmath as m
-->Here maheshmath is original module name and m is alias name.
-->We can access members by using alis name m.

[Link]
-----------
import maheshmath as m
print(m.x)
print([Link](10,20))
print([Link](10,20))

from....import:
-----------------------
-->We can import a particular member or module by using from...import
-->The main advantage of this is we can access members directly without
using module.

Ex:
from maheshmath import x,add
print(x)
print(add(10,20))
print(product(10,20)) #NameError: name 'product' is not defined

-->We can import all the members of a module as:


from maheshmath import *

Member aliasing:
-------------------------
from maheshmath import x as y,add as sum
print(y)
print(sum(100,200))

-->Once we defined as alias name, we should use alias name only and we
should not use original name.
from maheshmath import x as y
print(x) #NameError: name 'x' is not defined

Various possibilities of import:


-----------------------------------------------
import modulename
import module1,module2,module3
import module1 as m1
import module1 as m1,module2 as m2,module3 as m3
from module import member
from module import member1,member2,member3
from module import member1 as m1
from module import *

Patterns:
-------------
x = 3
--------
*
* *
* * *
n = int(input('Enter [Link] rows:'))#5
for i in range(n):#0,1,2,3,4
print('* '*(i+1))

x = 3
-------
1
2 2
3 3 3
n = int(input('Enter [Link] rows:'))#5
for i in range(n):#0,1,2,3,4
print((str(i+1)+' ')*(i+1))

x = 3
-------
A
B B
C C C
n = int(input('Enter [Link] rows:'))#5
for i in range(n):#0,1,2,3,4
print((chr(65+i)+' ')*(i+1))

Ex:
-----
1
1 2
1 2 3

Ex:
-----
A
A B
A B C

Ex:
-----
3
3 2
3 2 1
Ex:
----
C
C B
C B A
Reloading a Module:
==================
-->Bydefault module will be loaded only once eventhough we are importing
multiple times.

Ex:[Link]
----------------------
print('This is from module-1')

[Link]
----------
import module1
import module1
import module1
print('This is test module')

-->In the above program module1 will be loaded only once eventhough we
are importing multiple times.
-->The problem in this approach is after loading a module if it is
updated outside then updated version of module1 is not available to our
program.
-->We can solve this problem by reloading module explicitly based on our
requirement.
-->We can reload by using reload() function of importlib module.

Ex:
import time
import module1
from importlib import reload
print('Program entering into sleeping state')
[Link](30)
reload(module1)
print('This is test module')

-->The main advantage of explicit module reloading is we can ensure that


updated version is always available to our program.

How to find members of a module


--------------------------------------------------
-->dir() can list out all members of current module or a specific module.

dir()==>To list out all members of current module.


dir(module name)==>To list out all the members of specified module.

Ex:[Link]
----------------
x = 333
def add(a,b):
return a+b
print(dir())

Ex:To display members of a particular module.


----------------------------------------------------------------------
[Link]
----------
import maheshmath
print(dir(maheshmath))

Note:For every module at the time of execution python interpreter will


add some special properties automatically for internal use.
Ex:
['__builtins__', '__cached ', ' doc__', ' file ',
'__loader ', ' name__', '__package ', '__spec__', 'add', 'product',
'x']

-->Based on our requirement we can access these properties also in our


program.

Ex:[Link]
---------------
print(__builtins__)
print(__cached__)
print(__doc )
print(__file__)
print(__loader__)
print(__name__)
print(__package )
print(__spec__)

The special variable __name__:

---------------------------------------------
-->For every python program, a special variable __name__ will be added

internally. This variable stores information regarding whether the


program executed as an individual program or as a module.
-->If the program executed as an individual program then the value of
this variable is main__.

-->If the program executed as a module from some other program then the
value of this variable is the name of the module where it is defined.
-->Hence by using this __name__ variable we can identify whether the

program executed directly or as a module.

[Link]
-----------------
def f1():
if name == '__main ':

print('The code executed directly as a program')


print('The value of name :',__name__)
else:

print('The code executed indirectly as a module from some


other module')
print('The value of name :',__name__)
f1()

D:\Mahesh_Classes>py [Link]
The code executed directly as a program
The value of name : __main__

[Link]
----------
import module1
module1.f1()

D:\Mahesh_Classes>py [Link]
The code executed indirectly as a module from some other module
The value of name : module1
Working with random module:
---------------------------------------------
-->This module defines several functions to generate random numbers.
1).random():
To generate some float value between 0 and 1(not inclusive)

from random import *


for i in range(10):
print(random())

2).randint():
To generate random integer between two given numbers(inclusive)

from random import *


for i in range(10):
print(randint(1,100))

Generate 10 4-digit random numbers


-------------------------------------------------------
from random import *
for i in range(10):
print(randint(0,9),randint(0,9),randint(0,9),randint(0,9))

3).uniform():
To generate random float value between 2-given numbers(not
inclusive)

from random import *


for i in range(10):
print(uniform(1,10))

4).randrange([start],stop,[step]):
Returns a random number from the range.

from random import *


for i in range(10):
print(randrange(10))#generates a number from 0 to 9
print(randrange(1,11))#generates a number from 1 to 9
print(randrange(1,11,2))#generates a number from 1,3,5,7,9

5).choice():
-->It wont return random number.
-->It will return a random object from the given list or tuple or
str.

from random import *


l = ['sunny','bunny','vinny','chinny','pinny','zinny']
for i in range(10):
print(choice(l))
Packages:
========
-->It is an encapsulation mechanism to group related modules into a
single unit.
-->Package is nothing but folder or directory which represents collection
of python modules.
-->Any folder or directory contains init__.py file, is considered as a
python package. This can be empty.

The main advantages of packages statements are:


[Link] can resolve naming conflicts.
[Link] can identify our components uniquely.

Ex-1:
--------
D:\Mahesh_Classes
|--[Link]
|--pack1
|--[Link]
|--f1()
[Link]
----------------
def f1():

print('Hello this is from module-1 present in pack-1')

[Link](1st way)
------------------------
import pack1.module1
pack1.module1.f1()

[Link](2nd way)
------------------------
from pack1.module1 import f1
f1()

Ex-2:
--------
D:\Mahesh_Classes
|--[Link]
|--com
|--[Link]
|--f1()
|--nareshit
|--[Link]
|--f2()
[Link]
-----------------
def f1():

print('Hello this is from module-1 present in com')

[Link]
-----------------
def f2():
print('Hello this is from module-2 present in [Link]')

[Link]
----------
from com.module1 import f1
from [Link].module2 import f2
f1()
f2()
=======================================================================
Exception Handling
=================
-->In any programming language there are 2-types of errors are possible.
[Link] Errors
[Link] Errors
[Link] Errors:
The errors which are occurs because of invalid syntax are called as
syntax errors.

Ex:
x = 10
if x == 10
print('Hi')
SyntaxError: expected ':'

Ex:
print 'Hi'
SyntaxError: Missing parentheses in call to 'print'

Note:
Programmer is responsible to correct these errors. Once all the
syntax errors are corrected then only program execution will be started.

2).Runtime Errors:
----------------------------
-->Also called as exceptions
-->While executing the program if something goes wrong because of end
user input or programming logic or memory problems etc we will get
Runtime Errors.

Ex:
print(10/0) ==>ZeroDivisionError: division by zero
print(10/'ten')==>TypeError: unsupported operand type(s) for /: 'int' and
'str'
int('ten') ==>ValueError: invalid literal for int() with base 10: 'ten'

Note:
Exception handling concept applicable for Runtime errors but not
for syntax errors.

What is an Exception?
An unwanted and unexpected event that distrubs normal flow of the
program is called as an exception.

Ex:
ZeroDivisionError
ValueError
SleepingError
TyrePuncheredError

-->It is highly recommended to handle exceptions. The main advantage of


exception handling is Graceful Termination of the program(i.e we should
not block our resources and we should not miss anything).

-->Exception handling does not mean repairing exception. We have to


define alternative way to continue rest of the program normally.

[Link] is an Exception?
[Link] is purpose of Exception Handling?
[Link] is the meaning of Exception Handling?

Patterns:
-------------
n = 3
-------
* * *
* *
*
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print('* '*(n-i))

Ex:n = 3
------------
1 1 1
2 2
3
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print((str(i+1)+' ')*(n-i))

Ex:n=3
-----------
A A A
B B
C
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print((chr(65+i)+' ')*(n-i))

Ex:
-----
3 3 3
2 2
1
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print((str(n-i)+' ')*(n-i))

Ex:
----
C C C
B B
A
n = int(input('Enter no of rows:'))#3
for i in range(n):#0,1,2
print((chr(64+n-i)+' ')*(n-i))

Ex:
1 2 3
1 2
1

Ex:
A B C
A B
A
Ex:
3 2 1
3 2
3

Ex:
C B A
C B
C
Default exception handling in python:
--------------------------------------------------------
-->Every exception in python is an object. For every exception type the
corresponding classes are available.
-->Whenever an exception occurs PVM will create the corresponding
exception object and will check for handling code. If the handling code
is not available then python interpreter termiantes the program
abnormally and prints corresponding exception information to the console.
-->The rest of the program wont be executed.

Ex:
-----
print('Hello')
print(10/0)
print('Hi')

Customized exception handling by using try-except:


-------------------------------------------------------------------------
----
-->It is highly recommended to handle exceptions.
-->The code which may raise exception is called as risky code and we have
to take risky code inside the try block. The corresponding handling code
we have to take inside except block.

Syn:
try:
Risky code
except XXX:
Handling code/Alternative code
Ex:
-----

print('stmt-1')
try:
print(10/0)
except ZeroDivisionError:
print(10/2)
print('stmt-3')

Control flow in try-except block:


-------------------------------------------------
Ex:
-----
try:
stmt-1
stmt-2
stmt-3
except XXX:
stmt-4
stmt-5

Case-1:If there is no Exception.


1,2,3,5 Normal Termination

Case-2:If an exception is raised at stmt-2 and corresponding except block


is matched.
1,4,5 Graceful Termination

Case-3:If an exception is raised at stmt-2 but corresponding except block


is not matched.
1 Abnormal Termination
Case-4:If an exception is raised at stmt-4 or stmt-5 then it always
abnormal termination.

Conclusions:
-------------------
1).Within the try block if anywhere exception raised then rest of the try
block wont be executed eventhough we handled that exception. Hence we
have to take only risky code inside try block and length of the try block
should be less as possible.

2).In addition to try block, there may be a chance of raising exception


inside except block also.

3).If an statement which is not part of try block raises an exception


then it is always abnormal termination.

How to print exception information:


-------------------------------------------------------
try:
print(10/0)
except ZeroDivisionError as msg:
print("Exception raised and it's description is:",msg)

try with multiple except blocks:


------------------------------------------------
-->The way of handling exception is varied exception to exception. Hence
for every exception type a separate except block we have to provide. i.e
try with multiple except block is possible and recommended.
-->If try with multiple except blocks are available then based on raised
exception the corresponding except block will be executed.

try:
x = int(input('Enter 1st number:'))
y = int(input('Enter 2nd number:'))
print(x/y)
except ZeroDivisionError:
print("Can't devide with zero")
except ValueError:
print('Please provide int values only')

-->If try with multiple except blocks available then the order of these
except blocks is important. Python interpreter will always consider top
to bottom until matched except block identified.

try:
x = int(input('Enter 1st number:'))
y = int(input('Enter 2nd number:'))
print(x/y)
except ArithmeticError:
print('ArithmeticError')
except ZeroDivisionError:
print("Can't devide with zero")

Single except block that can handle multiple exceptions:


-------------------------------------------------------------------------
------------
try:
x = int(input('Enter 1st number:'))
y = int(input('Enter 2nd number:'))
print(x/y)
except (ZeroDivisionError,ValueError) as msg:
print("Pls provide valid numbers only the problem is:",msg)

Default except block:


-------------------------------
-->We can use default except block to handle any type of exception.
-->In default except block generally we can print normal error messages.
Syn:
except:
statements
Ex:
try:
x = int(input('Enter 1st number:'))
y = int(input('Enter 2nd number:'))
print(x/y)
except ZeroDivisionError:
print("ZeroDivisionError:Can't devide with zero")
except:
print('DefaultExcept:Please provide valid input')

Note:
If try with multiple except blocks available then the default
except block should be last, otherwise we will get SyntaxError.

try:
print(10/0)
except:
print('DefaultExcept')
except ZeroDivisionError:
print("ZeroDivisionError")

SyntaxError: default 'except:' must be last

Various combinations of except block:


[Link] ZeroDivisionError:
[Link] ZeroDivisionError as msg:
[Link] (ZeroDivisionError,ValueError):
[Link] (ZeroDivisionError,ValueError) as msg:
[Link]:
finally block:
-------------------
-->It is not recommended to maintain clean up code(Resource deallocation
code or Resource releasing code) inside try block because there is no
guarantee for the execution of every statement inside try block always.
-->It is not recommended to maintain clean up code inside except block,
because if there is no exception then except block wont be executed.
-->Hence we required some special place to maintain clean up code which
should be executed always irrespective of whether exception raised or not
raised and whether exception handled or not handled. Such type of best
place is nothing but finally block.
-->Hence the main purpose of finally block is to maintain clean up code.

Syn:
------
try:
Risky code
except:
Handling code
finally:
Cleanup code

Case-1:If there is no exception


----------------------------------------------
try:
print('try')
except:
print('except')
finally:
print('finally')

o/p:try finally

Case-2:If there is an exception raised and handled


-------------------------------------------------------------------------
--
try:
print('try')
print(10/0)
except ZeroDivisionError:
print('except')
finally:
print('finally')

o/p:try except finally

Case-3:If there is an exception raised but not handled


-------------------------------------------------------------------------
-------
try:
print('try')
print(10/0)
except NameError:
print('except')
finally:
print('finally')

o/p:try finally Abnormal termination.

Note:
-->There is only one situation where finally block wont be
executed. i.e whenever we are using os._exit(0) function.
-->Whenever we are using os._exit(0) function then PVM itself will
be shutdown. In this particular case finally block wont be executed.

import os
try:
print('try')
os._exit(0)
except NameError:
print('except')
finally:
print('finally')

Control flow of try-except-finally:


--------------------------------------------------
try:
stmt-1
stmt-2
stmt-3
except:
stmt-4
finally:
stmt-5
stmt-6

Case-1:If there is no exception.


1,2,3,5,6 Normal termination.

Case-2:If an exception raised in stmt-2 and the corresponding except


block matched.
1,5,6 Graceful termination.

Case-3:If an exception raised in stmt-2 but corresponding except block


not matched.
1,5 Abnormal termination.

Case-4:If an exception raised at stmt-5 or stmt-6 then it is always


abnormal termination.

Case-5:If an exception raised at stmt-4 then it always abnormal


termination but before that finally block will be executed.

Nested try-except-finally block:


----------------------------------------------
try:
------
try:
------
except:
------
finally:
------
except:
------
finally:
------

-->General risky code we have to take inside try block and too much risky
code we have to take inner try block. Inside inner try block if any
exception raised then inner except block is responsible to handle. If
unable to handle then outer except block is responsible to handle.

Ex:
try:
print('Outer try block')
try:
print('Inner try block')
print(10/0)
except NameError:
print('Inner except block')
finally:
print('Inner finally block')
except:
print('Outer except block')
finally:
print('Outer finally block')

else block with try-except-finally:


--------------------------------------------------
-->else block will be executed if an only if there are no exceptions
inside try block.

try:
Risky code
except:
will be executed if exception inside try
else:
will be executed if there is no exception inside try
finally:
will be executed whether exception raised or not raised handled or
not handled.

Ex:
try:
print('try')
print(10/0) ----->Line-1
except:
print('except')
else:
print('else')
finally:
print('finally')

-->If we comment Line-1 then else block will be executed bcoz there is no
exception inside try. In this case output is:try else
finally

-->If we are not commenting Line-1 then else block wont be executed bcoz
there is an exception inside try block. In this case output is:try
except finally

Types of Exceptions:
-------------------------------
[Link] exceptions
[Link] defined exceptions
Logging Module:
==============
-->It is highly recommended to store complete application flow and
exceptions information to a file. This process is called as logging.
-->The main advantage of logging are:
[Link] can use log files while performing debugging.
2).We can provide statistics like number of requests per day
etc....
-->To implement logging, python provides one inbuilt module:logging

logging levels:
---------------------
Depending on type of information, logging data is devided according to 6-
levels in python.

1).CRTICAL ==>50
2).ERROR ==>40
3).WARNING ==>30
4).INFO ==>20
5).DEBUG ==>10
6).NOTSET ==>0

How to implement logging:


----------------------------------------
-->To perform logging, first we required to create a file to store
messages and we have to specify which level messages we have to store.
-->We can do this by using basicConfig() function of logging module.

[Link](filename='[Link]',level=[Link])
-->The above line will create a file [Link] and we can store either
WARNING level or higher level messages to that file.
-->After creating log file, we can write messages to that file file by
using the methods.
[Link](message)
[Link](message)
[Link](message)
[Link](message)
[Link](message)

Ex:w.a.p to create a log file and write WARNING and higher level messages
-------------------------------------------------------------------------
--------------------------------------
import logging
[Link](filename='[Link]',level=[Link])
print('Logging Module Demo')
[Link]('This is debug message')
[Link]('This is info message')
[Link]('This is warning message')
[Link]('This is error message')
[Link]('This is critical message')

Note:
In the above program only WARNING and higher level messages will be
written to log file. If we set level as DEBUG then all the messages will
be written to log file.

How to write python program exceptions to log file:


-------------------------------------------------------------------------
-----
import logging
[Link](filename='[Link]',level=[Link])
[Link]('A new request came')
try:
x = int(input('Enter first number:'))
y = int(input('Enter second number:'))
print(x/y)
except ZeroDivisionError as msg:
print("Can't devide with zero")
[Link](msg)
except ValueError as msg:
print("Enter only int values")
[Link](msg)
[Link]('Request processing completed')

Assertions
=========
Debugging python program by using assert keyword:
-------------------------------------------------------------------------
-----
-->The process of identifying and fixing the bugs is called as debugging.
Very common way of debugging is to use print() statement. But the problem
with the print() statement is after fixing the bug, we have to delete the
extra print() statements, otherwise these will be executed at the runtime
which creates performance problems and distrubs console output.

-->To overcome this problem we should go for assert statement. The main
advantage of assert statement over print() statement is after fixing bugs
we are not required to delete assert statements. Based on our requirement
we can enable or disable assert statements.

-->Hence the main purpose of assertion is to perform debugging, usually


we can perform debugging either in development or in test environments
but not in production environemnt.

Types of assert statements:


There are 2-types of assert statements:
1).Simple Version
2).Augmented Version

1).Simple version:
assert condition_expression

2).Augmented version:
assert condition_expression,
message

-->Conditional_expression will be evaluated and if it is True then the


program will be continued.
-->If it is False then program will be terminated by raising
AssertionError.
-->By seeing AssertionError, programmer can analyze the code and can fix
the problem.

Ex:
-----
def squareit(n):
return n**n
assert squareit(2) == 4,'The square of 2 should be 4'
assert squareit(3) == 9,'The square of 3 should be 9'
assert squareit(4) == 16,'The square of 4 should be 16'
print(squareit(2))
print(squareit(3))
print(squareit(4))

Note:To disable assert statements py -O [Link]

Exception Handling vs Assertions:


---------------------------------------------------
-->Assertion concept can be used to alert the programmer to resolve
development time errors.
-->Exception handling can be used to handle run time errors.
File Handling
============
-->As part of the programming requirement, we have to store our data
permanently for future purpose. For this we should go for files.

Types of files:
1).Text files
2).Binary files

Text Files:
We can use text files to store characters data.
Ex:[Link]

Binary Files:
We can use binary files to store binary data like images, video
files audio files etc...

Opening a file:
---------------------
-->Before performing any operations(like read or write) on the file,
first we have to open that file. For this we should use python inbuilt
function open().
-->At the time of the open, we have to specify mode, which represents the
purpose of opening file.
Syn:
f = open(filename,mode)

The allowed modes in python are:

1).r -->Open an existing file for read operations. The file pointer is
positioned at the beginning of the file. If the specified file does not
exist then we will get FileNotFoundError. This is default mode.

2).w -->Open an existing file for write operations. If the file already
contains some data then it will be overridden. If the specified file not
available then this mode will create the file.

3).a -->Open an existing file for append operations. It wont override


existing data. If the specified file is not available then this mode will
create a new file.

4).r+ -->To read and write data into the file. The previous data in the
file will not be deleted. The file pointer is placed at the beginning of
the file.

5).w+ -->To write and read data. It will override existing data.

6).a+ -->To append and read data from the file. It wont override existing
data.
7).x -->To open a file in exclusive creating mode for write operation. If
the file already exist then we will get FileExistsError.
Note:
All the above modes are applicable for text files. If the above
modes suffixed with 'b' then these represents for binary files.
Ex: rb,wb,ab,r+b,w+b,a+b,xb

Closing a file:
--------------------
After completing our operations on the file, it is highly recommended to
close the file. For this we have to use close() function.

Various properties of file object:


----------------------------------------------
Once we opened a file and we got file object, we can get various details
related to that file by using its properties.
name-->Name of the opened file. mode-->Mode in which the file is
opened. closed-->Returns boolean value indicates that file is closed
or not. readable()-->Returns boolean value indicates that file is
readable or not.
writable()-->Returns boolean value indicates that file is writable or
not.
f = open('[Link]','w') print('File
Name:',[Link]) print('File
Mode:',[Link]) print('Is File
Readable:',[Link]()) print('Is File
Writable:',[Link]()) print('Is File
Closed:',[Link]) [Link]()
print('Is File Closed:',[Link])

Writting data to text file:


1).write(str)
2).writelines(list of lines)
Ex:
f = open('[Link]','w')
[Link]('Naresh\n')
[Link]('IT\n')
[Link]('Technologies\n') print('Data
written to the file.....')
[Link]()

Note:In the above program, data present in the file will be overridden
everytime if we run the program. Instead of overriding if we want to
append then we should open the file as: f = open('[Link]','a') Ex:
f = open('[Link]','w')
list = ['sunny\n','bunny\n','vinny\n','chinny']
[Link](list)
print('List of lines written to the file.....')
[Link]()

Reading data from the file:


--------------------------------------- read()==>To
read all data from the file read(n)==>To read 'n'
characters from the file readline()==>To read only
one line readlines()==>To read all lines into list

Ex-1:To read total data from the file


----------------------------------------------------
f = open('[Link]','r') data = [Link]()
print(data)
[Link]()

Ex-2:To read only first 10-characters


------------------------------------------------------
f = open('[Link]','r') data = [Link](10) print(data)
[Link]()

Ex-3:To read data line by line -----------


------------------------------- f =
open('[Link]','r') line1 = [Link]()
print(line1,end='') line2 = [Link]()
print(line2,end='')
[Link]()

Ex-4:To read all lines into list ----------


--------------------------------- f =
open('[Link]','r') lines = [Link]()
print(type(lines)) for line in lines:
print(line,end='') [Link]() Ex:
----
f = open('[Link]','r')
print([Link](3))
print([Link]())
print([Link](4)) print('Remaining
data') print([Link]())
[Link]()

The with statement:


------------------------------
-->The with statement can be used while opening a file. We can use this
to group file operation statements with a block.
-->The advantage of with statement is it will take care closing of file,
after completing all operations automatically even in case of exceptions
also, and we are not required to close explicitly. Ex:
with open('[Link]','w') as f:
[Link]('Naresh\n')
[Link]('IT\n')
[Link]('Technologies')
print('File is closed:',[Link])
print('File is closed:',[Link])
tell() and seek()
methods:
-------------------------------------- tell():
To return current position of the cursor(file pointer) from the
beginning of the file.
[can u please tell current position]

f = open('[Link]','r')
print([Link]()) print([Link](3))
print([Link]())
seek():
To move cursor(file pointer) to specified location.
[can u please seek the cursor to a particular location]
data = 'All Students Are BAD' f
= open('[Link]','w')
[Link](data) with
open('[Link]','r+') as f:
text = [Link]()
print(text)
print('The current position:',[Link]())
[Link](17)
print('The current position:',[Link]())
[Link]('GEMS!!!!!')
[Link](0)
text = [Link]()
print('Data after modification:')
print(text)

How to check a particular file exists of not?


-----------------------------------------------------------------
-->We can use os library to get information ablout file in our computer.
-->os has path module, which contains isfile() function to check whether
a particular file exist of not?
Syn:
[Link](filename)

w.a.p to check whether the given file exist or not. If it is available


then print its content.
import
os,sys
fname = input('Enter File Name:')
if [Link](fname):
print('File
Exist:',fname) f =
open(fname,'r') else:
print('File Does Not Exist:',fname)
[Link](0)
print('The content of file is:')
data = [Link]() print(data)

w.a.p to print number of lines,words and characters in the given file? --


-----------------------------------------------------------------------
------------------------------ import
os,sys
fname = input('Enter File Name:') if
[Link](fname):
print('File
Exist:',fname) f =
open(fname,'r') else:
print('File Does Not Exist:',fname)
[Link](0)
lcount = ccount = wcount = 0 for
line in f:
lcount += 1
ccount += len(line)
words = [Link]()
wcount += len(words)
print('The number of lines:',lcount) print('The
number of characters:',ccount) print('The
number of words:',wcount)

Handling binary files


--------------------------------
w.a.p to read image file and write to a new image file.
f1 = open('[Link]','rb') f2
= open('[Link]','wb')
bytes = [Link]()
[Link](bytes)
print('New image is available with the name:[Link]')

Handling CSV files:


-----------------------------
CSV==>Comma Separated Values
To handle CSV files python provides module:csv
Writting data to csv file:
------------------------------------
import csv with
open('[Link]','w',newline='') as f:
w = [Link](f)#Returns csv writer object pointing to
f [Link](['ENO','ENAME','ESAL','EADDR']) n =
int(input('Enter number of employees:')) for i in
range(n): eno = input('Enter Employee No:')
ename = input('Enter Employee Name:') esal =
input('Enter Employee Salary:') eaddr = input('Enter
Employee Address:') [Link]([eno,ename,esal,eaddr])
print('Total employees data written to csv file............')
Reading data from the csv file:
----------------------------------------------
import csv f = open('[Link]','r')
r = [Link](f)#Returns csv reader object
print(type(r)) data = list(r)
print(type(data)) for line in data: for
word in line:
print(word,'\t',end='') print()

Zipping and Unzipping files:


------------------------------------------ -->The
main advantages of zipping are:
[Link] improve memory utilization.
[Link] can reduce transport time.
[Link] can improve performance.
-->To perform zip and unzip operations, python contains one in-built
module zipfile. This module contains ZipFile class.

To create a zip file:


----------------------------
-->We have to create ZipFile class object with name of the zip file, mode
and constant ZIP_DEFLATED. This constant represents we are creating zip
file.
f =
ZipFile('[Link]','w',ZIP_DEFLATED)
-->Once we created ZIpFile object, we can add files by using write()
method.
[Link](filename)
Ex: from zipfile
import *
f = ZipFile('[Link]','w',ZIP_DEFLATED)
[Link]('[Link]')
[Link]('[Link]')
[Link]('[Link]')
[Link]()
print('[Link] file created successfully....')

To perform unzip operation:


----------------------------------------- -->We
have to create ZipFile object as:
f = ZipFile('[Link]','w',ZIP_STORED)
-->ZIP_STORED represents unzip operation. This is default value and hence
we are not required to specify.
-->Once we created ZipFile object for unzip operation, we can get all
file names present in that zip file by using namelist() method.
names = [Link]()
Ex: from zipfile
import *
f = ZipFile('[Link]','r',ZIP_STORED)
[Link]() names
= [Link]()
print(names) for
name in names:
print('File Name:',name)
print('The content in the file is:')
f1 = open(name,'r')
print([Link]())
print()

Working with directories:


--------------------------------------
1).To know current working directory
2).To create a new directory
3).To remove an existing directory
4).To rename a directory
5).To list contents of the directory..........

-->To perform these operations python provide module:os, which contains


several methods to perform directory related operations.

1).getcwd():To know current working directory.


2).mkdir():To create a sub directory in the current working directory.
3).makedirs():To create multiple directories.
4).rmdir():To remove a directory.
5).removedirs():To remove multiple sub directories.
6).rename():To rename a directory.
7).listdir():To know the content of directory.
Ex:
import os
print([Link]('.'))

-->The above program displays contents of current working directory but


not contents of sub directories.
-->If we want to content of a directory including sub directories then we
should go for walk() function. Ex:
import os for dirpath,dirnames,filenames in
[Link]('.'):
print('Current dir path:',dirpath)
print('Directories:',dirnames)
print('Files:',filenames)
print()

[Link] is the difference between listdir() and walk() functions?


-------------------------------------------------------------------------
--------------------
In case of listdir(), we will get contents of specified directory but not
sub directory contents. But in the case of walk() function we will get
contents of specified directory and it's sub directories also.

Running other programs from the python program:


-------------------------------------------------------------------------
---
-->os has system() function to run the programs and commands.
[Link]('command string')
Ex:
import os [Link]('dir
*.py') [Link]('py
[Link]') How to get
information about a
file:
------------------------------------------------------
We can get statistics of a file like size, last accessed time, last
modified time etc... by using stat() function of os module. Ex:
import os
stats = [Link]('[Link]') print(stats) Note: st_atime,st_mtime and
st_ctime returns the time as number of milliseconds since Jan 1st 1970,
12:00AM(Epoche Time Standard). By using datetime module fromtimestamp()
function, we can get exact date and time.
Ex:
import os from datetime
import * stats =
[Link]('[Link]')
print('File size in bytes:',stats.st_size)
print('File last accesses time:',[Link](stats.st_atime))
print('File last modifies time:',[Link](stats.st_mtime))
Pickling and Unpickling of objects
---------------------------------------------------

Python's Object Oriented Programming(OOP's)


---------------------------------------------------------------------
What is a class?
-----------------------
-->In python every thing is an object. To create objects we required some
model or plan or blue print, which is nothing but a class.
-->We can write a class to represent properties(attributes) and actions
(behaviour) of
an object.
-->Properties can be represented by variables.
-->Actions can be represented by methods.
-->Hence class contains both variables and methods.

How to define a class?


--------------------------------- Syn:
class ClassName:
'''documentation string'''
variables:Instance,Static and Local
methods:Instance,Static and class methods

-->Documentation string represents description of the class. Within the


class doc string is always optional. We can get doc string by using 2-
ways.
1).print(ClassName.__doc__)
2).help(ClassName)
Ex:
class Student:
'''This is student class with required
data''' print(Student.__doc__) help(Student)

What is an object?
Physical existance of class is nothing but object. We can create
any number of objects for a class.
Syn:
Ref variable = ClassName()
Ex:
s = Student()

What is a reference variable?


------------------------------------------
-->The variable which can be used to refer an object is called as
reference variable.
-->By using reference variable, we can access properties and methods of
an object. Ex:
w.a.p to create a Student class and create an object to it. Display
the student details.
class Student: def
__init__(self,name,rollno,marks):#Constructor
[Link] = name [Link] = rollno
[Link] = marks def display(self):
print('Hello My Name Is:',[Link])
print('My Roll No:',[Link])
print('My Marks Are:',[Link])
s = Student('Sunny',102,98)
[Link]() self
variable: ---------
----------
-->self is a default variable which is always pointing to current
object(like this keyword in java).
-->By using self we can access instance variables and instance methods of
object.
Note:
-------
1. self should be first parameter inside constructor.
def __init__(self):
[Link] should be first parameter inside instance methods.
def display(self):

Constructor Concept:
--------------------------------
-->Constructor is a special method in python.
-->The name of the constructor should be __init__(self).
-->Constructor will be executed automatically at the time of object
creation.
-->The main purpose of constructor is to declare and initialize instance
variables.
-->Per object constructor will be executed once.
-->Constructor can take atleast one argument(self).
-->Constructor is an optional.
Constructor will be executed only once per object
-------------------------------------------------------------------------
-- class Test: def __init__(self):
print('Constructor execution.....') def
m1(self): print('Method
execution.....') t1 = Test() t2 = Test() t3 =
Test() t1.m1()

How to create list of objects in constructor:


-----------------------------------------------------------------
class Movie: def __init__(self,name,hero,heroine,rating):
[Link] = name [Link] = hero
[Link] = heroine [Link] = rating def
info(self):
print('Movie Name:',[Link])
print('Hero Name:',[Link])
print('Heroine Name:',[Link])
print('Movie Rating:',[Link]) print()
movies = [Movie('OG','Pawan Kalyan','Priyanka',4),
Movie('Devara','[Link] ','Jahnavi',4),Movie('Aashiqui-3','Mahesh','Sunny
Leone',9)] for movie in movies: [Link]()
without
constructor:
-------------------------------
class Movie: def
info(self):
print('Movie Name:',[Link])
print('Hero Name:',[Link])
print('Heroine Name:',[Link])
print('Movie Rating:',[Link])
m = Movie()
[Link] = 'Kalki'
[Link] = 'Prabhas'
[Link] = 'Deepika'
[Link] = 4
[Link]() with
normal method:
------------------------------- class Movie:
def v_d(self,name,hero,heroine,rating):
[Link] = name [Link] = hero
[Link] = heroine
[Link] = rating def info(self):
print('Movie Name:',[Link])
print('Hero Name:',[Link])
print('Heroine Name:',[Link])
print('Movie Rating:',[Link])
m = Movie()
m.v_d('Game Changer','Ram Charan','Jahnavi',4)
[Link]()

[Link] between method and constructor?


----------------------------------------------------------------------
Method
Constructor
-----------
------------------
[Link] of the method can be any name. [Link] name should be
__init__().

[Link] will be execited, if we call that [Link] will be


executed
method.
automatically at the time of object

creation.

[Link] object, method can be called any will [Link] object, constructor
be
number of times.
executed only once.

[Link] method we have to declare [Link] constructor


we can write and
business logic.
initialize instance variables.

Types of variables:
[Link] variables(Object level variables)
[Link] variables(Class level variables)
[Link] variables(Method level variables)

[Link] variable:
-----------------------------
If the value of the variable is varied from object to object then such
type of variables are called as instance variables.
For every object a separate copy of instance variables will be created.

Where we can declare instance variables?


-------------------------------------------------------------
[Link] constructor:
-------------------------------
We can declare instance variables inside a constructor by using self.
Once we create the object, automatically these variables will be added to
the object.
class Employee:
def __init__(self):
[Link] = 101
[Link] =
'Mahesh' e = Employee()
print(e.__dict__)

[Link] instance method:


---------------------------------------
We can also declare instance variables inside method by using self.
If any instance variables declared inside instance method, that instance
variable will be added once we call that method.
class Test: def
__init__(self):
self.a = 10
self.b = 20 def
m1(self):
self.c = 30
t = Test()
t.m1()
print(t.__dict__)

[Link] of the class:


----------------------------------
We can also add instance variables outside of a class to a particular
object. class Test:
pass
t = Test()
t.a = 10
t.b = 20
print(t.__dict__)
Types of variables:
[Link] variables(Object level variables)
[Link] variables(Class level variables)
[Link] variables(Method level variables)

How to access instance variables:


--------------------------------------------------
We can access instance variables within the class by using self and
outside of the class by using object reference.
class Test: def
__init__(self):
self.a = 10
self.b = 20
def m1(self):
print(self.a)
print(self.b) t = Test()
t.m1() print(t.a,t.b)

How to delete instance variable from the object


-----------------------------------------------------------------------
[Link] a class we can delete instance variables by using self.
del self.variable_name

[Link] outside of class we can delete instance variables by using object


reference.
del objreference.variable_name
Ex:
class Test:
def __init__(self):
self.a = 10
self.b = 20
self.c = 30
def m1(self):
del self.c
t = Test()
print(t.__dict__)
t.m1()
print(t.__dict__) del
t.b
print(t.__dict__)
Note:
The instance variables which are deleted from one object, will not
be deleted from other object.
class Test: def
__init__(self):
self.a = 10
self.b = 20
self.c = 30
t1 = Test() t2 = Test()
del t1.a
print(t1.__dict__)
print(t2.__dict__)

-->If we change the values of instance variables of one object then those
changes wont be reflected to the remaining objects, because for every
object we have separate copy of instance variables are available.
class Test: def
__init__(self):
self.a = 10
self.b = 20
t1 = Test() t1.a = 333
t1.b = 999 t2 = Test()
print('t1:',t1.a,t1.b)#333 999 print('t2:',t2.a,t2.b)#10
20

[Link] variables:
---------------------------
-->If the value of a variable is not varied from object to object, such
type of variables we have to declare within the class directly but from
outside of methods. Such type of variables are called as static
variables.
-->For total class only one copy of static variable will be created and
shared by all the objects of that class.
-->We can access static variables either by ClassName or by object
reference. But recommended to use Classname.

Instance variables vs Static variables:


--------------------------------------------------------
In case of instance variables for every object a separate copy will be
created, but in the case of static variables for total class only one
copy will be created and shared by every object of that class.
class
Test:
x = 10
def __init__(self):
self.y = 20
t1 = Test() t2 = Test()
print('t1:',t1.x,t1.y)#10 20
print('t2:',t2.x,t2.y)#10 20
Test.x = 333 t1.y = 999
print('t1:',t1.x,t1.y)#333 999 print('t2:',t2.x,t2.y)#333
20

Various places to declare static variables:


--------------------------------------------------------------
[Link] general we can declare within the class directly but from out side
of any method.
[Link] constructor by using ClassName.
[Link] instance method by using ClassName.
[Link] classmethod by using cls variable or ClassName.
[Link] staticmethod by using ClassName.
[Link] of the class by using ClassName.
class Test:
a = 10
def __init__(self):
Test.b = 20
def m1(self):
Test.c = 30
@classmethod
def m2(cls):
cls.d1 = 40
Test.d2 = 50
@staticmethod def
m3():
Test.e = 60
t = Test()
t.m1()
t.m2()
t.m3() Test.f = 70
print(Test.__dict__)

How to access static variables:


----------------------------------------------
[Link] constructor:By using either self or ClassName.
[Link] instance method:By using either self or classname.
[Link] classmethod:By using cls or classname.
[Link] static method:By using classname
[Link] of the class:By using either obj reference or classname.
class Test: a = 10 def __init__(self):
print(Test.a) print(self.a) def m1(self):
print(Test.a) print(self.a) @classmethod def
m2(cls): print(Test.a) print(cls.a)
@staticmethod def m3(): print(Test.a) t = Test()
t.m1()
t.m2()
t.m3() print(Test.a)
Where we can modify
the value of static
variables:
-------------------------------------------------------------------------
-
Any where either within the class or outside of class we can modify by
using ClassName. But inside classmethod, by using cls variable.
class
Test:
a = 333
@classmethod
def m1(cls):
cls.a = 666
@staticmethod
def m2(): Test.a
= 999 print(Test.a)
Test.m1() print(Test.a)
Test.m2() print(Test.a)

-->If we change the value of static variable by using either self or


object reference variable, then the value of static variable wont be
changed, just a new instance variable with that name will be added to
that particular object.
class
Test:
a = 10 def
m1(self): self.a
= 333 t = Test()
t.m1()
print(Test.a)
print(t.a)
Ex:
class Test:
x = 10 def
__init__(self):
self.y = 20
t1 = Test() t2 = Test()
print('t1:',t1.x,t1.y)
print('t2:',t2.x,t2.y)
t1.x = 333 t1.y = 999
print('t1:',t1.x,t1.y)#333 999
print('t2:',t2.x,t2.y)#10 20
Ex:
class Test:
a = 10 def
__init__(self):
self.b = 20
@classmethod
def m1(cls):
cls.a = 333
cls.b = 999 t1 =
Test() t2 = Test()
t1.m1()
print('t1:',t1.a,t1.b)
#333 20
print('t2:',t2.a,t2.b)
#333 20
print(Test.a,Test.b)#333 999

How to delete static variable:


-------------------------------------------
We can delete static variables from anywhere by using ClassName.
del [Link]
But inside classmethid we can also use cls variable.
del [Link]
Ex:
class Test:
a = 10
@classmethod
def m1(cls):
del cls.a
Test.m1()
print(Test.__dict__)
Note:
By using object reference variable/self we can read static
variables, but we cannot modify or delete.
If we are trying to modify, then a new instance variable will be
added to that particular object. t.a = 100
If we are trying to delete then we will get error.
class
Test:
a = 10
t = Test()
del t.a ==>AttributeError: a

-->We can modify or delete static variables only by using ClassName or


cls variable.
import sys class
Customer:
'''Customer class with bank operations.....'''
bank_name = 'SunnyBank' def
__init__(self,name,balance=0.0): [Link] = name
[Link] = balance def deposit(self,amt):
[Link] = [Link] + amt def withdraw(self,amt):
if amt > [Link]:
print("Insufficinet funds....can't perform this operation")
[Link]()
[Link] = [Link] - amt
print('Balance after withdraw:',[Link])
print('Welcome To',Customer.bank_name)
name = input('Enter your name:') c =
Customer(name) while True:
print('d-Deposit\nw-Withdraw\ne-Exit')
option = input('Enter your option:') if
option == 'd' or option == 'D':
amt = float(input('Enter
amount:')) [Link](amt) elif
option == 'w' or option == 'W': amt =
float(input('Enter amount:'))
[Link](amt) elif option == 'e' or option
== 'E':
print('Thanks for
Banking!!!!!!!!!!!!') [Link]()
else:
print('Invalid option...Pls choose a valid option')

3).Local variables:
---------------------------
-->Sometimes to meet temporary requirements of programmer, we can declare
variables inside a method directly, such type of variables are called as
local variables or temporary variables.
-->Local variables will be created at the time of method execution and
destroyed once method completes.
-->Local variables of a method cannot be a cessed from outside of method.
Ex:
class Test:
def m1(self):
a = 1000
print(a) def
m2(self): b
= 2000
print(b)
print(a)#NameError: name 'a' is not defined
t = Test()
t.m1()
t.m2()

Types of methods:
---------------------------
[Link] methods
[Link] methods
[Link] methods
[Link] methods:
------------------------------
-->Inside method implementation if we are using instance variables then
such type of methods are called as instance methods. Inaise instance
method declaration, we have to pass self variable.
def m1(self):pass
-->By using self variable inside mthod we can able to acccess instance
variables.
-->Within the class we can call instance method by using self variable
and from outside of the class we can call by using object reference.
Ex: ----- class Student: def
__init__(self,name,marks):
[Link] = name
[Link] = marks def
display(self):
print('Hi',[Link])
print('Your marks are:',[Link]) def
grade(self): if [Link] >= 60:
print('You got First Grade')
elif [Link] >= 50:
print('You got Second Grade') elif
[Link] >= 35:
print('You got Third Grade')
else:
print('Congrats you are
failed......') n = int(input('Enter number of
students:')) for i in range(n):
name = input('Enter Name:')
marks = int(input('Enter Marks:'))
s = Student(name,marks) [Link]()
[Link]()
print()

Setter and Getter methods:


-----------------------------------------
-->We can set and get the values of instance variables by using getter
and setter methods.

Setter method:
Setter method can be used to set values to the instance variables.
Setter method also known as mutator methods.
Syn: def
set_variable(self,variable):
[Link] = variable

Getter method:
Getter method can be used to get values of the instance variables.
Getter methods also known as accessor methods.
Syn: def
get_variable(self):
return [Link]
Ex:
class Student:
def set_name(self,name):
[Link] = name def
get_name(self): return
[Link] def
set_marks(self,marks):
[Link] = marks def
get_marks(self):
return [Link] l = [ ]
n = int(input('Enter number of students:')) for
i in range(n):
s = Student() name =
input('Enter Name:')
s.set_name(name)
marks = int(input('Enter Marks:'))
s.set_marks(marks)
[Link](s)
for s in
l:
print('Student Name:',s.get_name())
print('Student Marks:',s.get_marks())
print()

[Link] methods:
--------------------------
-->Inside method implementation if we are using only class
variables(static variables) then such type of methods we should declare
as class methods.
-->We can declare class method explicitly by using @classmethod
decorator. For classmethod we should provide cls variable at the time of
declaration.
-->We can call classmethod by using classname or object reference
variable. class Animal:
legs = 4 @classmethod def walk(cls,name):
print("{} walks with {} legs.....".format(name,[Link]))
[Link]('Dog')
[Link]('Cat')

w.a.p to track the number of objects created for a class?


-------------------------------------------------------------------------
----------- class
Test:
count = 0 def
__init__(self):
[Link] += 1 @classmethod def
no_of_objects(cls): print('The number of
objects created for Test class:',[Link]) t1 = Test()
t2 = Test() Test.no_of_objects() t3 = Test() t4 = Test()
Test.no_of_objects()

[Link] methods:
--------------------------
-->In general these methods are general utility methods. Inside these
methods we wont use any instance or class variables. Here we wont provide
self or cls args at the time of declaration.
-->We can declare static method explicitly by using @staticmethod
decorator we can access static methods by using classname or object
reference.
Note:
-->In general we can use only instance and static
methods. -->class methods are rarely used methods in python.
Ex:
class MaheshMath:
@staticmethod def add(x,y):
print('The sum is:',x+y)
@staticmethod def
product(x,y): print('The
product is:',x*y)
@staticmethod def average(x,y):
print('The average is:',(x+y)/2)
[Link](10,20)
[Link](10,20)
[Link](10,20)

How to pass members of one class to another class?


-------------------------------------------------------------------------
----
We can access members of one class inside another class.
class Employee: def
__init__(self,eno,ename,esal):
[Link] = eno [Link] = ename
[Link] = esal def display(self):
print('Employee Number:',[Link])
print('Employee Name:',[Link])
print('Employee Salary:',[Link]) class
Test: def modify(emp):
[Link] += 8000 [Link]()
e = Employee(101,'Sunny',12000)
[Link](e)

Inner classes:
--------------------
-->Sometimes we can declare a class inside another class, such type of
classes are called as inner classes.
-->Without existing one type of object if there is no chance of existing
another type of object, then we should go for inner classes.

Ex-1: Without existing Car object there is no chance of existing Engine


object. Hence Engine class should be part of Car class.
class Car:
class Engine:

Ex-2:Without existing University object there is no chance of existing


Department object.
class University:
class Department:

Ex-3:Without existing Human there is no chance of existing Head. Without


Head there is no Brain.
class Human:
class Head:
class Brain:

Note:
Without existing outer class object there is no chance of existing inner
class object. Hence inner class object is always associated with outer
class object. Ex:
class Outer: def __init__(self):
print('Outer class object creation') class Inner:
def __init__(self): print('Inner
class object creation') def m1(self):
print('Inner class method')
o = Outer() i
= [Link]()
i.m1()
or
i = Outer().Inner()
i.m1()
or
Outer().Inner().m1()
Ex: ---- class Human:
def __init__(self):
[Link] = 'Sunny'
[Link] = [Link]()
[Link] =
[Link]()
def display(self):
print('Hello',[Link])
[Link]()
[Link]()

class Head:
def talk(self):
print('Talking...............')

class Brain:
def think(self):
print('Thinking????????')
h =
Human()
[Link]()
Nested Methods:
-------------------------
Nested method:A method inside the method.
Purpose:To define method specific required functionality.
Ex:
class Test: def m1(self):
def calc(a,b):
print('Sum is:',a+b)
print('Product is:',a*b)
print()
calc(10,20)
calc(20,30)
calc(30,40) t = Test()
t.m1()

Garbage Collection:
=================
-->In old languages like C++, programmer is responsible for both creation
and destruction of objects. Usually programmer taking very much care
while creating objects, but neglecting destruction of useless objects.
Because of this, total memory can be filled with useless objects which
creates memory problems and total application will be down with 'out of
memory error'.

-->But in python, we have some assistant which is always running in the


background to destroy useless objects. Because of this assistant the
chance of failing python program with memory problems is very less. This
assistant is nothing but Garbage Collector(GC).

-->The main objective of GC is to destroy useless objects.

-->If an object does not have any reference variable then that object is
eligible for GC.

How to enable and disable GC in our program?


---------------------------------------------------------------------
Bydefault GC is enabled, but we can disable based on our requirement. In
this context we can use the function of gc module. Ex:
import gc class
Test:
print([Link]())#True
[Link]() print([Link]())#False
[Link]()
print([Link]())#True

Destructor:
----------------
-->Destructor is a special method and name should be __del__(). -->Just
before destroying an object GC calls destructor to perform clean up
activities(Resource deallocation activities like close database
connection etc...)
-->Once destructor execution completed then GC automatically destroys
that object.

Note:
The job of destructor is not to destroy object and it is just
to perform clean up activities. Ex: import time class Test: def
__init__(self): print('Object initialization.....') def
__del__(self): print('Fullfilling last wish and performing
clean up activities......') t = Test() t = None [Link](10)
print('End of application')
Note:
If the object does not contain any reference variable then only it is
eligible for GC. i.e if the reference count is zero then only object
eligible for GC. Ex: import time class Test:
def __init__(self):
print('Constructor Execution.....') def
__del__(self):
print('Destructor
Execution.....') list =
[Test(),Test(),Test()] del list
[Link](10)
print('End of application')

How to find the number of references of an object?


-------------------------------------------------------------------------
---
sys module contains getrefcount() function to find number of ref. Syn:
[Link](object reference)
Ex:
import sys class
Test:
pass
t1 = Test()
t2 = t1 t3
= t1 t4 =
t1
print([Link](t1)) #5

Note:For every object, python internally maintains one default reference


variable self.

OOP's PART-2:
============= Agenda:
-->Inheritance
-->Has-A Relationship
-->IS-A Relationship
-->IS-A vs HAS-A Relationship
-->Composition vs Aggregation
-->Types of inheritance:
-->single
-->multi-level
-->hierarchial
-->multiple
-->hybrid
-->MRO(Method Resolution Order)
-->super() method

Using members of one class to another class:


------------------------------------------------------------------- [Link]
Composition(Has-A Relationship):
----------------------------------------------------------
-->By using ClassName or by creating object we can access members of one
class inside another class is nothing but composition(Has-A Relationship)
-->The main advantage of Has-A rerlationship is code re-usability. Ex:
class X:
a = 10 def
__init__(self):
self.b = 20 def
m1(self):
print('m1 method of X class')
class Y:
c = 30
def __init__(self):
self.d = 40
def m2(self): print('m2 method of
Y class') def m3(self): x = X()#Y
class Has-A X-class object
print(x.a) print(x.b)
x.m1() print(Y.c)
print(self.d)
self.m2()
print('m3 method of Y
class') y1 = Y() y1.m3()

Ex: ----- class Car: def


__init__(self,name,model,color):
[Link] = name [Link] =
model [Link] = color
def get_info(self): print('Car
Name:{},Model:{},Color:{}'.format([Link],[Link],[Link]))
class Employee: def
__init__(self,name,eno,car):
[Link] = name [Link] = eno
[Link] = car def emp_info(self):
print('Employee Name:',[Link])
print('Employee Number:',[Link])
print('Employee Car Info:')
[Link].get_info()
c = Car('KIA','CARENS','BLACK') e
= Employee('Mahesh',101,c)
e.emp_info()

-->In the above example Employee Has-A car reference and hence Employee
class can access all members of Car class.

2).By Inheritance(IS-A Relationship):


------------------------------------------------------
-->Whatever variables, methods and constructors available in the parent
class bydefault available to the child classes and we are not required to
re-write.
-->Hence the main advantage of inheritance is code reusability and we can
extend existing functionality with some more extra functionality.
Syn:
class ChildClass(ParentClass)
Ex:
class P:
a = 10 def __init__(self):
self.b = 20
def m1(self): print('Parent
instance method')
@classmethod def m2(cls):
print('Parent class method')
@staticmethod
def m3():
print('Parent static method')
class
C(P):
pass
c = C()
print(c.a)
print(c.b)
c.m1()
c.m2()
c.m3()
Ex: ----- class P: def m1(self):
print('Parent class method')
class C(P): def m2(self):
print('Child class method') c = C()
c.m1()
c.m2()

-->Similarly variables also


class
P:
a = 10 def
__init__(self):
self.b = 20 class C(P):
c = 30 def __init__(self):
super().__init__()===>Line-1
self.d = 40
c1 = C()
print(c1.a,c1.b,c1.c,c1.d)

-->If we comment Line-1 then variable 'b' is not available to the child
class.
Ex: ----- class Person: def
__init__(self,name,age): [Link] =
name [Link] = age def
eat_n_drink(self): print('Drink beer
and eat biryani')
class Employee(Person): def
__init__(self,name,age,eno,sal):
super().__init__(name,age)
[Link] = eno [Link] = sal
def work(self):
print('Coding python is very easy just like drinking
chilled water') def emp_info(self): print('Employee
Name:',[Link]) print('Employee Age:',[Link])
print('Employee Number:',[Link]) print('Employee
Salary:',[Link]) e = Employee('Sunny',25,102,12000)
e.eat_n_drink()
[Link]()
e.emp_info()

IS-A vs HAS-A Relationship:


-----------------------------------------
-->If we want to extend existing functionality with some more extra
functionality then we should go for IS-A relationship.

-->If we dont want to extend and just we have to use existing


functionality then we should go for HAS-A relationship.
Ex:
Employee class extends Person functionality.
But Employee class just uses Car functionality but not
extending. Ex:
class Car: def __init__(self,name,model,color):
[Link] = name [Link] = model
[Link] = color def get_info(self):
print('\tCar Name:{}\n\tModel:{}\n\tColor:{}'
.format([Link],[Link],[Link]))
class
Person:
def
__init__(self,name,age):
[Link] = name
[Link] = age def
eat_n_drink(self):
print('Drink beer and eat biryani')
class
Employee(Person):
def __init__(self,name,age,eno,sal,car):

super().__init__(name,age)
[Link] = eno [Link] = sal
[Link] = car def
work(self):
print('Coding python is very easy just like drinking chilled water')
def emp_info(self):
print('Employee Name:',[Link])
print('Employee Age:',[Link]) print('Employee
Number:',[Link]) print('Employee
Salary:',[Link]) print('Employee Car Info:')
[Link].get_info()

c = Car('KIA','CARENS','BLACK') e =
Employee('Sunny',25,102,12000,c)
e.eat_n_drink()
[Link]()
e.emp_info()

Composition vs Aggregation:
-------------------------------------------
Composition:
-------------------
-->Without existing container object if there is no chance of existing
contained object then the container and contained objects are strongly
associated and that strong association is nothing but Composition.
Ex:
University contains several Departments and without existing
University object there is no chance of existing Department object. Hence
University and Department objects are strongly associated and this strong
association is nothing but Composition.

2).Aggregation:
-----------------------
-->Without existing container object if there is a chance of existing
contained object then the container and contained objects are weakly
associated and that weak association is nothing but Aggregation.
Ex:
Department contains several Professors. Without existing Department still
there may be a chance of existing Professor. Hence Department and Professor
objects are weakly associated, which is nothing but Aggregation. Ex:
class Student:
college_name = 'NARESH
IT' def __init__(self,name):
[Link] = name
print(Student.college_name) s =
Student('Sunny') print([Link])

-->In the above example without existing Student object there is no


chance of existing his name. Hence Student object and his name are
strongly associated which is nothing but Composition.

-->But without existing Student object there may be a chance of existing


college_name. Hence Student object and college_name are weakly associated
which is nothing but Aggregation.

Conclusion:
The relation between object and its instance variables is always
Composition where as the relation between object and static variables is
Aggregation.
Note:
Whenever we are creating child class object then child class
constructor will be executed. If the child class does not contain
constructor then parent class constructor will be executed, but parent
object wont be created. Ex:
class P: def
__init__(self):
print(id(self)) class
C(P):
pass
c = C()
print(id(c)
) Ex:
class Person: def __init__(self,name,age):
[Link] = name [Link] =
age class Student(Person): def
__init__(self,name,age,rollno,marks):
super().__init__(name,age) [Link] =
rollno [Link] = marks def __str__(self):
return 'Name:{}\nAge:{}\nRollNo:{}\nMarks:{}'
.format([Link],[Link],[Link],[Link]) s =
Student('Sunny',23,102,98) print(s)
Types of Inheritances:
--------------------------------- 1).Single
Inheritance:
The concept of inheriting the properties from one class to
another class is known as single inheritance. Ex:
class P: def m1(self):
print('Parent Method') class
C(P): def m2(self):
print('Child Method') c = C()
c.m1()
c.m2()

2).Multi Level Inheritance:


The concept of inheriting the properties from multiple classes to
single class with the concept of one after another is known as multilevel
inheritance.
class P: def m1(self):
print('Parent Method') class C(P):
def m2(self): print('Child
Method') class CC(C): def
m3(self): print('Sub Child
Method') c = CC()
c.m1()
c.m2()
c.m3()

3).Hierarchial Inheritance:
The concept of inheriting the properties from one class into a
multiple classes which are present at same level is known as hierarchial
inheritance.
Ex:
class P: def m1(self):
print('Parent Method') class
C1(P): def m2(self):
print('Child-1 Method') class
C2(P): def m3(self):
print('Child-2 Method') c1 = C1()
c1.m1() c1.m2() c2 = C2() c2.m1()
c2.m3()

4).Multiple Inheritance:
The concept of inheriting the properties from multiple classes into
a single class at a time, is known as multiple inheritance. Ex:
class P1: def m1(self):
print('Parent-1 Method') class P2:
def m2(self):
print('Parent-2 Method') class
C(P1,P2): def m3(self):
print('Child
Method') c = C() c.m1()
c.m2()
c.m3()

-->If same methods is inherited from both parent classes, then python
will always consider the order of parent classes in the declaration of
child class.
class C(P1,P2):===>P1 method will be considered
class C(P2,P1):===>P2 method will be considered
5).Hybrid Inheritance:
---------------------------------
Cpmbination of single,multi level, multiple and hierarchial
inheritance is known as hybrid inheritance.

Method Resolution Order(MRO):


-----------------------------------------------
-->In hybrid inheritance the mmethod resolution order is decided based on
MRO algorithm.
-->This algorithm is also known as C3 algorithm. -->Samuele
Pedroni proposed this algorithm.
-->It follows DLR(Depth First Left to Right)
-->i.e child will get more priority than parent.
-->Left parent will get more priority than right parent.

MRO(X)=X + Merge(MRO(p1),MRO(P2),....ParentList)

Head element vs Tail Terminology:


----------------------------------------------------- Assume
C1,C2,C3......are classes
In the list:C1C2C3C4C5........
C1 is considered as Head element and remaining is considered as Tail.

How to find Merge:


----------------------------
-->Take the head of first list.
-->If the head is not in the tail part of any other list, then add this
head to the result and remove it from the lists in the merge. -->If the
head is present in the tail part of any other list, then consider the
head element of the next list and continue the same process.

Note:We can find MRO of any class by using mro() function


print([Link]())

Ex-1: -------
mro(A)=A,object
mro(B)=B,A,object
mro(C)=C,A,object
mro(D)=D,B,C,A,object
[Link] --------
--- class A:pass
class B(A):pass
class C(A):pass
class D(B,C):pass
print([Link]())
Ex-2:
-------
mro(A)=A,object
mro(B)=B,object
mro(C)=C,object
mro(X)=X,A,B,object
mro(Y)=Y,B,C,object
mro(P)=
Finding mro(P) by using C3 algorithm:
---------------------------------------------------------
MRO(X)=X + Merge(MRO(p1),MRO(P2),....ParentList)

mro(P) =P + Merge(mro(X),mro(Y),mro(C),XYC)
=P + Merge(XABO,YBCO,CO,XYC)
=P + X + Merge(ABO,YBCO,CO,YC)
=P + X + A + Merge(BO,YBCO,CO,YC)
=P + X + A + Y + Merge(BO,BCO,CO,C)
=P + X + A + Y + B + Merge(O,CO,CO,C)
=P + X + A + Y + B + C + Merge(O,O,O)
=P + X + A + Y + B + C + O
[Link] ----------
class A:pass class
B:pass class C:pass
class X(A,B):pass
class Y(B,C):pass
class P(X,Y,C):pass
print([Link]())
Ex-3: --------
mro(D)=D,object
mro(E)=E,object
mro(F)=F,object
mro(B)=B,D,E,object
mro(C)=C,D,F,object
mro(A)=A,B,C,D,E,F,object

mro(A) =A+Merge(mro(B),mro(C),BC)
=A+Merge(BDEO,CDFO,BC)
=A+B+Merge(DEO,CDFO,C)
=A+B+C+Merge(DEO,DFO)
=A+B+C+D+Merge(EO,FO)
=A+B+C+D+E+Merge(O,FO)
=A+B+C+D+E+F+O
[Link] --------
-- class D:pass
class E:pass
class F:pass
class B(D,E):pass
class C(D,F):pass
class A(B,C):pass
print([Link]())
super() method: ------
-----------------
super() is a built-in method which is useful to call the
super class constructor, variables and methods from the child
class. Ex:
class P:
a = 10 def
__init__(self):
self.b = 20
def m1(self):
print('Parent instance method')
@classmethod def m2(cls):
print('Parent class method')
@staticmethod def m3():
print('Parent static method') class
C(P):
a = 333 def
__init__(self):
super().__init__()
print(super().a)
super().m1()
super().m2()
super().m3() c = C()
Note:
From child class we are not allowed to access parent class instance
variables by using super(), we should use self only. But we can access
parent class static variables by using super() method.
class
P:
a = 10 def
__init__(self):
self.b = 20
class C(P): def
m1(self):
print(super().a)
print(self.b)#Valid

print(super().b)#Invalid c = C()
c.m1()
Types of Exceptions: ==================
1).Predefined exception
2).User defined exception

1).Predefined exceptions:
-------------------------------------
-->Also knonw as ibuilt exceptions.
-->The exceptions which are raised automatically by PVM whenever a
particular event occurs, are called as predefined exceptions.
Ex:
ZeroDivisionError
ValueError
NameError
TypeError

2).User defined exceptions:


----------------------------------------
-->Also known as customized exceptions or programatic exceptions. -->Some
times we have to define and raise exceptions explicitly to indicate that
something goes wrong, such type of exceptions are called as user defined
exceptions or customized exceptions.
-->Programmer is responsible to define these exceptions and python not
having any idea about these. Hence we have to raise explicitly based on
our requirement by using 'raise' keyword.
Ex:
InSufficientFundsException
InvalidInputException
TooYoungException
TooOldException
How to define and raised customized exceptions:
-------------------------------------------------------------------------
-->Every exception in python is a class that extends Exception class
either directly or idirectly. Syn:
class ClassName(Parent Exception
ClassName): def __init__(self,arg):
[Link] = arg
Ex:
class TooYoungException(Exception):
def __init__(self,arg):
[Link] = arg class
TooOldException(Exception):
def __init__(self,arg):
[Link] = arg
age = int(input('Enter Age:')) if age > 60: raise
TooYoungException('Pls wait some more time you will get best match
soon!!!!!!!') elif age < 18: raise TooOldException('Your age
already crossed marriage age...No chance of getting marriage') else:
print('You will get match details soon by email.....')

Pickling and Unpickling of objects: -------------------------------------


---------------
-->Some times we have to write total state of object to the file and we
have to read total object from the file.
-->The process of writing state of object to the file is called as
pickling and the process of reading state of an object from the file is
called as unpickling.
-->We can implement pickling and unpickling by using pickle module.
-->pickle module contains dump() function to perform pickling.
[Link](object,f)
-->pickle module contains load() function to perform unpickling.
[Link](f)
writting and reading state of object by using pickle
module:
-------------------------------------------------------------------------
--------------- import pickle class
Employee: def
__init__(self,eno,ename,eaddr):
[Link] = eno [Link] =
ename [Link] = eaddr
def display(self):
print([Link],'\t',[Link],'\t',[Link])
with open('[Link]','wb') as f:
e = Employee(101,'Sunny','Mumbai')
[Link](e,f)
print('Pickling of employee object completed.....')
with open('[Link]','rb') as f:
obj = [Link](f)
print('Printing employee information after unpickling')
[Link]()

Writing multiple employee objects to the file


------------------------------------------------------------------
[Link] ---------- class Employee:
def __init__(self,eno,ename,eaddr):
[Link] = eno [Link] = ename
[Link] = eaddr def display(self):
print([Link],'\t',[Link],'\t',[Link])
[Link] -----------
import pickle,emp f =
open('[Link]','wb')
n = int(input('Enter the number of employees:')) for
i in range(n):
eno = int(input('Enter Employee
Number:')) ename = input('Enter Employee
Name:') eaddr = input('Enter Employee
Address:') e =
[Link](eno,ename,eaddr)
[Link](e,f)
print('Employee objects pickled successfully.....')
[Link] --
------------
import
emp,pickle f =
open('[Link]'
,'rb')
print('Employe
e Details:')
while True:
try:
obj = [Link](f)
[Link]() except EOFError:
print('All employees completed')
break
[Link]()
Polymorphism:
=============
-->Poly means Many
-->Morphs means Forms
-->Polymorphism means 'Many Forms'

[Link] Typing Philosophy of python [Link]:


-->Operator overloading
-->Method overloading --
>Constructor overloading [Link]:
-->Method overriding
-->Constructor overriding

[Link] Typing Philosophy of python:


--------------------------------------------------------
-->In python we cannot specify the type explicitly.
-->Based on provided value at runtime the type will be considred
automatically.
-->Hence python is considered as Dynamically Typed Programming Language.
def f1(obj):
[Link]()

What is type of obj?


-----------------------------
-->We cannot decide at the beginning. At runtime we can pass any type.
Then how we can decide the type?
-->At runetime if 'it walks like a duck and talks like a duck, it must be
duck'. Python follows this principle. This is called as Duck Typing
Philosophy of python. Ex:
class Duck: def
talk(self):

print('Quack...Quack...') class Dog:


def talk(self):
print('Bow....Bow....') class Cat:
def talk(self):
print('Moew...Moew....') class Goat:
def talk(self):
print('Myaah...Myaah...') def
f1(obj):
[Link]()
l = [Duck(),Dog(),Cat(),Goat()]
for obj in l: f1(obj)

-->The problem in this approach is if obj does not contain talk() method
then we will get AttributeError.
AttributeError: 'Dog' object has no attribute
'talk'
-->But we can solve this problem by using hasattr() function. --
>hasattr(obj,'attributename')
-->attributename can be method name or variable name.
Ex:
class Dog: def bark(self):
print('Bow....Bow....')
class Human: def talk(self):
print('Hello...Hi....') def
f1(obj): if
hasattr(obj,'talk'):
[Link]() elif
hasattr(obj,'bark'):
[Link]() l = [Dog(),Human()] for
obj in l: f1(obj)

Overloading:
-------------------
-->We can use same operator or methods for different purposes.

1).Operator overloading:
------------------------------------
We can use the same operator for multiple purposes, which is
nothing but operator overloading.
Ex:
10 + 20 #30
'10' + '20' #'1020'
Ex:
10 * 20 #200
'10' * 3 #'101010'

Ex:To use + operator for class objects


--------------------------------------------------------
class Book: def __init__(self,pages):
[Link] = pages b1 = Book(100) b2 = Book(200)
print(b1 + b2)

TypeError: unsupported operand type(s) for +: 'Book' and 'Book'

-->We can overload + operator to work with Book objects.


-->For every operator magic methods are available. To overload any
operator we have to override that method in our class.
-->Internally + operator is implemented by using __add__() method. This
method is called magic method for + operator. We have to override this
method in our class.
class Book: def __init__(self,pages):
[Link] = pages def
__add__(self,other): return
[Link] + [Link] b1 = Book(100) b2
= Book(200) print(b1 + b2)

How to add multiple objects:


------------------------------------------- class
Book:
def __init__(self,pages):
[Link] = pages def
__add__(self,other):
print('add method calling')
total = [Link] + [Link]
return Book(total) def __str__(self):
return
str([Link]) b1 = Book(100) b2
= Book(200) b3 = Book(300) bx =
b1 + b2 + b3 #print([Link])
print(bx)
Ex:To overload multiplication operator
----------------------------------------------------------
class Employee: def __init__(self,name,sal):
[Link] = name [Link] = sal def
__mul__(self,other):
return [Link] *
[Link] class TimeSheet: def
__init__(self,name,days):
[Link] = name [Link]
= days def __mul__(self,other):
return [Link] * [Link] e =
Employee('Sunny',800) t =
TimeSheet('Sunny',28) print('This month
salaray:',e * t) print('This month
salaray:',t * e) 2).Method overloading:
----------------------------------
-->If 2-methods having same name but different type of args then those
methods are said to be overloaded methgods.
Ex:
m1(int a)
m1(float f)

-->But in python method overloading is not possible.


-->If we are trying to declare multiple methods with same name and
different number of args then python will always consider only last
method. Ex:
class Test: def m1(self):
print('no-arg method') def
m1(self,a): print('one-
arg method') def m1(self,a,b):
print('two-args method') t =
Test()
t.m1()#Test.m1() missing 2 required positional arguments: 'a' and 'b'
t.m1(10)#Test.m1() missing 1 required positional argument: 'b'
t.m1(10,20)#two-args method

How we can handle overloaded method requirements in python:


-------------------------------------------------------------------------
----------------------
-->Most of the times, if method with multiple number of args required
then we can handle with default args or with variable number of argument
methods. Ex:
class Test:
def sum(self,a=None,b=None,c=None):
if a != None and b != None and c != None:
print('The sum of 3-numbers:',a+b+c) elif a
!= None and b != None:
print('The sum of 2-numbers:',a+b)
else:
print('Please provide 2 or 3 args') t = Test()
[Link](10,20,30)
[Link](10)
[Link]()
[Link](10,20)
Ex:
----
class Test: def
sum(self,*a):
total = 0 for x in
a: total +=
x
print('The
sum:',total) t = Test() [Link]()
[Link](10,20,30,40,50)
[Link](10)
[Link](10,20)

Constructor overloading:
-------------------------------------
-->Constructor overloading is not possible in python.
-->If we define multiple constructors then the last constructor will be
considered.
class Test: def __init__(self):
print('No-arg constructor') def
__init__(self,a): print('One-
arg constructor') def
__init__(self,a,b): print('Two-
args constructor')
t = Test()#Test.__init__() missing 2 required positional arguments: 'a'
and 'b'
t = Test(10)#Test.__init__() missing 1 required positional argument: 'b'
t = Test(10,20)#Two-args constructor

Constructor with default args:


--------------------------------------------- class Test:
def __init__(self,a=None,b=None,c=None):
print('Constructor with 0|1|2|3 number of args') t = Test()
t = Test(10) t = Test(10,20) t = Test(10,20,30)

Constructor with variable number of args:


---------------------------------------------------------------
class Test: def __init__(self,*a):
print('Constructor with variable number of args') t = Test() t
= Test(10) t = Test(10,20)
t = Test(10,20,30,40,50,60)

Method overriding:
----------------------------
-->Whatever members available in the parent class are bydefault available
to the child class through inheritance.
-->If the child class not satisfied with parent class implementation then
child class is allowed to redefine that method in the child class based
on its requirement.
-->This concept is called as overriding.
-->Overriding concept applicable for both methods and constructors.
Ex:
class P: def property(self):
print('Gold + Land + Cash + Power') def
marry(self):
print('Appalamma')
class C(P): def
marry(self):
super().marry()
print('Katrina Kaif') c = C()
[Link]()
[Link]()

-->From the overriding method of child class, we can call parent class
method also by using super() method.

Constructor overriding:
----------------------------------
class P: def __init__(self):
print('Parent constructor') class
C(P): def __init__(self):
super().__init__()
print('Child constructor')
c = C()

-->In the above example, if child class does not contain constructor then
parent class constructor will be executed.

-->From child class constructor we can call parent class constructor by


using super() method.

OOP's PART-4
============ Agenda:
[Link] method
[Link] class
[Link]
[Link],private and protected members
5.__str__() method
[Link] between str() and repr() functions
OOP's PART-4
============ Agenda:
[Link] method
[Link] class
[Link]
[Link],private and protected members
5.__str__() method
[Link] between str() and repr() functions

[Link] method:
-----------------------------
-->Sometimes we dont know about implementation, still we can declare a
method. Such type of methods are called as abstract methods. i.e abstract
method has only declaration but not implementation.
-->In python we can declare abstract method by using @abstractmethod
decorator as
@abstractmethod
def m1(self):pass

@abstractmethod decorator present in abc module.


abc ==> abstract base class module
Ex: from abc import * class Test:
@abstractmethod
def m1(self):pass
Ex: from abc
import * class
Fruit:
@abstractmethod
def taste(self):pass

-->Child classes are responsible to provide implementation for parent


class abstract methods.

Abstract class:
---------------------
-->Some times implementation of a class is not completed, such type of
partially implementation classes are called as abstract classes. --
>Every abstract class in python should be derived from ABC class which
is present in abc module. Ex: from abc import * class Test(ABC):

@abstractmethod def
m1(self):
pass t = Test()
TypeError: Can't instantiate abstract class Test with abstract method m1
Conclusion:
-----------------
-->If a class contains atleast one abstract method and if we are
extending ABC class then instantiation is not possible.
'abstract class with abstract method instantiation is not possible'

-->Parent class abstract methods should be implemented in the child


classes. Otherwise we cannot instantiate child class. If we are not
creating child class object then we wont get any error. Ex: from
abc import * class Vehicle(ABC): @abstractmethod
def no_of_wheels(self):pass
class
Bus(Vehicle):
pass

-->It is valid bcoz we are not creating child class object.

b = Bus()
TypeError: Can't instantiate abstract class Bus with abstract method
no_of_wheels
Note:
If we are extending abstract class and does not override its abstract
method then child class is also abstract and instantiation is not
possible. Ex:
from abc import * class
Vehicle(ABC): @abstractmethod
def no_of_wheels(self):pass
class Bus(Vehicle):
def
no_of_wheels(self):
return 7 class
Auto(Vehicle):
def
no_of_wheels(self):
return 3 b = Bus()
print(b.no_of_wheels()) a
= Auto()
print(a.no_of_wheels())

Note:Abstract class can contain both abstract and non-abstract methods


also.

Interfaces in python:
==================
Concrete class vs Abstract class vs Interface:
------------------------------------------------------------------- [Link]
we dont know anything about implementation just we have requirement
specification then we should go for interface.

[Link] we are talking about implementation but not completely then we


should go for abstract class.(Partially implemented class)

[Link] we are talking about implementation completely and ready to provide


service then we should go for concrete class.

Interface :No Implementation


Abstract class :Partial Implementation
Concrete class :Full Implementation
Ex: from abc import * class
CollegeAutomation(ABC):
@abstractmethod def
m1():pass @abstractmethod
def m2():pass
@abstractmethod
def m3():pass
class AbsClass(CollegeAutomation): def
m1(self): print('M1 method
implementation') def m2(self):
print('M2 method implementation')
class ConcreteClass(AbsClass): def
m3(self): print('M3 method
implementation')

c = ConcreteClass()
c.m1()
c.m2()
c.m3()

-->In general if an abstract class contains only abstract methods such


type of abstract class is considered as interface.
Ex: ---- from abc import * class DBinterface(ABC):
@abstractmethod def connect(self):pass
@abstractmethod def disconnect(self):pass class
Oracle(DBinterface): def connect(self):
print('Connecting to Oracle DB......') def
disconnect(self): print('Disconnecting
to Oracle DB....') class MongoDB(DBinterface):
def connect(self): print('Connecting to
MongoDB ......') def disconnect(self):
print('Disconnecting to MongoDB DB....')
dname = input('Enter Database:')
print(globals()[dname]) ClassName =
globals()[dname] c = ClassName()
[Link]()
[Link]()

Note:The inbuilt function globals()[str] converts the string 'str' into a


Classname and returns the ClassName.

Reading ClassName from the file:


-------------------------------------------------
[Link] ---------------
HP Ex: from abc
import * class
Printer(ABC):
@abstractmethod
def
printit(self,text):pass
@abstractmethod def
disconnect(self):pass
class EPSON(Printer): def printit(self,text):
print('Printing from EPSON Printer.....')
print(text) def disconnect(self):
print('Printing completed on EPSON Printer.....')
class
HP(Printer):
def printit(self,text):
print('Printing from HP Printer.....')
print(text) def disconnect(self):
print('Printing completed on HP Printer.....')
with open('[Link]','r') as
f:
pname = [Link]()

ClassName = globals()[pname] c
= ClassName()
[Link]('This data has to print....')
[Link]() public, protected and
private attributes:
------------------------------------------------------------
BYdefault every attribute is public. We can access from anywhere either
within the class or from outside of the class.
[Link] --
--------
class Test:
x = 10
def __init__(self):
self.y = 20
[Link] -----------
- from test import
Test class Test1:
t = Test()
print(t.x)
print(t.y)
-->Protected attributes can be accessed within the class anywhere but
from outside of the class only in child classes. We can specify an
attribute as protected by prefixing with (_) underscore symbol.

Syn: _variablename = value


Ex:
class Test:
_x = 10
def
__init__(self):
self._y = 20 t = Test()
print(t._x) print(t._y)

-->But it is just convention and in reality does not exists protected


attributes.

-->Private attributes can be accessed only within the class. i.e from
outside of the class we cannot access. We can declare a variable as
private explicitly by prefixing with 2 underscore symbols.

Syn: __variablename = value


class
Test:
x = 10
_y = 20 __z =
30 def
m(self):
print(Test.x)
print(Test._y)

print(Test.__z) t = Test()
t.m() print(Test.x)
print(Test._y)
print(Test.__z)#AttributeError: type object 'Test' has no attribute '__z'
How to access private avariables from outside of the class?
-------------------------------------------------------------------------
---------------
-->We cannot access private variables directly from outside of the class.
-->But we can access indirectly as: Ex:
class Test:
__x = 10 def
__init__(self):
self.__y = 20 t = Test()
print(t.__dict__)#{'_Test__y': 20}
print(t._Test__y)#20 print(Test._Test__x)#10

__str__() method:
-------------------------
-->Whenever we are printing any object reference internally __str__()
method will be called which returns string in following format.
<__main__.Student object at
0x000001FC02A2BB20>
-->To return meaningful string representation we have to override
__str__() method.
class
Student:
def
__init__(self,
name,rollno):

[Link] =
name
[Link] =
rollno
def
__str__(self):
return
'This is
Student with
Name:{} and
Rollno:{}'.format([Link],[Link])
s1 = Student('Radhika',101) s2 =
Student('Lilly',102) print(s1) print(s2)

[Link] between str() and repr() (or) Difference between __str__()


and __repr__()?
-------------------------------------------------------------------------
---------------------------------------------------
-->str() internally calls __str__() function and hence functionality of
both is same.
-->Similarly repr() internally calls __repr__() method.
-->str() returns a string containing a nicely printable representation
object.
-->The main purpose of str() is for readability. It may not possible to
convert result string to original object.
-->But we can solve this one by using repr().
-->The main goal of repr() is unambigouous.
-->We can convert result string to original object by using eval()
function, which may not possible in str() function. Ex:
import datetime
today = [Link]()
print(type(today)) s =
repr(today) print(type(s)) d =
eval(s) print(type(d))

Regular Expressions: ==================


-->If we want to represent a group of strings according to a particular
format/pattern then we should go for regular expressions.

-->i.e regular expressions is a declarative mechanism to represent a


group of strings according to particular format/pattern.

Ex-1:We can write a regular expression to represent all mobile numbers.


Ex-2:We can write a regular expression to represent all mail id's.

We can develop regular expression based applications by using python


module:re

[Link](): re module contains compile() function to compile a


pattern into RegexObject.
pattern = [Link]('ab')
[Link]():
Returns an iterator object which yields match object for every
match.
matcher =
[Link]('abaababa')

On match object we can call the methods.


[Link]():Returns start index of the match
[Link]():Returns end+1 index of the match
[Link]():Returns the matched string. Ex:
import re count
= 0
pattern = [Link]('ab') matcher =
[Link]('abaababa') for match
in matcher:
count += 1
print([Link](),'...',[Link](),'...',[Link]())
print('The number of occurences:',count)

Note:We can pass pattern directly as argument to finditer() function.


Ex:
import re
matcher = [Link]('aba','abaababa') for match in matcher:
print([Link](),'...',[Link](),'...',[Link]())

Character classes:
---------------------------
1.[abc]===>Either a or b or c
2.[^abc]===>Except a and b and c
3.[a-z]===>Any lower case alphabet symbol
4.[A-Z]===>Any upper case alphabet symbol
5.[a-zA-Z]===>Any alphabet symbol
6.[0-9]===>Any digit from 0 to 9
7.[a-zA-Z0-9]===>Any alphanumeric caharcter
8.[^a-zA-Z0-9]===>Except alphanumeric characters(special characters)
Ex:
import re
matcher = [Link]('x','a7b@k9z') for
match in matcher:
print([Link](),'...',[Link]())
x = [abc] -
-----------
0 ... a
2 ... b
x = [^abc] --
------------
1 ... 7
3 ... @
4 ... k
5 ... 9
6 ... z
x = [a-z] -
-----------
0 ... a
2 ... b
4 ... k
6 ... z
x = [0-9] -
-----------
1 ... 7
5 ... 9

x = [a-zA-Z0-9] ---------------------
0 ... a
1 ... 7
2 ... b
4 ... k
5 ... 9
6 ... z

x = [^a-zA-Z0-9] -----------------------
3 ... @

2).Pre-defined character classes:


------------------------------------------------
\s ==>Space character
\S ==>Any character except space character
\d ==>Any digit from 0 to 9
\D ==>Any character except digit
\w ==>Any word character [a-zA-Z0-9]
\W ==>Any character except word character(Special Characters)
. ==>Any character including special characters. Ex:
import re
matcher = [Link]('x','a7b k@9z') for
match in matcher:
print([Link](),'...',[Link]())
x = \s
--------
3 ... x
= \S ---
------
0 ... a
1 ... 7
2 ... b
4 ... k
5 ... @
6 ... 9
7 ... z
x = \d -
--------
1 ... 7
6 ... 9
x = \D -
--------
0 ... a
2 ... b
3 ...
4 ... k
5 ... @
7 ... z
x = \w -
--------
0 ... a
1 ... 7
2 ... b
4 ... k
6 ... 9
7 ... z x = \W ---------- 3 ...
5 ... @
x = . -
------
0 ... a
1 ... 7
2 ... b
3 ...
4 ... k
5 ... @
6 ... 9
7 ... z

3).Quantifiers:
---------------------
We can se quantifiers to specify the number of occurences to match.

a==>Exactly one 'a' a+==>Atleast one 'a' a*==>Any number


of a's including zero number. a?==>Atmost one 'a' i.e
either zero number of one number. a{m}==>Exactly 'm'
number of a's.
a{m,n}==>Minimum 'm' number of a's and maximum 'n' number of a's
Ex:
import re
matcher = [Link]('x','abaabaaab') for
match in matcher:
print([Link](),'...',[Link]())
x = a
-------
0 ... a
2 ... a
3 ... a
5 ... a
6 ... a
7 ... a x = a+ ---------
0 ... a
2 ... aa
5 ... aaa
x = a* -
--------
0 ... a 1
... 2 ...
aa 4 ...
5 ... aaa
8 ...
9 ... x = a? -------- 0 ... a
1 ...
2 ... a
3 ... a
4 ...
5 ... a
6 ... a
7 ... a
8 ...
9 ... x = a{3} -----------
5 ... aaa
x = a{2,4} --
------------
2 ... aa
5 ... aaa

Note:
^x==>It will check whether target string startswith x or not.
x$==>It will check whether target string endswith x or not.

Functions of re module:
match(), fullmatch(), search(), findall(), finditer(), sub(),
subn(), split(), compile()

[Link]():
---------------
To check the given pattern at beginning of target string.
If the match is available then we will get match object, otherwise we
will get None.
import
re
s = input('Enter pattern to check:') m = [Link](s,'abcdefg') if m
!= None: print('Match is available at the beginning of the
string') print('Start index:',[Link](),'and End index:',[Link]())
else: print('Match is not available at the beginning of the
string')
Functions of re module: match(), fullmatch(), search(),
findall(), finditer(), sub(), subn(), split(), compile()

[Link]():
--------------------
We can use fullmatch() function to match a pattern to all of the target
string. i.e complete string should be matched according to given pattern.
import
re
s = input('Enter pattern to check:')
m = [Link](s,'ababab') if m !=
None:
print('Full String Matched')
else:
print('Full String Not Matched')

[Link]():
---------------
We can use search() function to search the given pattern in the target
string.
If the match is available then it returns the match object which
represents first occurence of the match.
import
re
s = input('Enter pattern to check:')
m = [Link](s,'abaaaba') if m !=
None:
print('Match is available')
print('First occurence of match with start
index:',[Link](),'end index:',[Link]()) else:
print('Match is not available')

4).findall():
----------------
To find all occurences of the match.
This function returns a list object which contains all occurences.
import
re
l = [Link]('[0-9]','a7b9c5k8z')
print(type(l))#<class 'list'> print(l)
#['7', '9', '5', '8']

5).sub(): ------------
sub means substitution or replacement
[Link](regex,replacement,targetstring)
In the target string every matched pattern will be replaced with provided
replacement.
import
re
s = [Link]('[a-z]','#','a7b9c5k8z')
print(s)

-->Every alphabet symbol is replaced with # symbol

6).subn():
--------------
It is exactly same as sub except it can also returns the number of
replacements.
This function returns a tuple where first element is result string and
second element is number of replacements.
(result string,number of replacements)
import
re
t = [Link]('[a-z]','#','a7b9c5k8z')
print(type(t)) print(t)
print('The result string:',t[0]) print('The
number of replacements:',t[1])

7).split():
-------------
-->If we want to split the given target string according to a particular
pattern then we should go for split() function.
-->This function returns a list of all tokens.
import
re
l = [Link](',','sunny,bunny,vinny,chinny')
print(l) for i in l:
print(i)
Ex:
import re
l = [Link]('\.','[Link]')
print(l) for i in l:
print(i)

^ symbol:
---------------
To check whether the given target string startswith our provided pattern
or not.
Ex:
res = [Link]('^Learn',s)
If the target string startswith Learn it will return match object
otherwise returns None.
import
re
s = 'Learning Python is Very Easy'
res = [Link]('^Learn',s) if res
!= None:
print('Target string starts with Learn')
else:
print('Target string not starts with Learn')

$ symbol:
---------------
To check whether the given target string endswith our provided pattern or
not. import re
s = 'Learning Python is Very Easy'
res = [Link]('Easy$',s) if res
!= None:
print('Target string ends with Easy')
else:
print('Target string not ends with Easy')
Note:
If we want to ignore case then we have to pass 3rd argument
[Link] for search() function.
Ex: res =
[Link]('Easy$',s,[Link])
Write a regular expression to represent S-Language Identifiers:
-------------------------------------------------------------------------
------------------- Rules:
[Link] allowed characters are a-z/A-Z/0-9,#
[Link] first character should be a lower case alphabet symbol a to
k.
[Link] second character should be a digit divisible by 3.
[Link] length of identifier should be atleast 2.

[a-k][0369][a-zA-Z0-9#]*

w.a.p to check whether the given string is S-language identifier or not?


-------------------------------------------------------------------------
-------------------------------- import
re
s = input('Enter Identifier:')
m = [Link]('[a-k][0369][a-zA-Z0-
9#]*',s) if m != None:
print(s,'is valid S-language identifier')
else:
print(s,'is invalid S-language identifier')

Write a regular expression to represent all 10-digit mobile numbers


-------------------------------------------------------------------------
-------------------------- Rules:
[Link] number should contain exactly 10-digits.
[Link] first digit should be 6 or 7 or 8 or 9

[6-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-
9][0-9]
[6-9][0-9]{9}
[6-9]\d{9}

w.a.p to check whether the given number is valid mobile number or not? --
-----------------------------------------------------------------------
----------------------------------- import
re
n = input('Enter Number:') m =
[Link]('[6-9][0-9]{9}',n) if m !=
None:
print(n,'is valid mobile number')
else:
print(n,'is invalid mobile number')

w.a.p to extract all mobile numbers present in [Link] where numbers


are mixed with normal text data.
import
re
f1 = open('[Link]','r') f2
= open('[Link]','w') for
line in f1:
list = [Link]('[6-9][0-9]{9}',line)
for n in list:
[Link](n+'\n')
print('Extracted all mobile numbers into [Link]')
[Link]() [Link]()
w.a.p to check whether the given mobile number is valid or not(10 digit
or 11 digit or 12 digit)
import
re
n = input('Enter Number:')
m = [Link]('(0|91)?[6-9][0-9]{9}',n) if
m != None:
print(n,'is valid mobile number')
else:
print(n,'is invalid mobile number')
Python Data Base Connectivity (PDBC) ==================================
Python data base programming:
-----------------------------------------------
-->Sometimes as the part of programming requirement we have to connect to
the database and we have to perform several operations like creating
tables, inserting data, updating data, deleting data and selecting data
etc...
-->We can use SQL language to talk to the database and we can use python
to send those SQL commands to the database.
-->Python provides inbuilt support for several databases like
Oracle,Mysql, Sqlserver, sqlite3 etc......

Standard steps for python DB programming:


------------------------------------------------------------------
[Link] database specific module
import cx_Oracle

[Link] connection between python program and DB.


We can create this connection object by using connect() function of the
module.
con = cx_Oracle.connect(database information)

[Link] execute our sql queries and to hold results some special object is
required, which is nothing but Cursor object. We can create Cursor object
by using cursor() method.
cursor = [Link]()

[Link] SQL queries by using Cursor object. For this we can use the
methods.
-->execute()
-->executescript()
-->executemany()

[Link] or rollback changes bsed on our requirement in the case of DML


Queries(insert | update | delete)
commit():Saves the changes to the database
rollback():rolls all temporary changes back

[Link] the result from the Cursor object in the case of select queries.
fetchone():To fetch only one row
fetchall():To fetch all rows and it returns a list of rows
fetchmany(n):To fetch first 'n' rows.

[Link] the resources:


After completing our operations it is highly recommended to close
the resources in the reverse order of their opening by using close()
methods.
[Link]()
[Link]()

Note:The methods which can be used for python DB programming are:


connect(),cursor(),execute(),executescript(),executemany()
commit(),rollback(),fetchone(),fetchmany(n),fetchall(),close()
-->These methods wont be changed from database to database and same for
all databases.

Working with Oracle database: -------------------------------------------


--
From python program if we want to communicate with any database, some
translator must be required to translate python calls into database
specific calls and database specific calls into python calls. This
translator is nothing but driver/connector.

For Oracle database the name of the driver needed is cx_Oracle.

Installing cx_Oracle: -------------


----------------- goto cmd prompt:
D:\Mahesh_Classes>pip install cx_Oracle

How to test installation:


goto python shell:
>>>help('modules')

w.a.p to connect with Oracle DB and print its version?


-------------------------------------------------------------------------
--------
SQL> select * from global_name;
GLOBAL_NAME
-----------------------
ORCL
import cx_Oracle try:
con = cx_Oracle.connect('scott/tige@ORCL')
print('Connection established successfully......')
print('Version:',[Link]) except
cx_Oracle.DatabaseError:
print('Connection not established......')

w.a.p to create employee table in Oracle DB


-----------------------------------------------------------------
import cx_Oracle try:
query = "create table employee(eno number,ename varchar2(10),esal
number(10,2),eaddr varchar2(10))"
con =
cx_Oracle.connect('scott/tiger@ORCL') cursor =
[Link]() [Link](query)
print('Table created
successfully......') except
cx_Oracle.DatabaseError as e: if con:
[Link]()
print('There is a problem is
sql:',e) finally: if cursor:
[Link]()
if con:
[Link]()

w.a.p to drop employee table from Oracle DB


------------------------------------------------------------------- query
= "drop table employee"
w.a.p to insert single row in the employee table
-----------------------------------------------------------------------
query = "insert into employee values (101,'Sunny',10000,'Mumbai')"
[Link]()

Note:while performing DML operations(insert | update | delete), we have


to use commit() method, then only results will be reflected in the
database.
w.a.p to insert multiple rows in the employee table by using
executemany() method
-------------------------------------------------------------------------
---------------------------------------------------- query =
"insert into employee values(:eno,:ename,:esal,:eaddr)" records
= [(102,'Bunny',12000,'Hyd'),(103,'Vinny',15000,'Vja'),
(104,'Chinny',18000,'Bng')]
con = cx_Oracle.connect('scott/tiger@ORCL')
cursor = [Link]()
[Link](query,records) [Link]()
print('Records are inserted successfully......')

w.a.p to insert multiple rows in the employee table with dynamic input
from the keyboard?
-------------------------------------------------------------------------
------------------------------------------------
con = cx_Oracle.connect('scott/tiger@ORCL')
cursor = [Link]() while True:
eno = int(input('Enter Employee Number:')) ename
= input('Enter Employee Name:') esal =
float(input('Enter Employee Salary:')) eaddr =
input('Enter Employee Number:') sql = "insert into
employee values(%d,'%s',%f,'%s')"
[Link](sql%(eno,ename,esal,eaddr))
print('Record inserted successfully......')
option = input('Do you want to insert one more record[Yes |
No]:') if option == 'No': [Link]() break

Ex:Increment all employee salaries by 1200 whose salary < 20000


-------------------------------------------------------------------------
--------------------------
con = cx_Oracle.connect('scott/tiger@ORCL') cursor
= [Link]()
increment = float(input('Enter increment salary:'))
salrange = float(input('Enter salary range:'))
sql="update employee set esal = esal+%f where esal<%f"
[Link](sql%(increment,salrange)) print('Records
are updated successfully....') [Link]()

Ex:Delete all employees whose sal > 20000


----------------------------------------------------------------
con = cx_Oracle.connect('scott/tiger@ORCL') cursor =
[Link]()
cutoffsal = float(input('Enter Cutoff Salary:')) sql="delete
from employee where esal>%f" [Link](sql%(cutoffsal))
print('Records are deleted successfully....') [Link]()

w.a.p to select all employee info by using fetchone() method?


-------------------------------------------------------------------------
------------------
con = cx_Oracle.connect('scott/tiger@ORCL') cursor
= [Link]()
[Link]("select * from employee")
row = [Link]() while
row is not None:
print(row)
row = [Link]()

w.a.p to select all employee info by using fetchall() method?


-------------------------------------------------------------------------
----------------
con = cx_Oracle.connect('scott/tiger@ORCL') cursor
= [Link]()
[Link]("select * from employee")
data = [Link]()
print(type(data)) for row in data:
print('Employee Number:',row[0])
print('Employee Name:',row[1])
print('Employee Salary:',row[2])
print('Employee Address:',row[3])
print()

w.a.p to select employees info by using fetchmany() method?


-------------------------------------------------------------------------
------------------
con = cx_Oracle.connect('scott/tiger@ORCL') cursor
= [Link]()
[Link]("select * from employee") n =
int(input('Enter the number of required rows:'))
data = [Link](n) for row in data:
print(row)

Working with Mysql database:


--------------------------------------------
Current version:8.0
Vendors:SUN Micro Systems/Oracle Corp
Opensource and freeware
Default port:3306
Default user:root
Note:
In MySQL, everything we have to work with our own databases, which
are also known as logical databases.

Commonly used commands in Mysql:


--------------------------------------------------------
[Link] know available databases: mysql> show
databases;

[Link] create our own logical database:


mysql> create database maheshdb;

[Link] drop our own database:


mysql> drop database maheshdb;

[Link] use particular database:


mysql> use maheshdb; or mysql> connect maheshdb;
Driver/Connection information:
------------------------------------------------
For mysql the driver needed is:pymysql

How to install:
goto cmd prompt:
D:\Mahesh_Classes>pip install pymysql

How to check installation:


goto python shell:
>>>help('modules')

w.a.p to create table, insert data and display data by using Mysql
Database
-------------------------------------------------------------------------
---------------------------------------
import pymysql try:
con =
[Link](host='localhost',database='maheshdb',user='root',

password='root') cursor = [Link]()


[Link]("create table employees(eno int(5) primary key,ename
varchar(10),esal double(10,2),eaddr varchar(10))")
print('Table is created........')
query = "insert into employees(eno,ename,esal,eaddr) values
(%s,%s,%s,%s)"
records =
[(111,'Katrina',1000,'Mumbai'),(222,'Kareena',2000,'Hyd'),
(333,'Deepika',3000,'Chennai')]
[Link](query,records)
[Link]()
print('Records are inserted successfully.....')

[Link]("select * from
employees") data = [Link]()
print(type(data)) for row in data:
print('Employee Number:',row[0])
print('Employee Name:',row[1])
print('Employee Salary:',row[2])
print('Employee Address:',row[3])
print() except [Link] as e:
if con: [Link]()
print('There is a problem with
sql:',e) finally: if cursor:
[Link]()
if con:
[Link]()

w.a.p to copy data present in employees table of Mysql DB into Oracle DB?
-------------------------------------------------------------------------
---------------------------------------
import pymysql,cx_Oracle try:
con =
[Link](host='localhost',database='maheshdb',user='root',
password='root') cursor = [Link]()
[Link]("select * from employees")
data = [Link]()
print(type(data))#<class 'tuple'>
list_data = list(data)
print(type(list_data))#<class 'list'>
try:
con = cx_Oracle.connect('scott/tiger@ORCL')
cursor = [Link]()
query = "insert into employee
values(:eno,:ename,:esal,:eaddr)"
[Link](query,list_data) [Link]()
print('Records copied from Mysql to Oracle DB successfully......')

Multi Threading
============== Multi
Tasking:
----------------------
-->Executing several tasks simultaneously is the concept of multi
tasking.

[Link] based multi tasking(OS Level)


[Link] based multi tasking
Multi Threading
============== Multi
Tasking:
----------------------
-->Executing several tasks simultaneously is the concept of multi
tasking.

[Link] based multi tasking(OS Level)


[Link] based multi tasking

-->Python provides one in-built module threading to provide support for


developing threads.
-->Every python program bydefault contains one thread which is nothing
but MainThread.

Ex:To print name of current executing thread


--------------------------------------------------------------------
import threading
print('Current executing thread:',threading.current_thread().name)
Note:
threading module contains function current_thread() which returns
the current executing Thread object. On this object if we call name
attribute then we will get current executing thread name.

The ways of creating Thread in python:


----------------------------------------------------------
We can create a thread in python by using 3-ways
[Link] a Thread without using any class.
[Link] a Thread by extending Thread class.
[Link] a Thread without extending thread class.

[Link] a Thread without using any class.


-------------------------------------------------------------------
from threading import * def display():
print('This code(Display Function) is executed by
thread:',current_thread().name)
t = Thread(target=display)#MainThread created child thread
[Link]()#MainThread started child thread
print('This code executed by Thread:',current_thread().name)
Note:
Thread is pre-defined class present in the threading module which
can be used to create our own threads.

Creating multiple threads:


----------------------------------------
from threading import * def
display(): for i in
range(10):
print('Child Thread') t =
Thread(target=display)
[Link]() for i in
range(10):
print('Main Thread')

-->If multiple threads present in our program, then we cannot expect


execution order and hence we cannot expect exact output for the multi
threaded programs. Bcoz of this we cannot provide exact output for the
above program. It is varied from machine to machine and run to run.

[Link] a Thread by extending Thread class.


---------------------------------------------------------------------- We
have to create child class for Thread class. In that child class we have
to override run() method with our required job. Whenever we call start()
method then automatically run() method will be executed and performs our
job.

from threading import * class


MyThread(Thread): def
run(self): for i
in range(10):
print('Child Thread-1')
t = MyThread()
[Link]() for i in
range(10):
print('Main Thread-1')

[Link] a Thread without extending thread class.


-------------------------------------------------------------------------
-----
from threading import * class
Test:
def display(self):
for i in range(10):
print('Child Thread')
obj = Test()
t = Thread(target=[Link])
[Link]() for i in
range(10):
print('Main Thread')
without
multithreading:
------------------------------------
import time def doubles(numbers):
for n in numbers:
print('Double is:',2*n)
[Link](1) def squares(numbers):
for n in numbers:
print('Square is:',2*n)
[Link](1) numbers =
[1,2,3,4,5,6] begintime =
[Link]() doubles(numbers)
squares(numbers) endtime =
[Link]()
print('The total time taken:',endtime - begintime)
with
multithreading:
------------------------------
numbers = [1,2,3,4,5,6] begintime
= [Link]()
t1 = Thread(target=doubles,args=(numbers,))
t2 = Thread(target=squares,args=(numbers,))
[Link]() [Link]()
[Link]() [Link]()
endtime = [Link]()
print('The total time taken:',endtime - begintime)

Setting and getting name of thread:


-----------------------------------------------------
from threading import * print(current_thread().name)
current_thread().name = 'Radhika'
print(current_thread().name)

Thread identification number:


---------------------------------------------
For every thread internally a unique identification number is available.
We can access this id by using implicit variable 'ident'

from threading import * def


test():
print('Child Thread')
print('Child Thread identification number:',current_thread().ident)
t = Thread(target=test)
[Link]()
print('Main Thread identification number:',current_thread().ident)
print('Child Thread identification number:',[Link])
join() method: -----
----------------
If a thread wants to wait until completing some other thread then we
should go for join() method.

from threading import * import


time def display(): for i in
range(10):
print('Seetha Thread')
[Link](1)
t = Thread(target=display)
[Link]()
[Link]() for i in
range(10):
print('Rama Thread')
Python New Features:
=================== [Link]
operator:
----------------------------
:=(It is available in plsql also)
python 3.8

This operator released as the part of PEP 572


PEP-->Python Enhancement Proposals
To assign values to the variables as the part of expression itself.

Other meaning is:


Assignment Expressions
Ex: l =
[10,20,30,40,50] if
(n:=len(l)) > 3:
print('List contains more than 3-elements')
print('The length of the list is:',n)
Ex:
heroines = [ ] while (heroine := input('Enter your favourite
heroine:')) != 'sunny':
[Link](heroine)
print(heroines)

Ex:read data line by line from [Link] file and print to the console
-------------------------------------------------------------------------
-------------------------- f =
open('[Link]') while (line :=
[Link]()) != '':
print(line,end='')
[Link]()

The main advantage of the walrus operator:


-----------------------------------------------------------------
-->It won't do any new thing.
-->It just reduces length of the code and readability will be improved.

Functions:
----------------
[Link] args
[Link] args
[Link] args
[Link] length args
keyword-only argument:
------------------------------------
After *, all parameters will become keyword-only parameters.
At the time of calling we should pass values by keyword-only.
Ex:
def f1(*,a,b):
print(a,b)
f1(10,20)#Invalid f1(10,b=20)#Invalid
f1(a=10,b=20)#Valid

What about def f1(a,*,b,c):


--------------------------------------
#for a, we can pass value either by positional or keyword
#But for b and c, we should use keyword-only
def
f1(a,*,b,c):
print(a,b,c)
f1(10,20,c=30)#Invalid
f1(10,b=20,c=30)#Valid
f1(a=10,b=20,c=30)#Valid
Ex:
def f1(a,b,*):
pass
f1()
==>SyntaxError
positional-only
argument:
---------------------------------------
All parameters before /, will become positional-only parameters
/--->forward slash
We should pass values by positional-only args.
Ex:
def f1(a,b,/):
print(a,b)
f1(a=10,b=20)#Invalid
f1(10,b=20)#Invalid f1(10,20)#Valid

Python 3.8 version as the part of PEP 570


def f1(a,b,/,c,d,*,e,f): -----
--------------------------
#a and b are positional-only parameters
#c and d are positional-or-keyword parameters
#e and f are keyword-only parameters
def
f1(a,b,/,c,d,*,e,f):
print(a,b,c,d,e,f)
f1(10,20,30,40,e=50,f=60)#Valid
f1(10,20,c=30,40,e=50,f=60)#Invalid
f1(10,20,30,d=40,e=50,f=60)#Valid
f1(10,b=20,c=30,d=40,e=50,f=60)#Invalid
Ex:
def f1(*,a,b,c,/):
print(a,b,c)

SyntaxError: invalid syntax Note: f1(positional-only args,


positional-or-keyword args, keyword-only args) positional-only vs
keyword-only:
------------------------------------------------
[Link] the parameter names are not important and not having any meaning and
there are only few args===>positional-only args

[Link] parameter names having meaning and function implementation is more


understandable with these names===>keyword-only args
f-strings or formatted strings or Literal string interpolation: -------
------------------------------------------------------------------
----------------
Python 3.6 verion
PEP 498
String formatting means inserting values and expressions in string
literal

3-types of techniques
-------------------------------- 1.%-formatting
[Link]() method
3.f-strings Ex:
name = 'radhika'
print('Hello %s good evening'%name)
print('Hello {} good evening'.format(name))
print(f'Hello {name} good evening')
Note:
We can use either f or F, we can use single quotes or double quotes
or triple quotes also.

name = 'lilly'
print(f'Hello {name} good evening') print(F"Hello
{name} good evening") print(F'''Hello {name} good
evening''') print(F"""Hello {name} good
evening""")

Handling quotes in f-string


----------------------------------------
The symbol " is good

print(f'The symbol " is good')


print(f"The symbol ' is good")
print(f'''The symbol ' and " are good''')
print(f"The symbol \' and \" are good")
Ex: name = 'Mahesh' subject = 'Python'
print(f'''The classes of '{subject}' by "{name}" are too good''')
How to define multi line f-strings:
--------------------------------------------------
name = 'Mahesh' age = 50 subject = 'Python' msg =
f''' Name:{name}, Age:{age},
Subject:{subject}
''' print(msg)

Python f-string calling a function


--------------------------------------------------
We can call function directly from f-string

name = 'Mahesh'
print(f'Faculty Name:{[Link]()}')
Ex:
def mymax(a,b):
max = a if a>b else b
return max
a = int(input('Enter 1st Number:')) b
= int(input('Enter 2nd Number:'))
print(f'The maximum of {a} and {b} is {mymax(a,b)}')

Python f-strings for objects:


----------------------------------------- [Link]()
method will always call str() method only
But f-string we can call either str() or repr() based on our requirement.
class Student: def
__init__(self,name,rollno,marks):
[Link] = name [Link] =
rollno [Link] = marks
def __str__(self): return
f'Name:{[Link]},RollNo:{[Link]},Marks:{[Link]}'
def __repr__(self): return f'Student
Name:{[Link]},Student RollNo:{[Link]},Student
Marks:{[Link]}' s = Student('Sunny',101,90)
print('Information--->{}'.format(s)) print(f'Information---
>{s}') print(f'Information--->{s!r}')

Expressions inside f-strings:


------------------------------------------
We can pass expressions inside f-string and these expressions will be
evaluated at runtime. Ex: a = 10 b = 20 c = 30
print(f'The Result:{10*20/3}') print(f'The
Result:{10*20/3:.2f}') print(f'The
Result:{a+b*c}')

How to use curly braces inside f-strings:


------------------------------------------------------------- o/p:
'It is a { a special symbol'

print(f'It is { a special symbol')#SyntaxError: f-string: expecting '}'


print(f'It is {{ a special symbol')#It is { a special symbol print(f'It
is {{{ a special symbol')#SyntaxError: f-string: expecting '}' print(f'It
is {{{{ a special symbol')#It is {{ a special symbol

The same applicable for } also


--------------------------------------------
print(f'It is } a special symbol')#Invalid
print(f'It is }} a special symbol')#Valid
print(f'It is }}} a special symbol')#Invalid
print(f'It is }}}} a special symbol')#Valid
Ex: ----- name
= 'Sunny'
print(f'Name:{name}')#Name:Sunny print(f'Name:{{name}}')#Name:{name}
print(f'Name:{{{name}}}')#Name:{Sunny}
print(f'Name:{{{{name}}}}')#Name:{{name}}

We can use = symbol inside f-string for self documenting expressions and
it is very useful for debugging purpose.
x =
10 y =
20
#print(f'x={x}')
#print(f'y={y}')
print(f'{x=}') print(f'{y=}')

Dictionary related enhancements(3.7,3.8 and 3.9 versions)


-------------------------------------------------------------------------
--------------
Until 3.7 version how to iterate items of dict in reverse order:

d = {100:'sunny',200:'bunny',300:'vinny',400:'chinny'}
keys = [Link]() l = list(keys) r = reversed(l) for k
in r:
print(k,'--->',d[k])

From 3.8 version onwards, we can apply reversed() for dict also
d = {100:'sunny',200:'bunny',300:'vinny',400:'chinny'} r =
reversed(d) for k in r:
print(k,'--->',d[k])

How to merge 2-dictionaries into a third dict


-------------------------------------------------------------------
1st way: -------------
d1 = {100:'sunny',200:'bunny',300:'vinny'} d2
= {300:'chinny',400:'pinny',500:'ginny'} d3 =
{**d1,**d2}
print(d3)
2nd way: -------------
d3 = [Link]() for k,v
in [Link]():
d3[k] = v
print(d3)

-->In 3.9 version as the part of PEP 584


d3 = d1|d2 print(d3)

How to update an existing dictionary with items of another dictionary


-------------------------------------------------------------------------
-------------------------------
update--->inline merge
[Link](d2) print(d1)

-->From 3.9 version onwards


d1 |= d2 print(d1)

Interview Questions:
-------------------------------
[Link] to merge two lists into a new list?
---------------------------------------------------------------
l1 = [10,20,30] l2 = [40,50,60] l3 = l1+l2 print(l3) l4 =
[*l1,*l2] print(l4)

[Link] to update existing list with elements of another list?


-------------------------------------------------------------------------
------------------
l1 = [10,20,30] l2
= [40,50,60]
[Link](l2) l1
|= l2 #Invalid
print(l1)

[Link] to merge two tuples into a new tuple?


--------------------------------------------------------------------
t1 = (10,20,30) t2 = (40,50,60) t3 = t1+t2 print(t3) t4 = (*t1,*t2)
print(t4)

[Link] to update existing tuple with elements of another tuple?


-------------------------------------------------------------------------
------------------------
It is impossible
Tuple is immutable. Once we creates a tuple, we cannot perform any
changes.

[Link] to merge two sets into a new set?


--------------------------------------------------------------
s1 = {10,20,30} s2 = {40,50,60,30} s3 = s1|s2 print(s3) s4 =
{*s1,*s2} print(s4)

[Link] to update existing set with elements of another set?


-------------------------------------------------------------------------
-------------------
[Link](s2) s1 |=
s2
Aliasing
Cloning
Deep cloning and Shallow cloning

Aliasing: --------
----- l1 =
[10,20,30,40] l2 =
l1 #Aliasing l1[0]
= 100
print(f'l1:{l1}')
print(f'l2:{l2}')

D:\Mahesh_Classes>py [Link]
l1:[100, 20, 30, 40] l2:[100,
20, 30, 40]

-->The problem with aliasing is, by using one reference if we performs


any change, automatically those changes will be reflected for the
remaining references also.

-->If we want duplicate object instead of duplicate reference variable


then we should go for cloning.
Cloning: ---------
--- l1 =
[10,20,30,40] #l2
= [Link]() l2 =
l1[:] l1[0] = 333
print(f'l1:{l1}')
print(f'l2:{l2}')

Deep Cloning and Shallow Cloning:


----------------------------------------------------
Aliasing --->Shallow Cloning
Cloning ---> Deep Cloning

Shallow Cloning: --------


----------------- import
copy l1 =
[10,20,[30,40],50] l2 =
[Link](l1) l2[2][0] =
333 print(f'l1:{l1}')
print(f'l2:{l2}')

D:\Mahesh_Classes>py [Link]
l1:[10, 20, [333, 40], 50] l2:[10,
20, [333, 40], 50]

Deep Cloning: ---------


------------ import
copy l1 =
[10,20,[30,40],50] l2 =
[Link](l1)
l1[2][0] = 333 l2[2][1]
= 999 print(f'l1:{l1}')
print(f'l2:{l2}')
Shallow cloning vs Deep
cloning:
------------------------------------------------
If original object does not contain any nested objects then it is highly
recommended to go for --->Shallow Cloning

If original object contains any nested objects then we should go for --


>Deep Cloning.

Common questions

Powered by AI

List comprehensions in Python allow concise creation of new lists by iterating over an iterable and applying an expression. Shallow comprehensions create top-level lists where elements are not deeply processed; they just convert elements directly, e.g., `[x for x in iterable]`. Deep comprehensions involve nested comprehensions which iterate over sub-elements, useful for flattening nested structures or processing lists of lists, e.g., `[[y for y in x] for x in nested]`. Shallow comprehensions are suitable for straightforward operations, while deep ones are powerful in complex data transformation scenarios, such as handling matrices or other high-dimensional data .

Inner classes in Python provide benefits like logical grouping and encapsulation, representing a part-whole relationship where the contained class has no independent existence. For example, an `Engine` class inside a `Car` class exemplifies this, as an engine without a car doesn't function independently. This can simplify code and enhance readability. However, limitations include potential complexity in understanding and maintaining nested class structures, which can lead to less clarity for other developers. The scope of inner classes being tied to their outer class restricts their independent utility, making them suitable primarily in scenarios demanding containment relationships .

The `__init__` method in Python acts as a constructor for a class, automatically executed when a new instance of the class is created. It initializes the object's attributes and sets the initial state. For example, in a `Student` class, `__init__` can set attributes like `name`, `rollno`, and `marks`. It takes `self` as its first argument, which refers to the newly created object, allowing `__init__` to work with the object's data. While it's optional, using it provides a standardized way to initialize object properties and ensures each object starts in a known state .

Mathematical operations in Python, such as addition and multiplication, have different implications for lists and sets. The `+` operator concatenates two lists, e.g., `a = [10,20]; b = [30,40]; c = a + b` results in `c = [10, 20, 30, 40]`. However, adding elements directly to a set uses the `|` operator for union, which removes duplicates. For multiplication, `*` replicates list elements, `a = [10] * 3` results in `[10, 10, 10]`. Sets don’t support this operation as they require unique elements, highlighting a key difference where lists support duplication and sets enforce uniqueness .

In Python, lists can be created in several ways, each serving different use cases. Lists can be initialized as empty with `l = []` or filled with values like `l = [10, 20, 30, 40]`. Dynamic lists can be created from user input with `eval(input('Enter List:'))`, which evaluates the input to create a list. The `list()` function can generate a list from a range or a string, providing flexibility in initializing from various iterable objects. The `split()` function is used to create a list from a string by splitting it into words, which is helpful for text processing .

Python offers two primary ways to clone objects: shallow and deep cloning. Shallow cloning creates a new object with references to the original object’s elements using methods like slicing (`y = x[:]`) or the `copy()` function. Deep cloning, however, involves creating a completely independent duplicate, ensuring nested objects are also duplicated, typically using the `deepcopy()` function from the `copy` module. Shallow cloning is more memory-efficient but doesn't fully duplicate nested objects, while deep cloning requires more resources but ensures complete independence of clones .

The `append()` method in Python lists adds its argument as a single element to the end of the list, which means if you append a list, it becomes a sub-list within the main list. In contrast, `extend()` adds elements from its iterable argument to the end of the list, expanding the list directly with each element. Thus, using `append()`, `l.append([40, 50])` results in `[10, 20, 30, [40, 50]]`, while `extend()`, `l.extend([40, 50])` results in `[10, 20, 30, 40, 50]`. This highlights that `append()` maintains the list as a single item, whereas `extend()` increases list elements .

The `add()` method in Python is used to insert a single element into a set, while `update()` is used for adding multiple elements. `add()` accepts only one argument, making it suitable for singular additions. In contrast, `update()` can take any iterable as arguments (like lists, tuples) and adds all contained elements to the set. This flexibility allows `update()` to perform batch insertions efficiently. These differences make `add()` optimal for simple additions and `update()` for extending sets with multiple items or other collections, showcasing the versatility and efficiency in set operations .

Garbage collection in Python is managed by the interpreter to automatically deallocate memory no longer in use, freeing resources and preventing memory leaks. This system tracks object references and collects those that are unreachable, i.e., objects with no references. The cyclic garbage collector handles reference cycles, which would otherwise create memory issues. This process is crucial in Python, unlike manual memory management in languages like C++, ensuring efficient memory use and avoiding scenarios such as 'out of memory' errors, thereby allowing programmers to focus more on application logic rather than memory management intricacies .

In Python, inheritance (IS-A relationship) allows a class to inherit attributes and methods from another class, promoting code reuse. For instance, a `C(Employee)` could inherit from `Person`. This means Employee 'is-a' Person, allowing it to use Person’s behavior and extend it. Composition (HAS-A relationship) involves a class containing instances of another class to use its functionality without forming an inheritance relationship. For example, `Employee` having a `Car` object suggests an Employee 'has-a' Car, using car’s functionalities. Inheritance extends functionality; composition utilizes existing capabilities without modification .

You might also like