Python Identifiers and Data Types Guide
Python Identifiers and Data Types Guide
==========
-->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:
Ex:
cash = 100 #Valid
cas$h = 100 #Invalid
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]
[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.
[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:
bytes,bytearray,list,tuple,range,set,frozenset,dict,None
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
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'
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
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
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]
[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()
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.
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)'
2).Collection DT's:
bytes,bytearray,list,tuple,range,set,frozenset,dict,None
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
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
[Link] DT's:
bytes,bytearray,list,tuple,range,set,frozenset,dict,None
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.
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'
d[100] = 'pinny'
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
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
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
Ex:
4 & 5 #4
4 | 5 #5
4 ^ 5 #1
~4 #-5
Ex:
True & False #False
True | False #True
True ^ False #True
~True #-2
True << 2 #4
True >> 2 #0
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:
+=, -=, *=, /=, %=, **=.............
7).Ternary operator:
------------------------------
In java we can use:
x = (condition)?first value:second value
Ex:
x = (10<20)?30:40
SyntaxError: invalid syntax
pow(2,3,5)#3
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)
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
Ex:
x = input('Enter some value:')
print(type(x)) ==>It always print str type only for any input type.
or
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.
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.
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])
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')
a,b,c = 10,20,30
print(a,b,c,sep=':')#10:20:30
print(a,b,c,sep='-')#10-20-30
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
Ex:
s = 'Mahesh'
l = [10,20,30]
print('Hello %s......The list of values are %s'%(s,l))
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.
[Link]-else:
if condition:
Action-1
else:
Action-2
-->If condition is True Action-1 will be executed otherwise Action-2 will
be executed.
[Link]-elif-else:
------------------
if condition-1:
Action-1
elif condition-2:
Action-2
elif condition-3:
Action-3
else:
Default Action
[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
------
-------
for i in range(1,21,2):
print(i)
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
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
-------------
*
* *
* * *
* * * *
* * * * *
or
n = 2
-------
* *
* *
n = 3
--------
* * *
* * *
* * *
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))
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]:
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"""
w.a.p to accept some string from the keyboard and display its characters
by index wise(both +ve and -ve)
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?
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
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)
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))
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')
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 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 sort the characters of the string and first alphabates followed
by numbers
-------------------------------------------------------------------------
--------------------------------------------------
i/p:'B4A1D3'
o/p:'ABD134'
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))
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)
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]
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]
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]
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)
Ex:
n = [10,20,30,40,50,60]
print([Link]())#60
print([Link](1))#20
print([Link](10))#IndexError
[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.
[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)
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]
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]
Nested List:
------------------
n = [10,20,[30,40]]
print(n[0])
print(n[1])
print(n[2][0])
print(n[2][1])
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]
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)
Ex:
num1 = [10,20,30,40]
num2 = [30,40,50,60]
o/p:[10,20]
o/p:[30,40]
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:
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
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])
4. l = [10,20,30]
t = tuple(l)
print(t)
-->Tuple is Immutable
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()
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.
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]():
-->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)
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)
2nd way
------------
l = eval(input('Enter list of values:'))
l1 = [ ]
for x in l:
if x not in l1:
[Link](x)
print(l1)
Set comprehensions:
-------------------------------
-->set comprehensions is possible
Note:
In C++ and Java dict is known as 'Map' where as in perl and
Ruby it is known as 'Hash'.
d = {}
d[100] = 'sunny'
d[200] = 'bunny'
d[300] = 'vunny'
print(d)
print(d[100])#sunny
print(d[400])#KeyError:400
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)
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)
Dictionary comprehensions:
------------------------------------------
-->Comprehension concept applicable for dictionary also.
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...
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())
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)
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)
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.
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
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)
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)
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)
[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()
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.....'''
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')
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():
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))
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
[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
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
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')
Ex:[Link]
----------------
x = 333
def add(a,b):
return a+b
print(dir())
Ex:[Link]
---------------
print(__builtins__)
print(__cached__)
print(__doc )
print(__file__)
print(__loader__)
print(__name__)
print(__package )
print(__spec__)
---------------------------------------------
-->For every python program, a special variable __name__ will be added
-->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
[Link]
-----------------
def f1():
if name == '__main ':
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)
2).randint():
To generate random integer between two given numbers(inclusive)
3).uniform():
To generate random float value between 2-given numbers(not
inclusive)
4).randrange([start],stop,[step]):
Returns a random number from the range.
5).choice():
-->It wont return random number.
-->It will return a random object from the given list or tuple or
str.
Ex-1:
--------
D:\Mahesh_Classes
|--[Link]
|--pack1
|--[Link]
|--f1()
[Link]
----------------
def f1():
[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():
[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
[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')
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')
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.
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")
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")
Syn:
------
try:
Risky code
except:
Handling code
finally:
Cleanup code
o/p:try finally
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')
-->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')
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
[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.
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.
1).Simple version:
assert condition_expression
2).Augmented version:
assert condition_expression,
message
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))
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)
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.
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.
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]()
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)
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()
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()
creation.
[Link] object, method can be called any will [Link] object, constructor
be
number of times.
executed only once.
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.
-->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.
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 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')
[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)
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.
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'.
-->If an object does not have any reference variable then that object is
eligible for GC.
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')
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
-->In the above example Employee Has-A car reference and hence Employee
class can access all members of Car class.
-->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()
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])
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()
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.
MRO(X)=X + Merge(MRO(p1),MRO(P2),....ParentList)
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
-->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'
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
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.
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
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'
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())
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.
c = ConcreteClass()
c.m1()
c.m2()
c.m3()
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.
-->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.
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)
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 ... @
3).Quantifiers:
---------------------
We can se quantifiers to specify the number of occurences to match.
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)
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#]*
[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')
[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] 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.
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
How to install:
goto cmd prompt:
D:\Mahesh_Classes>pip install pymysql
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',
[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.
Ex:read data line by line from [Link] file and print to the console
-------------------------------------------------------------------------
-------------------------- f =
open('[Link]') while (line :=
[Link]()) != '':
print(line,end='')
[Link]()
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
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""")
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)}')
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=}')
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])
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)
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]
D:\Mahesh_Classes>py [Link]
l1:[10, 20, [333, 40], 50] l2:[10,
20, [333, 40], 50]
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 .