0% found this document useful (0 votes)
6 views156 pages

Python Notes

The document provides an overview of Python virtual environments, including their creation and activation using the venv module. It also covers various Python programming concepts such as multi-line statements, variable types, user input, control flow statements, functions, and modules. Additionally, it discusses string manipulation techniques and built-in string methods.

Uploaded by

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

Python Notes

The document provides an overview of Python virtual environments, including their creation and activation using the venv module. It also covers various Python programming concepts such as multi-line statements, variable types, user input, control flow statements, functions, and modules. Additionally, it discusses string manipulation techniques and built-in string methods.

Uploaded by

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

Python Virtual Environment

Python virtual environments create a virtual installation of Python inside a


project directory. Users can then install and manage Python packages for
each project. This allows users to be able to install packages and modify their
Python environment without fear of breaking packages installed in other
environments.

A virtual environment is a separate directory structure containing isolated


installation having a local copy of Python interpreter, standard library and
other modules.

Creation of Virtual Environments in Python using


venv
This functionality is supported by venv module in standard Python
distribution. Use following commands to create a new virtual environment.

C:\pythonapp>python -m venv myvenv


Here, myvenv is the folder in which a new Python virtual environment will be
created showing following directory structure

Activating Virtual Environment


To enable this new virtual environment, execute [Link] in Scripts
folder.

C:\pythonapp>myvenv\scripts\activate
(myvenv) C:\pythonapp>

Python Multi-Line Statements


Statements in Python typically end with a new line. Python does, however,
allow the use of the line continuation character (\) to denote that the line
should continue. For example −

total = item_one + \
item_two + \
item_three

triple quotes are used to span the string across multiple lines.
paragraph = """This is a paragraph. It is made up of multiple
lines and sentences."""
Memory Addresses
id() function returns the address where the object is stored.

Printing Python Variables


print (counter)

Deleting Python Variables


del variable_name

Getting Type of a Variable


print(type(x))

Casting Python Variables


x = str(10) # x will be '10'
y = int(10) # y will be 10
z = float(10) # z will be 10.0

print( "x =", x )


print( "y =", y )
print( "z =", z )

Implicit type casting


a Python object with lesser byte size is upgraded to match the bigger byte
size of other object in the operation. For example, a Boolean object is first
upgraded to int and then to float, before the addition with a floating point
object. In the following example, we try to add a Boolean object in a float,
pleae note that True is equal to 1, and False is equal to 0.

Open Compiler
a=True;
b=10.5;
c=a+b;

print (c);
This will produce the following result:

11.5

Python Explicit Casting


Python's built-in functions int(), float() and str() to perform the explicit
conversions such as string to integer.
a = int(10.5) #converts a float object to int
<<< a 10
a = int("100") <<< a 100 <<< type(a) <class 'int'>

Conversion of Sequence Types


A string and tuple can be converted into a list object by using
the list() function. Similarly, the tuple() function converts a string or list to a
tuple.
a=[1,2,3,4,5] # List Object
b=(1,2,3,4,5) # Tupple Object
c="Hello" # String Object

### list() separates each character in the string and builds the list
obj=list(c)
<<< obj
['H', 'e', 'l', 'l', 'o']

### The parentheses of tuple are replaced by square brackets


obj=list(b)
<<< obj
[1, 2, 3, 4, 5]

Python User Input Function


input () Function
name = input("Enter your name : ")
print ("Hello My name is", name)

Taking Numeric Input in Python


width = int(input("Enter width : "))
amount = float(input("Enter Amount : "))

To make two lines appear in the same line, define end parameter in the first
print() function and set it to a whitespace string " ".
print("City:", city, end=" ")
print("State:", state)

Output of both the print() functions appear in continuation.

City: Hyderabad State: Telangana

Syntax of Python if elif else Statement

if expression1:
statement(s)
elif expression2:
statement(s)
elif expression3:
statement(s)
else:
statement(s)

match-case Statement

Syntax

match variable_name:
case 'pattern 1' : statement 1
case 'pattern 2' : statement 2
...
case 'pattern n' : statement n

match n:
case 0: return "Monday"
case 1: return "Tuesday"
case 2: return "Wednesday"
case _: return "Invalid day number"

Combined Cases in Match Statement


We can combine cases with the OR operator represented by "|" symbol.

match user:
case "admin" | "manager": return "Full access"
case "Guest": return "Limited access"
case _: return "No access"

Python for Loop with Strings


zen = “Explicit is better than implicit“
for char in zen:
……

Python for Loop with Tuples


numbers = (34,54,67,21,78,97,45,44,80,19
for num in numbers:
..

Python for Loop with Lists


numbers = [34,54,67,21,78,97,45,44,80,19]
for num in numbers:

Python for Loop with Range Objects


for num in range(start, stop, step)

Python for Loop with Dictionaries


Running a simple for loop over the dictionary object traverses the keys
used in it.
numbers = {key1:"Ten", key2:"Twenty", key3:"Thirty"}
for x in numbers:
print (x)
OUTPUT:
key1
key2
key3

Syntax to Define a Python Function


def function_name( parameters ):
"function_docstring"
function_suite
return [expression]

Positional or Required Arguments


Required arguments are the arguments passed to a function in correct
positional order. Here, the number of arguments in the function call should
match exactly with the function definition, otherwise the code gives a syntax
error.

Keyword Arguments
Keyword arguments are related to the function calls. When you use keyword
arguments in a function call, the caller identifies the arguments by the
parameter name. This allows you to skip arguments or place them out of
order because the Python interpreter is able to use the keywords provided to
match the values with parameters.

def printinfo( name, age ):


print ("Name: ", name)
print ("Age ", age)

# Now you can call printinfo function


printinfo( age=50, name="miki" )

Default Arguments
A default argument is an argument that assumes a default value if a value
is not provided in the function call for that argument.

def printinfo( name, age = 35 ):


print ("Name: ", name)
print ("Age ", age)

printinfo( name="miki" )

Keyword-only arguments
Those arguments that must be specified by their name while calling the
function is known as Keyword-only arguments. They are defined by placing
an asterisk ("*") in the function's parameter list before any keyword-only
parameters.

def posFun(*, num1, num2, num3):


print(num1 * num2 * num3)

posFun(num1=6, num2=8, num3=5)

Arbitrary or Variable-length Arguments


An asterisk (*) is placed before the variable name that holds the values of all
non-keyword variable arguments. This tuple remains empty if no additional
arguments are specified during the function call.

def printinfo( arg1, *vartuple ):


print (arg1)
for var in vartuple:
print (var)
return;

printinfo( 10 )
printinfo( 70, 60, 50 )

Order of Python Function Arguments


A function can have arguments of any of the types defined above. However,
the arguments must be declared in the following order −

 The argument list begins with the positional-only args, followed by the
slash (/) symbol.
 It is followed by regular positional args that may or may not be called
as keyword arguments.
 Then there may be one or more args with default values.
 Next, arbitrary positional arguments represented by a variable prefixed
with single asterisk, that is treated as tuple. It is the next.
 If the function has any keyword-only arguments, put an asterisk before
their names start. Some of the keyword-only arguments may have a
default value.
 Last in the bracket is argument with two asterisks ** to accept arbitrary
number of keyword arguments.

Anonymous Functions/ lambda functions


Syntax
lambda [arg1 [,arg2,.....argn]]:expression

Example:
sum = lambda arg1, arg2: arg1 + arg2;
# Now you can call sum as a function
print ("Value of total : ", sum( 10, 20 ))

Arbitrary Arguments (*args)


You may want to define a function that is able to
accept arbitrary or variable number of arguments
 An argument prefixed with a single asterisk * for arbitrary positional
arguments.
 An argument prefixed with two asterisks ** for arbitrary keyword
arguments.

Arbitrary Arguments Example


def add(*args):
for x in args:
print(x)

result = add(10,20,30,40)
print (result)
result = add(1,2,3)
print (result)
The args variable prefixed with "*" stores all the values passed to it. Here,
args becomes a tuple. We can run a loop over its items to add the
numbers.

Arbitrary Keyword Arguments (**kwargs)


If a variable in the argument list has two asterisks prefixed to it, the function
can accept arbitrary number of keyword arguments. The variable becomes
a dictionary of keyword:value pairs.
def addr(**kwargs):
for k,v in [Link]():
print ("{}:{}".format(k,v))

# pass 2 keyword args


addr(Name="John", City="Mumbai")

# pass 4 keyword args


addr(Name="Raam", City="Mumbai", ph_no="9123134567", PIN="400001")

Python Modules
A module is a file containing definition of functions, classes, variables,
constants or any other Python object. Contents of this file can be made
available to any other program. Python has the import keyword for this
purpose.

Python User-defined Modules


Any text file with .py extension and containing Python code is basically a
module. It can contain definitions of one or more functions, variables,
constants as well as classes. Any Python object from a module can be made
available to interpreter session or another Python script by import statement.

Creating a Python Module


Creating a module is nothing but saving a Python code with the help of any
editor. Save the following code having three functions as [Link].
def sum(x,y):
return x+y
def average(x,y):
return (x+y)/2
The import mymodule statement loads all the functions in this module in
the current namespace. To call any function, use the module object's
reference. For example, [Link]().
import mymodule
print ("sum:",[Link](10,20))
print ("average:",[Link](10,20))

The from ... import Statement


The import statement will load all the resources of the module in the current
namespace. It is possible to import specific objects from a module

Out of three functions in mymodule, only two are imported in following


executable script [Link] .Call these functions directly without
the module name
from mymodule import sum, average
print (sum(10,20))
The from...import * Statement
Import all the names from a module into the current namespace

Locating Modules
When you import a module, the Python interpreter searches for the module in
the following sequences −

 The current directory.


 If the module isn't found, Python then searches each directory in the
shell variable PYTHONPATH.
 If all else fails, Python checks the default path. On UNIX, this default
path is normally /usr/local/lib/python/.

Module Attributes
In Python, a module is an object of module class, and hence it is characterized by
attributes.
Following are the module attributes −
__file__ returns the physical name of the module.
__package__ returns the package to which the module belongs.
__doc__ returns the docstring at the top of the module if any
__dict__ returns the entire scope of the module
__name__ returns the name of the module
Save [Link] and with the following code -
def sum(x,y):
return x+y
print (sum(10,20))
You can see that [Link] has some executable statements(like execution
of the functions) along with the function definitions within the same script in
which it is defined.

Now let us import this function in another script [Link].


import mymodule
print ("sum:",[Link](10,20))
It will produce the following output −
sum: 30
sum: 30
The output "sum:30" appears twice. Once when mymodule module is imported.
The executable statements in imported module are also run. Second output is
from the calling script, i.e., [Link] program.

What we want to happen is that when a module is imported, only the function should
be imported, its executable statements should not run. This can be done by checking
the value of __name__. If it is __main__, means it is being run and not imported.
Include the executable statements like function calls conditionally.

Add if statement in [Link] as shown −


def sum(x,y):
return x+y
if __name__ == "__main__":
print ("sum:",sum(10,20))

String is an immutable sequence

Creating Python Strings


var1 = 'Hello World!'

Accessing Values in Strings


var1[0]
var2[1:5])

Updating Strings
You can "update" an existing string by (re)assigning a variable to
another string. The new value can be related to its previous value or to a
completely different string altogether. For example −

var1 = 'Hello World!'


var1 = var1[:6] + 'Python')
Updated String :- Hello Python

String Special Operators


Assume string variable a holds 'Hello' and variable b holds 'Python', then −
Operat
Description Example
or

Concatenation - Adds values on either side a &plus; b will give


&plus;
of the operator HelloPython

Repetition - Creates new strings,


a*2 will give -
* concatenating multiple copies of the same
HelloHello
string

Slice - Gives the character from the given


[] a[1] will give e
index

Range Slice - Gives the characters from the


[:] a[1:4] will give ell
given range

Membership - Returns true if a character


in H in a will give 1
exists in the given string

Membership - Returns true if a character


not in M not in a will give 1
does not exist in the given string

String Formatting Operator

print ("My name is %s and weight is %d kg!" % ('Zara', 21))

Sr.N
Format Symbol & Conversion
o.

%c
1
character

%s
2
string conversion via str() prior to formatting

%i
3
signed decimal integer

%d
4
signed decimal integer
%u
5
unsigned decimal integer

%o
6
octal integer

%x
7
hexadecimal integer (lowercase letters)

%f
8
floating point real number

Python Multiline Strings


Triple quoted string ’’’ ’’’ is useful to form a multi-line string.

var = '''
Welcome To
Python Tutorial
from TutorialsPoint
'''
Built-in String Methods
Python includes the following built-in methods to manipulate strings −

[Link]. Methods with Description

capitalize()
1
Capitalizes first letter of string.

casefold()
2 Converts all uppercase letters in string to lowercase. Similar to lower(),
but works on UNICODE characters alos.

center(width, fillchar)
3 Returns a space-padded string with the original string centered to a total
of width columns.

count(str, beg= 0,end=len(string))


4 Counts how many times str occurs in string or in a substring of string if
starting index beg and ending index end are given.

decode(encoding='UTF-8',errors='strict')
5 Decodes the string using the codec registered for encoding. encoding
defaults to the default string encoding.

encode(encoding='UTF-8',errors='strict')
6 Returns encoded string version of string; on error, default is to raise a
ValueError unless errors is given with 'ignore' or 'replace'.

endswith(suffix, beg=0, end=len(string))


Determines if string or a substring of string (if starting index beg and
7
ending index end are given) ends with suffix; returns true if so and false
otherwise.

expandtabs(tabsize=8)
8 Expands tabs in string to multiple spaces; defaults to 8 spaces per tab if
tabsize not provided.

find(str, beg=0 end=len(string))


Determine if str occurs in string or in a substring of string if starting
9
index beg and ending index end are given returns index if found and -1
otherwise.

format(*args, **kwargs)
10
This method is used to format the current string value.

11 format_map(mapping)
This method is also use to format the current string the only difference
is it uses a mapping object.

index(str, beg=0, end=len(string))


12
Same as find(), but raises an exception if str not found.

isalnum()
13 Returns true if string has at least 1 character and all characters are
alphanumeric and false otherwise.

isalpha()
14 Returns true if string has at least 1 character and all characters are
alphabetic and false otherwise.

isascii()
15 Returns True is all the characters in the string are from the ASCII
character set.

isdecimal()
16 Returns true if a unicode string contains only decimal characters and
false otherwise.

isdigit()
17
Returns true if string contains only digits and false otherwise.

isidentifier()
18
Checks whether the string is a valid Python identifier.

islower()
19 Returns true if string has at least 1 cased character and all cased
characters are in lowercase and false otherwise.

isnumeric()
20 Returns true if a unicode string contains only numeric characters and
false otherwise.

isprintable()
21
Checks whether all the characters in the string are printable.

isspace()
22 Returns true if string contains only whitespace characters and false
otherwise.

istitle()
23
Returns true if string is properly "titlecased" and false otherwise.

isupper()
24 Returns true if string has at least one cased character and all cased
characters are in uppercase and false otherwise.
join(seq)
25 Merges (concatenates) the string representations of elements in
sequence seq into a string, with separator string.

ljust(width[, fillchar])
26 Returns a space-padded string with the original string left-justified to a
total of width columns.

lower()
27
Converts all uppercase letters in string to lowercase.

lstrip()
28
Removes all leading white space in string.

maketrans()
29
Returns a translation table to be used in translate function.

partition()
30
Splits the string in three string tuple at the first occurrence of separator.

removeprefix()
31
Returns a string after removing the prefix string.

removesuffix()
32
Returns a string after removing the suffix string.

replace(old, new [, max])


33 Replaces all occurrences of old in string with new or at most max
occurrences if max given.

rfind(str, beg=0,end=len(string))
34
Same as find(), but search backwards in string.

rindex( str, beg=0, end=len(string))


35
Same as index(), but search backwards in string.

rjust(width,[, fillchar])
36 Returns a space-padded string with the original string right-justified to a
total of width columns.

rpartition()
37
Splits the string in three string tuple at the ladt occurrence of separator.

rsplit()
38
Splits the string from the end and returns a list of substrings.

rstrip()
39
Removes all trailing whitespace of string.
split(str="", num=[Link](str))
40 Splits string according to delimiter str (space if not provided) and
returns list of substrings; split into at most num substrings if given.

splitlines( num=[Link]('\n'))
41 Splits string at all (or num) NEWLINEs and returns a list of each line
with NEWLINEs removed.

startswith(str, beg=0,end=len(string))
Determines if string or a substring of string (if starting index beg and
42
ending index end are given) starts with substring str; returns true if so
and false otherwise.

strip([chars])
43
Performs both lstrip() and rstrip() on string.

swapcase()
44
Inverts case for all letters in string.

title()
45 Returns "titlecased" version of string, that is, all words begin with
uppercase and the rest are lowercase.

translate(table, deletechars="")
46 Translates string according to translation table str(256 chars), removing
those in the del string.

upper()
47
Converts lowercase letters in string to uppercase.

zfill (width)
Returns original string leftpadded with zeros to a total of width
48
characters; intended for numbers, zfill() retains any sign given (less one
zero).

Built-in Functions with Strings


Following are the built-in functions we can use with strings −

[Link]
Function with Description
.

len(list)
1
Returns the length of the string.

max(list)
2
Returns the max alphabetical character from the string str.
min(list)
3
Returns the min alphabetical character from the string str.
String slicing is a way of creating a sub-string from a given string. In this
process, we extract a portion or piece of a string. slice operator "[ : ]" to
perform slicing.

var[x:y] separates characters from xth position to (y-1)th position from the
original string.

Python String Slicing With Negative Indexing


var="HELLO PYTHON"
print ("var[3:8]:", var[3:8])
print ("var[-9:-4]:", var[-9:-4])
var: HELLO PYTHON
var[3:8]: LO PY
var[-9:-4]: LO PY
if both the operands are not used, the slice will be equal to the original string
var[:]: HELLO PYTHON

String modification
a string (object of str class) is of immutable type. Unlike a list, we cannot
overwrite any character in the sequence, nor can we insert or append
characters to it directly.

[Link] a String to a List


Suppose, we have a string variable s1 with WORD as its value and we are
required to convert it into a list. For this operation, we can use the list() built-
in function and insert a character L at index 3. Then, we can concatenate all
the characters using join() method of str class
s1="WORD"
print ("original string:", s1)
l1=list(s1)
[Link](3,"L")
print (l1)
s1=''.join(l1)
print ("Modified string:", s1)
It will produce the following output –

original string: WORD


['W', 'O', 'R', 'L', 'D']
Modified string: WORLD

String Concatenation using '+' operator


str3=str1+str2

String formatting
Using % operator
name = "Tutorialspoint" print("Welcome to %s!",name)

output −
Welcome to Tutorialspoint!

Using format() method


It is a built-in method of str class. The format() method works by defining
placeholders within a string using curly braces "{}". These placeholders are
then replaced by the values specified in the method's arguments.
str = "Welcome to {}"
print([Link]("Tutorialspoint"))
On running the above code, it will produce the following output –
Welcome to Tutorialspoint

Using f-string
The f-strings, also known as formatted string literals, is used to embed
expressions inside string literals. The "f" in f-strings stands for formatted and
prefixing it with strings creates an f-string. The curly braces "{}" within the
string will then act as placeholders that is filled with variables, expressions,
or function calls.

item1 = 2500
item2 = 300
total = f ' Total: {item1} , {item2} sums to {item1 + item2 }'
print(total)

The output of the above code is as follows −

Total: 2500,300 sums to 2800


Python Lists
List is one of the built-in data types in Python. A Python list is a sequence of
comma separated items, enclosed in square brackets [ ]. The items in a
Python list need not be of the same data type.

list1 = ["Rohan", "Physics", 21, 69.75]

Python list is mutable

Accessing Values in Lists


list1 = ['physics', 'chemistry', 1997, 2000];
list2 = [1, 2, 3, 4, 5, 6, 7 ];
list1[0]: physics
list2[1:5]: [2, 3, 4, 5]

Updating Lists
list[2] = 2001;

Delete List Elements


del list1[2];

Python List Operations


Python Expression Results Description

[1, 2, 3] + [4, 5, 6] [1, 2, 3, 4, 5, 6] Concatenation

['Hi!'] * 4 ['Hi!', 'Hi!', 'Hi!', 'Hi!'] Repetition

3 in [1, 2, 3] True Membership

Python List Methods


[Link]
Methods with Description
.

[Link](obj)
1
Appends object obj to list.

[Link]()
2
Clears the contents of list.
[Link]()
3
Returns a copy of the list object.

[Link](obj)
4
Returns count of how many times obj occurs in list

[Link](seq)
5
Appends the contents of seq to list

[Link](obj)
6
Returns the lowest index in list that obj appears

[Link](index, obj)
7
Inserts object obj into list at offset index

[Link](obj=list[-1])
8
Removes and returns last object or obj from list

[Link](obj)
9
Removes object obj from list

[Link]()
10
Reverses objects of list in place

[Link]([func])
11
Sorts objects of list, use compare func if given

Built-in Functions with Lists


Following are the built-in functions we can use with lists −

[Link]
Function with Description
.

cmp(list1, list2)
1
Compares elements of both lists.

len(list)
2
Gives the total length of the list.

max(list)
3
Returns item from the list with max value.

min(list)
4
Returns item from the list with min value.

list(seq)
5
Converts a tuple into list.
Change Consecutive List Items
list1 = ["a", "b", "c", "d"]

list1[1:3] = ['Y', 'Z']

List Comprehension in Python


concise way to create lists. It is similar to set builder notation in mathematics.
It is used to define a list based on an existing iterable object, such as a list,
tuple, or string, and apply an expression to each element in the iterable.

Syntax of Python List Comprehension


new_list = [expression for item in iterable if condition]

string = "hello world"


uppercase_letters = [[Link]() for char in string if [Link]()]
print(uppercase_letters)

The result obtained is displayed as follows −

['H', 'E', 'L', 'L', 'O', 'W', 'O', 'R', 'L', 'D']

List Comprehensions and Lambda


original_list = [1, 2, 3, 4, 5]
doubled_list = [(lambda x: x * 2)(x) for x in original_list]
Following is the output of the above code −

doubled_list = [2, 4, 6, 8, 10]

list1=[1,2,3]

list2=[4,5,6]

CombLst=[(x,y) for x in list1 for y in list2]

It will produce the following output −

[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
Conditionals in Python List Comprehension
list1=[x for x in range(1,21) if x%2==0]

We get the output as follows −


[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

chars = [ char for char in 'TutorialsPoint' if char not in


'aeiou']

list comprehension to build a list of squares of numbers between 1 to 10 −

squares = [x*x for x in range(1,11)]


print (squares)

The squares list object is −

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Sorting Lists Using sort() Method


The python sort() method is used to sort the elements of a list in place. This
means that it modifies the original list and does not return a new list.
list_name.sort(key=None, reverse=False)
If reverse=True, the list will be sorted in descending order. If reverse=False
(default), the list will be sorted in ascending order.

Using sorted() Method


returns a new sorted list, leaving the original iterable unchanged.
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5
sorted_numbers_desc = sorted(numbers, reverse=True)
Shallow Copy on a Python List
A shallow copy in Python creates a new object, but instead of copying the
elements recursively, it copies only the references to the original elements.
This means that the new object is a separate entity from the original one, but
if the elements themselves are mutable, changes made to those elements in
the new object will affect the original object as well.

original_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]


# Creating a shallow copy
shallow_copied_list = [Link](original_list)

even though we only modify the first element of the first sublist in the
shallow copied list, the same change is reflected in the original list as well.

This is because a shallow copy only creates new references to the original
objects, rather than creating copies of the objects themselves

Deep Copy on a Python List


A deep copy in Python creates a completely new object and recursively
copies all the objects referenced by the original object. This means that even
nested objects within the original object are duplicated, resulting in a fully
independent copy where changes made to the copied object do not affect the
original object

original_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]


# Creating a deep copy
deep_copied_list = [Link](original_list)

when we modify the first element of the first sublist in the deep copied list, it
does not affect the original list.

This is because a deep copy creates a new object and recursively copies all
the nested objects, ensuring that the copied object is fully independent from
the original one
Python tuple is a sequence of comma separated items, enclosed in
parentheses (). The items in a Python tuple need not be of same data type.

tup1 = ("Rohan", "Physics", 21, 69.75)

Difference b/w Tuple & List


Python list is mutable, whereas tuple is immutable.

Updating Tuples
tup1 = (12, 34.56);
# Following action is not valid for tuples -> tup1[0] = 100;

Delete Tuple Elements


tup = ('physics', 'chemistry', 1997, 2000);
del tup;

Built-in Functions with Tuples


[Link]
Function with Description
.

cmp(tuple1, tuple2)
1
Compares elements of both tuples.

len(tuple)
2
Gives the total length of the tuple.

max(tuple)
3
Returns item from the tuple with max value.

min(tuple)
4
Returns item from the tuple with min value.

tuple(seq)
5
Converts a list into tuple.

Updating Tuples Using append() function


first convert the original tuple "T1" to a list "list_T1". We then use a loop to
iterate over the new elements and append each new element to the list using
the append() function. Finally, we convert the updated list back to a tuple to
get the updated tuple
# Original tuple
T1 = (10, 20, 30, 40)
# Convert tuple to list
list_T1 = list(T1)
# Elements to be added
new_elements = [50, 60, 70]
# Updating the list using append()
for element in new_elements:
list_T1.append(element)
# Converting list back to tuple
updated_tuple = tuple(list_T1)

Unpack Tuple Items


The term "unpacking" refers to the process of parsing tuple items in
individual variables.
tup1 = (10,20,30)
x, y, z = tup1
print ("x: ", x, "y: ", "z: ",z)

ValueError While Unpacking a Tuple


If the number of variables is more or less than the length of tuple, Python
raises a ValueError.

tup1 = (10,20,30)
x, y = tup1
x, y, p, q = tup1 # ValueError: not enough values to unpack (expected 4,
got 3)
Unpack Tuple Items Using Asterisk (*)
In such a case, the "*" symbol is used for unpacking. Prefix "*" to "y", as
shown below −

tup1 = (10,20,30)
x, *y = tup1
print ("x:",x,"y:",y)
x: 10 y: [20, 30]

The first value in tuple is assigned to "x", and rest of items to "y" which
becomes a list.

Example 2
In this example, the tuple contains 6 values and variables to be unpacked are
3. We prefix "*" to the second variable.

tup1 = (10,20,30, 40, 50, 60)


x, *y, z = tup1
print ("x: ",x, "y: ", y, "z: ", z)
It will produce the following output −
x: 10 y: [20, 30, 40, 50] z: 60

Here, values are unpacked in "x" and "z" first, and then the rest of values are
assigned to "y" as a list.

Example 3
What if we add "*" to the first variable?

Open Compiler
tup1 = (10,20,30, 40, 50, 60)
*x, y, z = tup1
print ("x: ",x, "y: ", y, "z: ", z)
It will produce the following output −
x: [10, 20, 30, 40] y: 50 z: 60

Here again, the tuple is unpacked in such a way that individual variables take
up the value first, leaving the remaining values to the list "x".

Joining Tuples Using extend() Function


extend() function is not used for joining tuples in Python. It is used to extend
a list by appending elements from another iterable (such as another list)
We can join tuples using the extend() function by temporarily converting the
tuples into lists, performing the joining operation as if they were lists, and
then converting the resulting list back into a tuple.

T1 = (10,20,30,40)
T2 = ('one', 'two', 'three', 'four')
L1 = list(T1)
L2 = list(T2)
[Link](L2)
T1 = tuple(L1)
print ("Joined Tuple:", T1)

Sets in Python
In Python, a set is an unordered collection of unique elements. Unlike lists or
tuples, sets do not allow duplicate values i.e. each element in a set must be
unique. Sets are mutable, meaning you can add or remove items after a set
has been created.

Sets are defined using curly braces {} or the built-in set() function.

Using Curly Braces


You can directly define a set by listing its elements within curly braces,
separating each element by a comma as shown below −

my_set = {1, 2, 3, 4, 5}
print (my_set)

Using the set() Function


my_set = set([1, 2, 3, 4, 5])
print (my_set)

We get the output as shown below −

{1, 2, 3, 4, 5}
Duplicate Elements in Set
Sets in Python are unordered collections of unique elements. If you try to
create a set with duplicate elements, duplicates will be automatically
removed −

my_set = {1, 2, 2, 3, 3, 4, 5, 5}
print (my_set)

The result obtained is as shown below −

{1, 2, 3, 4, 5}

Adding Elements in a Set


my_set = {1, 2, 3}

1. [Link](obj)- include new elements into an existing set. If the


element is already present in the set, the set remains unchanged .

Ex- my_set.add(4)

2. [Link](obj)-Where, obj is a set or a sequence object (list, tuple,


string).

Ex- my_set.update([4])

3. union operator ( "|" operator or union() function)

Ex- combined_set1 = [Link](lang2) , combined_set2 = lang2 | lang3

Removing Elements from a Set

1. using the remove() function


my_set.remove(object)
2. using the discard() function
Unlike remove(), discard() does not raise an error if the element is not found
in the set
my_set.discard(object)
3. using the pop() function
my_set.pop()
Remove Items Existing in Both Sets
You can remove items that exist in both sets (i.e., the intersection of two
sets) using the difference_update() method or the subtraction operator (-=).
s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
s1.difference_update(s2)

Remove Items Existing in Either of the Sets


symmetric difference operation can be performed using the ^ operator or
symmetric_difference() method- results in a set containing elements that
are in either of the sets but not in their intersection.
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
result_set = set1 ^ set2
Resulting Set: {1, 2, 5, 6}

Remove Uncommon Set Items


 using the intersection_update() method:
set1.intersection_update(set2)
using the intersection_update() method to modify "set1" so that it only
contains elements that are also in "set2"
 intersection() Method
returns a new set object that consists of items common to existing sets.
s1 = {1,2,3,4,5} s2 = {4,5,6,7,8}
s3 = [Link](s2)

Symmetric Difference of Set Items


 symmetric_difference_update() method
symmetric difference between two sets is the collection of all the uncommon
items, rejecting the common elements
s1.symmetric_difference_update(s2)
 using the symmetric_difference() method
s3 = s1.symmetric_difference(s2)
Membership Testing in a Set – in & not in
operators
Sets provide an efficient way to check if an element is present in the set. You
can use the in keyword to perform this check, which returns True if the
element is present and False otherwise −

my_set = {1, 2, 3, 4}
if 2 in my_set:
print("2 is present in the set")

Set Operations
 Union − It combine elements from both sets using the union() function
or the | operator.
 Intersection − It is used to get common elements using the
intersection() function or the & operator.
 Difference − It is used to get elements that are in one set but not the
other using the difference() function or the - operator.
 Symmetric Difference − It is used to get elements that are in either
of the sets but not in both using the symmetric_difference() method or
the ^ operator.

Python Set Comprehensions


set_variable = {expression for item in iterable if condition}

Example
In the following example, we are creating a set containing the squares of
numbers from 1 to 5 using a set comprehension −

squared_set = {x**2 for x in range(1, 6)}


print(squared_set)

The output obtained is as follows −

{1, 4, 9, 16, 25}

Frozen Sets
In Python, a frozen set is an immutable collection of unique elements, similar
to a regular set but with the distinction that it cannot be modified after
creation. Once created, the elements within a frozen set cannot be added,
removed, or modified, making it a suitable choice when you need an
immutable set.
my_frozen_set = frozenset([1, 2, 3])

Access Subset From a Set


 issubset() function to check if one set is a subset of another.
 Iterate over all possible subsets of the set and filter based on
certain criteria to access specific subsets.
# Defining a set
original_set = {1, 2, 3, 4}

# Checking if {1, 2} is a subset of the original set


is_subset = {1, 2}.issubset(original_set)

Checking if Set Item Exists


Use Python's membership operators, in and not in.
langs = {"C", "C++", "Java", "Python"}

# Checking if an item exists in the set


if "Java" in langs:
print("Java is present in the set.")

Python Copy Sets- Using the copy() Method


lang1 = {"C", "C++", "Java", "Python"}
lang2 = [Link]()

Adding and Removing Elements


The following are the methods specifically designed for adding and removing
item/items into a set −

[Link]
Methods with Description
.

[Link]()
1
Add an element to a set.

[Link]()
2
Remove all elements from a set.
[Link]()
3
Return a shallow copy of a set.

[Link]()
4
Remove an element from a set if it is a member.

[Link]()
5
Remove and return an arbitrary set element.

[Link]()
6
Remove an element from a set; it must be a member.

Set Operations
These methods perform set operations such as union, intersection,
difference, and symmetric difference −

[Link]
Methods with Description
.

[Link]()
1
Update a set with the union of itself and others.

set.difference_update()
2
Remove all elements of another set from this set.

[Link]()
3
Returns the intersection of two sets as a new set.

set.intersection_update()
4
Updates a set with the intersection of itself and another.

[Link]()
5
Returns True if two sets have a null intersection.

[Link]()
6
Returns True if another set contains this set.

[Link]()
7
Returns True if this set contains another set.

set.symmetric_difference()
8
Returns the symmetric difference of two sets as a new set.

set.symmetric_difference_update()
9
Update a set with the symmetric difference of itself and another.

10 [Link]()
Returns the union of sets as a new set.

[Link]()
11
Returns the difference of two or more sets as a new set.

Dictionaries in Python
a dictionary is a built-in data type that stores data in key-value pairs. It is an
unordered, mutable, and indexed collection. Each key in a dictionary is
unique and maps to a value
numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
Key Features of Dictionaries
Following are the key features of dictionaries −

 Unordered − The elements in a dictionary do not have a specific


order. Python dictionaries before version 3.7 did not maintain insertion
order. Starting from Python 3.7, dictionaries maintain insertion order as
a language feature.
 Mutable − You can change, add, or remove items after the dictionary
has been created.
 Indexed − Although dictionaries do not have numeric indexes, they
use keys as indexes to access the associated values.
 Unique Keys − Each key in a dictionary must be unique. If you try to
assign a value to an existing key, the old value will be replaced by the
new value.
 Heterogeneous − Keys and values in a dictionary can be of any data
type.

Creating a Dictionary
 using curly braces
sports_player = {
"Name": "Sachin Tendulkar",
"Age": 48,
"Sport": "Cricket"
}
 using the dict() function
student_info = dict(name="Alice", age=21, major="Computer Science")
Accessing Dictionary Items

1. using square brackets []


value = dict [key]

student_info = {
"name": "Alice",
"age": 21,
"major": "Computer Science"
}
# Accessing values using square brackets
name = student_info["name"]

2. Using get() Method-

value = [Link]("key")

Access Dictionary Keys


[Link]()

Removing Dictionary Items


 del statement- del student_info["major"]
del dictionary_name[key]

 the pop() method-


dictionary_name.pop(key)
student_info.pop("graduation_year")

 popitem() method
dictionary_name.popitem(key)

Iterating Through a Dictionary


# Iterating through keys
for key in student_info:
print("Keys:",key, student_info[key])
# Iterating through values
for value in student_info.values():
print("Values:",value)

# Iterating through key-value pairs


for key, value in student_info.items():
print("Key:Value:",key, value)
Python Dictionary Operators
In Python, following operators are defined to be used with dictionary
operands. In the example, the following dictionary objects are used.

d1 = {'a': 2, 'b': 4, 'c': 30}


d2 = {'a1': 20, 'b1': 40, 'c1': 60}
Operator Description Example

print (d1['b']) retrieves


Extract/assign the value 4
dict[key]
mapped with key d1['b'] = 'Z' assigns
new value to key 'b'

d3=d1|d2 ; print (d3)


Union of two dictionary
{'a': 2, 'b': 4, 'c': 30,
dict1|dict2 objects, returning new
'a1': 20, 'b1': 40, 'c1':
object
60}

d1|=d2; print (d1)


Augmented dictionary union {'a': 2, 'b': 4, 'c': 30,
dict1|=dict2
operator 'a1': 20, 'b1': 40, 'c1':
60}

Python Dictionary Methods


Python includes following dictionary methods −

[Link]
Methods with Description
.

[Link]()
1
Removes all elements of dictionary dict

[Link]()
2
Returns a shallow copy of dictionary dict
[Link]()
3
Create a new dictionary with keys from seq and values set to value.

[Link](key, default=None)
4
For key key, returns value or default if key not in dictionary

dict.has_key(key)
5
Returns true if key in dictionary dict, false otherwise

[Link]()
6
Returns a list of dict's (key, value) tuple pairs

[Link]()
7
Returns list of dictionary dict's keys

[Link](key, default=None)
8 Similar to get(), but will set dict[key]=default if key is not already in
dict

[Link](dict2)
9
Adds dictionary dict2's key-values pairs to dict

[Link]()
10
Returns list of dictionary dict's values

Built-in Functions with Dictionaries


Following are the built-in functions we can use with Dictionaries −

Sr.N
Function with Description
o.

cmp(dict1, dict2)
1
Compares elements of both dict.

len(dict)
2 Gives the total length of the dictionary. This would be equal to the
number of items in the dictionary.

str(dict)
3
Produces a printable string representation of a dictionary

type(variable)
4 Returns the type of the passed variable. If passed variable is dictionary,
then it would return a dictionary type.
Updating Multiple Dictionary Values
person = {'name': 'Alice', 'age': 25, 'city': 'New York'}
# Updating multiple values
[Link]({'age': 26, 'city': 'Los Angeles'})

Adding New Key-Value Pairs


person = {'name': 'Alice', 'age': 25}
# Adding a new key-value pair 'city': 'New York'
person['city'] = 'New York'

Copy Dictionaries

1. Shallow Copy
- using the copy() method
original_dict = {"name": "Alice", "age": 25}
shallow_copy = original_dict.copy()

2. Deep Copy
- using the deepcopy() method
original_dict = {"name": "Alice", "age": 25}
deep_copy = [Link](original_dict)

What are arrays?


An array is a container which can hold a fix number of items and these items
should be of the same type. Each item stored in an array is called
an element and they can be of any type including integers, floats, strings,
etc.

Creating Array in Python


To create an array in Python, import the array module and use its array()
function

Syntax
import array as array_name

# creating array
obj = array_name.array(typecode[, initializer])

Where,

 typecode − The typecode character used to speccify the type of


elements in the array.
 initializer − It is an optional value from which array is initialized. It
must be a list, a bytes-like object, or iterable elements of the
appropriate type.

from array import *

# creating an array with integer type


a = array('i', [1, 2, 3])

# creating an array with char type


a = array('u', 'BAT')

# creating an array with float type


a = array('d', [1.1, 2.2, 3.3])

typeco
Python data type Byte size
de

'b' signed integer 1

'B' unsigned integer 1

'u' Unicode character 2

'h' signed integer 2

'H' unsigned integer 2


'i' signed integer 2

'I' unsigned integer 2

'l' signed integer 4

'L' unsigned integer 4

'q' signed integer 8

'Q' unsigned integer 8

'f' floating point 4

'd' floating point 8

[Link]. Methods with Description

append(x)
1
Appends a new item with value x to the end of the array.

extend(iterable)
2
Appends items from iterable to the end of the array.

insert(i, x)
3
Inserts a new item with value x before position i.

array_name.pop([i])
4 Removes and returns the item with index i. If i is not specified, removes and returns the
last item.

array_name.remove(item)
5
Removes the first occurrence of item from the array.

Information and Utility Methods


These methods are used for obtaining information about arrays and to
perform utility operations −

Sr.N
Methods with Description
o.

buffer_info()
1 Returns a tuple (address, length) giving the current memory address and the length in
elements of the buffer used to hold the arrays contents.
count(x)
2
Returns the number of occurrences of x in the array.

index(x[, start[, stop]])


3 Returns the smallest index where x is found in the array. Optional start and stop
arguments can specify a sub-range to search.

Manipulating Array Elements


Following methods are used for manipulating array elements, such as
reversing the array or byteswapping values.

[Link]
Methods with Description
.

reverse()
1
Reverses the order of the items in the array.

byteswap()
2 "Byteswaps" all items of the array, useful for reading data from a file written on a
machine with a different byte order.

Conversion Methods
These methods are used to convert arrays to and from bytes, files, lists, and
Unicode strings.

[Link]
Methods with Description
.

frombytes(buffer)
1 Appends items from the bytes-like object, interpreting its content as an array of machine
values.

tobytes()
2
Converts the array to a bytes representation.

fromfile(f, n)
3
Reads n items from the file object f and appends them to the array.

tofile(f)
4
Writes all items to the file object f.

fromlist(list)
5
Appends items from the list to the array.
tolist()
6
Converts the array to a list with the same items.

fromunicode(s)
7 Extends the array with data from the given Unicode string. The array must have type
code 'u'.

tounicode()
8
Converts the array to a Unicode string. The array must have type code 'u'.

Accessing array items in Python

Using indexing
numericArray = array('i', [111, 211, 311, 411, 511])
print (numericArray[0])

Using iteration
numericArray = [Link]('i', [111, 211, 311, 411, 511])

for i in numericArray:
print(i)

Adding Elements to Python Array


 using array_name.append(item)
a = array('i', [1, 2, 3])
[Link](10)

 Using array_name.insert(index,item)
a = [Link]('i', [1, 2, 3])
[Link](1,20)

 Using array_name.extend(array2) method


 Using array_name.extend(item) method

Ways to Reverse an Array in Python


 Using slicing operation
reverseArray = origArray[ : : -1]

 Using reverse() Method of List Structure

reverse() is a method of list class, we cannot directly use it to reverse an


array created through the Python array module. We have to first transfer the
contents of an array to a list with tolist() method of array class, then we
call the reverse() method and at the end, when we convert the list back to an
array, we get the array with reversed order.

numericArray = [Link]('i', [10,5,15,4,6,20,9])

# converting the array into list


newArray = [Link]()

# reversing the list


[Link]()

# creating a new array from reversed list


revArray = [Link]('i', newArray)
print ("Array after reversing:",revArray)

 Using reversed() Method

numericArray = [Link]('i', [12, 10, 14, 16, 20, 18])

# reversing the array


newArray = list(reversed(numericArray))

# creating a new array from reversed list


revArray = [Link]('i', newArray)
Sort Arrays
 Using the sort() method from List
First, declare an array and obtain a list object from it, using tolist() method.
Then, use the sort() method to get a sorted list. Lastly, create another array
using the sorted list which will display a sorted array.

orgnlArray = [Link]('i', [10,5,15,4,6,20,9])

# converting to list
sortedList = [Link]()

# sorting the list


[Link]()

# creating array from sorted list


sortedArray = [Link]('i', sortedList)

 Using sorted() Method


a = [Link]('i', [4, 5, 6, 9, 10, 15, 20])
sorted(a)

First Class functions in Python


Characteristics of First-Class Functions
 Assigned to Variables : We can assign functions to
variables.
 Passed as Arguments: We can pass functions as
arguments to other functions.
 Returned from Functions: Functions can return other
functions.
 Stored in Data Structures: Functions can be stored in
data structures such as lists, dictionaries, etc.

Python Lambda/ One-line/Anonymous


Functions
Python Lambda Functions are anonymous functions
means that the function is without a name.
Python Lambda Function Syntax
Syntax: lambda arguments : expression
 lambda: The keyword to define the function.
 arguments: A comma-separated list of input
parameters (like in a regular function).
 expression: A single expression that is evaluated and
returned.

lambda with Condition Checking


A lambda function can include conditions using if statements.
Example:
# Example: Check if a number is positive, negative, or zero
n = lambda x: "Positive" if x > 0 else "Negative" if x < 0 else "Zero"
print(n(5))

Lambda with if-else


lambda functions can incorporate conditional logic directly,
allowing us to handle simple decision making within the function.
Example:
# Example: Check if a number is even or odd
check = lambda x: "Even" if x % 2 == 0 else "Odd"

print(check(4))

# Example: Perform addition and multiplication in a single line


calc = lambda x, y: (x + y, x * y)
res = calc(3, 4)

Python map() function


map() function is used to apply a given function to every item
of an iterable, such as a list or tuple, and returns a map
object (which is an iterator).

Q. Using map() to convert a list of strings into a list of integers.

s = ['1', '2', '3', '4']


res = map(int, s)
print(list(res))

used the built-in int function to convert each string in the list s
into an integer. The map() function takes care of
applying int() to every element
Syntax of the map() function
map(function, iterable)
Parameter:
 function: The function we want to apply to every
element of the iterable.
 iterable: The iterable whose elements we want to
process.
By default, the map() function returns a map object, which is
an iterator. In many cases, we will need to convert
this iterator to a list/tuple to work with the results directly.

Example: Let's see how to double each elements of the given


list.
a = [1, 2, 3, 4]

# Using custom function in "function" parameter


# This function is simply doubles the provided number
def double(val):
return val*2

res = list(map(double, a))


print(res)

Output
[2, 4, 6, 8]
Explanation:
 The map() function returned an iterator, which we then
converted into a list using list(). This is a common
practice when working with map()
 We used a custom function to double each value in
the list a. The result was mapped and converted into a
list for easy display.

map() with lambda


We can use a lambda function instead of a custom function
with map() to make the code shorter and easier. Let's see how
to improve the above code for better readability.
a = [1, 2, 3, 4]

# Using lambda function in "function" parameter


# to double each number in the list
res = list(map(lambda x: x * 2, a))
print(res)

Output
[2, 4, 6, 8]
Explanation: We used lambda x: x * 2 to double each value in
the list a. The result was mapped and converted into a list for
easy display.

Using map() with multiple iterables


We can use map() with multiple iterables if the function we are
applying takes more than one argument.
Example: In this example, map() takes two iterables (a and b)
and applies the lambda function to add corresponding elements
from both lists.
a = [1, 2, 3]
b = [4, 5, 6]
res = map(lambda x, y: x + y, a, b)

filter() in python
The filter() method filters the given sequence with the help of a
function that tests each element in the sequence to be true or not
Python filter() Syntax
The filter() method in Python has the following syntax:
Syntax: filter(function, sequence)
 function: A function that defines the condition to filter
the elements. This function should return True for items
you want to keep and False for those you want to
exclude.
 iterable: The iterable you want to filter (e.g., list, tuple,
set).

By default, the filter() function returns an iterator. In many


cases, we will need to convert this iterator to a list/tuple to
work with the results directly

Example Usage of filter()


# Function to check if a number is even
def even(n):
return n % 2 == 0

a = [1, 2, 3, 4, 5, 6]
b = filter(even, a)

# Convert filter object to a list


print(list(b))
Output
[2, 4, 6]
Explanation:
 Function: even function checks if a number is divisible
by 2.
 Filter: The filter() applies this function to each item in
numbers.
 Result: A new iterable containing only even numbers is
returned.

Using filter() with lambda


For concise conditions, we can use a lambda function instead of
defining a named function.
a = [1, 2, 3, 4, 5, 6]
b = filter(lambda x: x % 2 == 0, a)

print(list(b))

Output
[2, 4, 6]
Here, the lambda function replaces even and directly defines the
condition x % 2 == 0 inline.

Decorators in Python

 A decorator is essentially a function that takes another
function as an argument and returns a new function with
enhanced functionality. Decorators modify or extend the
behavior of functions or methods, without changing their
actual code.
This can happen only because python functions are 1st
class citizens.
There are 2 types of decorators available in python
 Built in
decorators like @staticmethod, @classmethod, @abstractme
thod, @property etc
 User defined decorators that we programmers can create
according to our needs
Syntax of Decorator Parameters
def decorator_name(func):
def wrapper(*args, **kwargs):
# Add functionality before the original function call
result = func(*args, **kwargs)
# Add functionality after the original function call
return result
return wrapper
@decorator_name
def function_to_decorate():
# Original function code
pass

Explanation of Parameters
1. decorator_name(func):
 decorator_name: This is the name of the decorator
function.
 func: This parameter represents the function being
decorated. When you use a decorator, the decorated
function is passed to this parameter.
2. wrapper(*args, **kwargs):
 wrapper: This is a nested function inside the decorator.
It wraps the original function, adding additional
functionality.
 *args: This collects any positional arguments passed to
the decorated function into a tuple.
 **kwargs: This collects any keyword arguments passed
to the decorated function into a dictionary.
 The wrapper function allows the decorator to handle
functions with any number and types of arguments.
3. @decorator_name:
 This syntax applies the decorator to
the function_to_decorate function. It is equivalent to
writing function_to_decorate =
decorator_name(function_to_decorate).

Decorator Examples:
# simple example

def my_decorator(func):
def wrapper():
print('***********************')
func()
print('***********************')
return wrapper

def hello():
print('hello')

def display():
print('hello nitish')

a = my_decorator(hello)
a()

b = my_decorator(display)
b()

Output
***********************
hello
***********************
***********************
hello nitish
***********************

Example 2:

# A simple decorator function


def decorator(func):

def wrapper():
print("Before calling the function.")
func()
print("After calling the function.")
return wrapper

# Applying the decorator to a function


@decorator
def greet():
print("Hello, World!")

greet()

Output
Before calling the function.
Hello, World!
After calling the function.
Explanation:
 decorator takes the greet function as an argument.
 It returns a new function (wrapper) that first prints a
message, calls greet() and then prints another message.
 The @decorator syntax is a shorthand for greet =
decorator(greet).

Types of Decorators
1. Function Decorators:
The most common type of decorator, which takes a function as
input and returns a new function. The example above
demonstrates this type.
def simple_decorator(func):
def wrapper():
print("Before calling the function.")
func()
print("After calling the function.")
return wrapper

@simple_decorator
def greet():
print("Hello, World!")

greet()

Output
Before calling the function.
Hello, World!
After calling the function.
Explanation:
 simple_decorator(func): This decorator takes the
function greet as an argument (func) and returns a new
function (wrapper) that adds some functionality before
and after calling the original function.
 @simple_decorator: This is the decorator syntax. It
applies the simple_decorator to the greet function.
 Calling greet(): When greet() is called, it doesn't just
execute the original function but first runs the added
behavior from the wrapper function.

import time

def timer(func):
def wrapper(*args):
start = [Link]()
func(*args)
print('time taken by',func.__name__,[Link]()-start,'secs')
return wrapper

@timer
def hello():
print('hello wolrd')
[Link](2)

@timer
def square(num):
[Link](1)
print(num**2)

@timer
def power(a,b):
print(a**b)

hello()
square(2)
power(2,3)

In this example , we need our decorator to work robustly for


various functions that may require 0 , 1 or more arguments, so
we need our decorator’s wrapper() to accept and handle variable
number of arguments from the function it is decorating . We do
this using wrapper(*args)
2. Method Decorators:
Used to decorate methods within a class. They often handle
special cases, such as the self argument for instance methods.
def method_decorator(func):
def wrapper(self, *args, **kwargs):
print("Before method execution")
res = func(self, *args, **kwargs)
print("After method execution")
return res
return wrapper

class MyClass:
@method_decorator
def say_hello(self):
print("Hello!")

obj = MyClass()
obj.say_hello()

Output
Before method execution
Hello!
After method execution
Explanation:
 method_decorator(func): The decorator takes the
method (say_hello) as an argument (func). It returns a
wrapper function that adds behavior before and after
calling the original method.
 wrapper(self, *args, **kwargs): The wrapper must
accept self because it is a method of an instance. self is
the instance of the class and *args and **kwargs allow
for other arguments to be passed if needed.
 @method_decorator: This applies the
method_decorator to the say_hello method of MyClass.
 Calling obj.say_hello(): The say_hello method is now
wrapped with additional behavior.

3. Class Decorators
Class decorators are used to modify or enhance the behavior of a
class. Like function decorators, class decorators are applied to
the class definition. They work by taking the class as an
argument and returning a modified version of the class.
Example:
def fun(cls):
cls.class_name = cls.__name__
return cls

@fun
class Person:
pass

print(Person.class_name)

Output
Person
Explanation:
 add_class_name(cls): This decorator adds a new
attribute, class_name, to the class cls. The value of
class_name is set to the name of the class
(cls.__name__).
 @add_class_name: This applies the add_class_name
decorator to the Person class.
 Result: When the Person class is defined, the decorator
automatically adds the class_name attribute to it.
 print(Person.class_name): Accessing the class_name
attribute that was added by the decorator prints the
name of the class, Person.

Common Built-in Decorators in Python


Python provides several built-in decorators that are commonly
used in class definitions. These decorators modify the behavior
of methods and attributes in a class, making it easier to manage
and use them effectively. The most frequently used built-in
decorators are @staticmethod, @classmethod, and @property.
@staticmethod
The @staticmethod decorator is used to define a method that
doesn't operate on an instance of the class (i.e., it doesn't
use self). Static methods are called on the class itself, not on an
instance of the class.
Example:
class MathOperations:
@staticmethod
def add(x, y):
return x + y

# Using the static method


res = [Link](5, 3)
print(res)
Output
8
Explanation:
 add is a static method defined with the @staticmethod
decorator.
 It can be called directly on the class MathOperations
without creating an instance.
@classmethod
The @classmethod decorator is used to define a method that
operates on the class itself (i.e., it uses cls). Class methods can
access and modify class state that applies across all instances of
the class.
Example:
class Employee:
raise_amount = 1.05

def __init__(self, name, salary):


[Link] = name
[Link] = salary

@classmethod
def set_raise_amount(cls, amount):
cls.raise_amount = amount

# Using the class method


Employee.set_raise_amount(1.10)
print(Employee.raise_amount)

Output
1.1
Explanation:
 set_raise_amount is a class method defined with the
@classmethod decorator.
 It can modify the class variable raise_amount for the
class Employee and all its instances.
@property
The @property decorator is used to define a method as a
property, which allows you to access it like an attribute. This is
useful for encapsulating the implementation of a method while
still providing a simple interface.
Example:
class Circle:
def __init__(self, radius):
self._radius = radius

@property
def radius(self):
return self._radius

@[Link]
def radius(self, value):
if value >= 0:
self._radius = value
else:
raise ValueError("Radius cannot be negative")

@property
def area(self):
return 3.14159 * (self._radius ** 2)

# Using the property


c = Circle(5)
print([Link])
print([Link])
[Link] = 10
print([Link])

Output
5
78.53975
314.159
Explanation:
 radius and area are properties defined with the
@property decorator.
 The radius property also has a setter method to allow
modification with validation.
 These properties provide a way to access and modify
private attributes while maintaining encapsulation.

Python OOPs Concepts


Create a Class
# define a class
class Dog:
sound = "bark" # class attribute
Create Object
An Object is an instance of a Class. It represents a specific
implementation of the class and holds its own data.
Now, let's create an object from Dog class.

class Dog:
sound = "bark"

# Create an object from the class


dog1 = Dog()

# Access the class attribute


print([Link])

sound attribute is a class attribute. It is shared across all


instances of Dog class, so can be directly accessed through
instance dog1.

Using __init__() Function


In Python, class has __init__() function. It automatically initializes
object attributes when an object is created.
class Dog:
species = "Canine" # Class attribute

def __init__(self, name, age):


[Link] = name # Instance attribute
[Link] = age # Instance attribute
Explanation:
 class Dog: Defines a class named Dog.
 species: A class attribute shared by all instances of the
class.
 __init__ method: Initializes the name and age attributes
when a new object is created.
Initiate Object with __init__
class Dog:
species = "Canine" # Class attribute

def __init__(self, name, age):


[Link] = name # Instance attribute
[Link] = age # Instance attribute

# Creating an object of the Dog class


dog1 = Dog("Buddy", 3)
print([Link]) # Output: Buddy
print([Link]) # Output: Canine

Output
Buddy
Canine
Explanation:
 dog1 = Dog("Buddy", 3): Creates an object of the Dog
class with name as "Buddy" and age as 3.
 [Link]: Accesses the instance attribute name of
the dog1 object.
 [Link]: Accesses the class attribute species of
the dog1 object.
Self Parameter
self parameter is a reference to the current instance of the class.
It allows us to access the attributes and methods of the object.
class Dog:
def __init__(self, name, age):
[Link] = name
[Link] = age

def bark(self):
print(f"{[Link]} is barking!")

# Creating an instance of Dog


dog1 = Dog("Buddy", 3)
[Link]()

Output
Buddy is barking!
Explanation:
 Inside bark(), [Link] accesses the specific dog's name
and prints it.
 When we call [Link](), Python automatically passes
dog1 as self, allowing access to its attributes.
__str__ Method
__str__ method in Python allows us to define a custom string
representation of an object. By default, when we print an object
or convert it to a string using str(), Python uses the default
implementation, which returns a string like
<__main__.ClassName object at 0x00000123>.
class Dog:
def __init__(self, name, age):
[Link] = name
[Link] = age

def __str__(self):
return f"{[Link]} is {[Link]} years old." # Correct: Returning a
string

dog1 = Dog("Buddy", 3)
dog2 = Dog("Charlie", 5)

print(dog1)
print(dog2)

Output
Buddy is 3 years old.
Charlie is 5 years old.
Explanation:
 __str__ Implementation: Defined as a method in the
Dog class. Uses the self parameter to access the
instance's attributes (name and age).
 Readable Output: When print(dog1) is called, Python
automatically uses the __str__ method to get a string
representation of the object. Without __str__, calling
print(dog1) would produce something like <__main__.Dog
object at 0x00000123>.

Class and Instance Variables in Python


In Python, variables defined in a class can be either class
variables or instance variables, and understanding the distinction
between them is crucial for object-oriented programming.

Class Variables
These are the variables that are shared across all instances of a
class. It is defined at the class level, outside any methods. All
objects of the class share the same value for a class variable
unless explicitly overridden in an object.

Instance Variables
Variables that are unique to each instance (object) of a class.
These are defined within __init__ method or other instance
methods. Each object maintains its own copy of instance
variables, independent of other objects.
Example:
class Dog:
# Class variable
species = "Canine"

def __init__(self, name, age):


# Instance variables
[Link] = name
[Link] = age

# Create objects
dog1 = Dog("Buddy", 3)
dog2 = Dog("Charlie", 5)

# Access class and instance variables


print([Link]) # (Class variable)
print([Link]) # (Instance variable)
print([Link]) # (Instance variable)

# Modify instance variables


[Link] = "Max"
print([Link]) # (Updated instance variable)

# Modify class variable


[Link] = "Feline"
print([Link]) # (Updated class variable)
print([Link])

Output
Canine
Buddy
Charlie
Max
Feline
Feline
Explanation:
 Class Variable (species): Shared by all instances of
the class. Changing [Link] affects all objects, as it's
a property of the class itself.
 Instance Variables (name, age): Defined in the
__init__ method. Unique to each instance (e.g.,
[Link] and [Link] are different).
 Accessing Variables: Class variables can be accessed
via the class name ([Link]) or an object
([Link]). Instance variables are accessed via the
object ([Link]).
 Updating Variables: Changing [Link] affects all
instances. Changing [Link] only affects dog1 and
does not impact dog2.

self in Python class


Last Updated : 26 Feb, 2025



In Python, self is a fundamental concept when working
with object-oriented programming (OOP). It represents the
instance of the class being used. Whenever we create an object
from a class, self refers to the current object instance. It is
essential for accessing attributes and methods within the class.

What is the Purpose of "self"?


In Python, self is used as the first parameter in instance
methods to refer to the current object. It allows methods within
the class to access and modify the object's attributes, making
each object independent of others.
When we call a method on an object, self automatically gets
passed to the method, referring to the specific instance of the
class the method is acting upon. Without self, Python wouldn't
know which instance’s attributes or methods to refer to.
The Role of "self" in Constructors and Methods
Self in the Constructor (__init__ method)
__init__ method is called when a new instance of the class is
created. This method serves as the constructor for the class and
initializes the object's attributes. The first argument of the
__init__ method must always be self, as it allows the method to
set instance attributes for the object being created.
Example:
class Subject:

def __init__(self, attr1, attr2):


self.attr1 = attr1
self.attr2 = attr2

obj = Subject('Maths', 'Science')


print(obj.attr1)
print(obj.attr2)

Output
Maths
Science
Explanation: In this example, self.attr1 and self.attr2 refer to
the attributes of the current object, ensuring that each object
can have its own values for these attributes.

Self in Instance Methods


Any method within the class that operates on an instance of the
class must include self as the first parameter. It allows us to
access the instance's attributes and other methods.
Example:
class Car:
def __init__(self, model, color):
[Link] = model
[Link] = color

def show(self):
print("Model is", [Link])
print("Color is", [Link])

# Creating instances of the class


audi = Car("Audi A4", "Blue")
ferrari = Car("Ferrari 488", "Green")

# Calling instance methods


[Link]()
[Link]()

Output
Model is Audi A4
Color is Blue
Model is Ferrari 488
Color is Green
Explanation: In this example, self allows each instance to retain
its unique attributes, such as model and color and
the show() method displays them.

Class and Instance Attributes in Python


Last Updated : 05 Sep, 2024



Class attributes: Class attributes belong to the class itself they
will be shared by all the instances. Such attributes are defined in
the class body parts usually at the top, for legibility.

class sampleclass:
count = 0 # class attribute

def increase(self):
[Link] += 1

# Calling increase() on an object


s1 = sampleclass()
[Link]()
print([Link])

# Calling increase on one more


# object
s2 = sampleclass()
[Link]()
print([Link])

print([Link])
Output:
1
2
2

Instance Attributes
Unlike class attributes, instance attributes are not shared by
objects. Every object has its own copy of the instance attribute (In
case of class attributes all object refer to single copy). To list the
attributes of an instance/object, we have two functions:- 1.

class emp:
def __init__(self):
[Link] = 'xyz' # instance attribute
[Link] = 4000 # instance attribute

def show(self):
print([Link])
print([Link])

e1 = emp()
print("Dictionary form :", vars(e1))
print(dir(e1))

Inner Class in Python


A class defined in another class is known as an inner class or
nested class. If an object is created using child class means inner
class then the object can also be used by parent class or root
class. A parent class can have one or more inner classes but
generally inner classes are avoided.

Syntax:
# create NameOfOuterClass class
class NameOfOuterClass:
# Constructor method of outer class
def __init__(self):
[Link] = Value
# create Inner class object
[Link] = [Link]()

# create a NameOfInnerClass class


class NameOfInnerClass:
# Constructor method of inner class
def __init__(self):
[Link] = Value
# create object of outer class
outer = NameOfOuterClass()

Example:
 First, we create a class and then the constructor of the
class.
 After creating a class, we will create another class within
that class, the class inside another class will be called an
inner class.
class Color:

# constructor method

def __init__(self):

# object attributes

[Link] = 'Green'
[Link] = [Link]()

def show(self):
print('Name:', [Link])
# create Inner Lightgreen class

class Lightgreen:

def __init__(self):
[Link] = 'Light Green'
[Link] = '024avc'

def display(self):
print('Name:', [Link])
print('Code:', [Link])

# create Color class object


outer = Color()

# method calling
[Link]()

# create a Lightgreen
# inner class object

g = [Link]

# inner class method calling

[Link]()
Output:
Name: Green
Name: Light Green
Code: 024avc

Creating Instance Objects in Python


In Python, an instance object is an individual object created
from a class, which serves as a blueprint defining the attributes
(data) and methods (functions) for the object. When we create
an object from a class, it is referred to as an instance. Each
instance has its own unique data but shares the class's
methods. Example:
class Person:
def __init__(self, name, age):
[Link] = name
[Link] = age

# instance of the class


a = Person("John Doe", 25)

# Accessing attributes
print([Link])
print([Link])

Output
John Doe
25
Explanation:
 __init__ method takes two parameters, name and age
and initializes them for each instance.
 We then create an instance called a and pass the values
"John Doe" and 25 to the constructor.
 We can access the instance's attributes using dot
notation, such as [Link] and [Link].

Examples of creating instance object

Example 1: In this example, we define a simple Car class to


represent a car with basic attributes like make, model
and year. We also add a method to simulate driving the car,
which increases its mileage.
class Car:
def __init__(self, make, model, year):
[Link] = make
[Link] = model
[Link] = year
[Link] = 0 # Mileage starts at 0

def drive(self, distance):


[Link] += distance

a = Car("Toyota", "Camry", 2022) # Car object

print(f"{[Link]} {[Link]} ({[Link]})")


[Link](100)
print(f"Mileage: {[Link]} miles")

Example 2: In this example, we create a base class Animal and a derived


class Dog. We use super() to call the parent class constructor and set the species to
"Dog" by default.
class Animal:
def __init__(self, species):
[Link] = species # Base class attribute
class Dog(Animal):
def __init__(self, name, age):
super().__init__("Dog") # Set species as 'Dog'
[Link] = name
[Link] = age

dog = Dog("Buddy", 3) # Dog instance

print(f"{[Link]} is a {[Link]} of age {[Link]} years")

Explanation:
 Animal is a base class with one attribute species.
 Dog inherits from Animal and uses super() to set
species as "Dog".
 dog object has a name and age along with inherited
species.

Example 3: This example demonstrates encapsulation by


using double underscores (__) to make the balance attribute
private. The class provides methods to deposit, withdraw and
view the balance securely.
class Bank:
def __init__(self, name, bal=0):
[Link] = name
self.__bal = bal

def deposit(self, amt):


if amt > 0: self.__bal += amt

def withdraw(self, amt):


if 0 < amt <= self.__bal: self.__bal -= amt

def get_bal(self):
return self.__bal

acc = Bank("Alice", 500)


[Link](200)
[Link](150)
print(acc.get_bal())

Explanation:
 __bal attribute is private, meaning it cannot be accessed
directly from outside the class.
 methods deposit(), withdraw() and get_bal() provide
safe access and modification to the balance.
 After depositing 200 and withdrawing 150, the final
balance is 550.

Dynamic Attributes in Python


Dynamic attributes in Python are terminologies for attributes
that are defined at runtime, after creating the objects or
instances.

Example 1:
class GFG:

employee = True

# Driver Code
e1 = GFG()
e2 = GFG()

[Link] = False
[Link] = "Nikhil"

print([Link])
print([Link])
print([Link])

# this will raise an error as name is a dynamic attribute created only for
the e2 object
print([Link])

Dynamic attribute for object e1 is "employee" and for object e2


is "name". This is defined at runtime and not at compile time like
static attributes.
Note:
 The class “GFG” ,object e1 all and other objects or
instances of this class do not know the attribute “name”
created only for the e2 object. It is only defined for the
instance “e2”.
 The class “GFG” ,object e2 all and other objects or
instances of this class do not know the attribute
“employee” created only for the e1 object. It is only defined
for the instance “e1”.

Constructors in Python
The method __new__ is the constructor that creates a new
instance of the class while __init__ is the initializer that sets up
the instance's attributes after creation. These methods work
together to manage object creation and initialization.

__new__ in Python

Syntax
class ClassName:
def __new__(cls, *args, **kwargs):
# Custom instance creation logic
instance = super(ClassName, cls).__new__(cls, *args, **kwargs)
return instance

Parameters:
 cls : The class itself.
 *args : Positional arguments passed to __new__ .
 **kwargs : Keyword arguments passed to __new__ .
Return Value:
 Must return an instance of the class (cls) or another
class.
 If __new__ returns an object of another type, __init__ will
not be called.

Whenever a class is instantiated, two methods are called:


__new__ : Responsible for creating a new instance of the
class.
 __init__ : Initializes the instance.
Unlike __init__, which is used for setting up an object after it has
been created, __new__ is responsible for creating and returning
the new instance itself.

Example:
class A:
def __new__(cls):
print("Creating instance")
return super(A, cls).__new__(cls)

def __init__(self):
print("Initializing instance")

A()

Output
Creating instance
Initializing instance
Explanation: __new__ method is called first to create an
instance of class A and then returns the newly created instance.
After that, the __init__ method initializes the instance.

Example 1: What happens if __new__ does not return an


instance?
class A:
def __new__(cls):
print("Creating instance")

def __init__(self):
print("Initializing instance")

print(A())

Output
Creating instance
None
Explanation: __new__ method does not return an instance of
the class. Since __new__ must return an instance, but it lacks a
return statement, it implicitly returns None.

Returning a different type from __new__


class A:
def __new__(cls):
print("Creating instance")
return "Hello, World!"

print(A())

Output
Creating instance
Hello, World!
Explanation : __new__ method should return a new object
of class A, but here it returns the string "Hello, World!". Because
of this, Python does not create an instance of A, so the __init__
method is never called. Instead, print(A()) simply prints "Hello,
World!".

Returning an instances of another class


class GeeksforGeeks:
def __str__(self):
return "GeeksforGeeks Instance"

class Geek:
def __new__(cls):
return GeeksforGeeks()

def __init__(self):
print("Inside init")

print(Geek())

Output
GeeksforGeeks Instance
Explanation :__new__ method of Geek returns an instance of
GeeksforGeeks instead of Geek, so the __init__ method is never
called. When print(Geek()) is executed, it prints "GeeksforGeeks
Instance" from the __str__ method of GeeksforGeeks.

__init__ Method
This method initializes the newly created instance and is
commonly used as a constructor in Python. It is called
immediately after the object is created by __new__ method and
is responsible for initializing attributes of the instance.
Syntax:
class ClassName:
def __init__(self, parameters):
[Link] = value

__new__ method:
 Responsible for creating a new instance of the class.
 Rarely overridden but useful for customizing object
creation and especially in singleton or immutable
objects.
__init__ method:
 Called immediately after __new__.
 Used to initialize the created object.

Types of Constructors

1. Default Constructor
A default constructor does not take any parameters other
than self. It initializes the object with default attribute values.
class Car:
def __init__(self):

#Initialize the Car with default attributes


[Link] = "Toyota"
[Link] = "Corolla"

# Creating an instance using the default constructor


car = Car()
print([Link])
print([Link])

Output
Toyota
Corolla

2. Parameterized Constructor
A parameterized constructor accepts arguments to initialize
the object's attributes with specific values.
class Car:
def __init__(self, make, model, year):

#Initialize the Car with specific attributes.


[Link] = make
[Link] = model
[Link] = year

# Creating an instance using the parameterized constructor


car = Car("Honda", "Civic", 2022)
print([Link])
print([Link])
print([Link])

Output
Honda
Civic
2022

Encapsulation in Python
How Encapsulation Works :
 Data Hiding: The variables (attributes) are kept private
or protected, meaning they are not accessible directly
from outside the class. Instead, they can only be
accessed or modified through the methods.
 Access through Methods: Methods act as the interface
through which external code interacts with the data
stored in the variables. For instance, getters and setters
are common methods used to retrieve and update the
value of a private variable.

Public Members
Public members are accessible from anywhere, both inside and
outside the class. These are the default members in Python.

Example:
class Public:
def __init__(self):
[Link] = "John" # Public attribute

def display_name(self):
print([Link]) # Public method

obj = Public()
obj.display_name() # Accessible
print([Link]) # Accessible
Explanation:
 Public Attribute (name): This attribute is declared
without any underscore prefixes. It is accessible from
anywhere, both inside and outside of the class.
 Public Method (display_name): This method is also
accessible from any part of the code. It directly accesses
the public attribute and prints its value.
 Object (obj): An instance of Public is created, and the
display_name method is called, demonstrating how
public attributes and methods can be accessed directly.

Protected members
Protected members are identified with a single underscore (_).
They are meant to be accessed only within the class or its
subclasses.
Example:
class Protected:
def __init__(self):
self._age = 30 # Protected attribute

class Subclass(Protected):
def display_age(self):
print(self._age) # Accessible in subclass

obj = Subclass()
obj.display_age()
Explanation:
 Protected Attribute (_age): This attribute is prefixed
with a single underscore, which by convention, suggests
that it should be treated as a protected member. It's not
enforced by Python but indicates that it should not be
accessed outside of this class and its subclasses.
 Subclass: Here, a subclass inherits from Protected.
Within this subclass, we can still access the
protected attribute _age.
 Method (display_age): This method within the subclass
accesses the protected attribute and prints its value. This
shows that protected members can be accessed within
the class and its subclasses.

Private members
Private members are identified with a double
underscore (__) and cannot be accessed directly from outside
the class. Python uses name mangling to make private members
inaccessible by renaming them internally.
Note: Python's private and protected members can be accessed
outside the class through python name mangling .
class Private:
def __init__(self):
self.__salary = 50000 # Private attribute

def salary(self):
return self.__salary # Access through public method

obj = Private()
print([Link]()) # Works
#print(obj.__salary) # Raises AttributeError
Explanation:
 Private Attribute (__salary): This attribute is prefixed
with two underscores, which makes it a private member.
Python enforces privacy by name mangling, which means
it renames the attribute in a way that makes it hard to
access from outside the class.
 Method (salary): This public method provides the only
way to access the private attribute from outside the
class. It safely returns the value of __salary.
 Direct Access Attempt: Trying to access the private
attribute directly (obj.__salary) will result in an
AttributeError, showing that direct access is blocked. This
is Python's way of enforcing encapsulation at a language
level.

Inheritance in Python
Syntax

class ParentClass:
# Parent class code here
pass
class ChildClass(ParentClass):
# Child class code here
pass

Creating a simple subclass


Animal is the base class with a __init__ method to initialize
the name attribute and a sound method. Dog is a
subclass Animal that inherits from it. It overrides the sound
method to provide a specific implementation for dogs.

class Animal:
def __init__(self, name):

# Storing the name of the animal


[Link] = name

def sound(self):

# This method should be implemented by subclasses


raise NotImplementedError("Subclasses must implement this
method")

class Dog(Animal):
def sound(self):

# Dog-specific sound
return "Woof!"

# Creating instances
# Animal instance with generic name
a = Animal("Generic Animal")

# Dog instance with name 'Buddy'


d = Dog("Buddy")

# Accessing attributes and methods


print([Link]) # Output: Generic Animal
print([Link]) # Output: Buddy
print([Link]()) # Output: Woof!

Output
Generic Animal
Buddy
Woof!

Adding additional attributes in the subclass


Shape is the base class with an __init__ method to initialize
the color attribute and an abstract area method. Circle is a
subclass of Shape that extends it by adding a radius attribute. It
calls the superclass constructor using super() to initialize the
common attribute. The area method is overridden in
the Circle subclass to provide a specific implementation for
calculating the area of a circle.
class Shape:
def __init__(self, color):

# Storing the color of the shape


[Link] = color

def area(self):

# This method should be implemented by subclasses


raise NotImplementedError("Subclasses must implement this
method")

class Circle(Shape):
def __init__(self, color, radius):

# Initialize the parent class (Shape) with color


super().__init__(color)

# Storing the radius of the circle


[Link] = radius

def area(self):

# Circle-specific area calculation


return 3.14 * [Link] ** 2

# Creating instances
# Shape instance with color 'Red'
s = Shape("Red")

# Circle instance with color 'Blue' and radius 5


c = Circle("Blue", 5)

# Accessing attributes and methods


print([Link]) # Output: Red
print([Link]) # Output: Blue
print([Link]) # Output: 5
print([Link]()) # Output: 78.5

Output
Red
Blue
5
78.5

super() Function
super() function is used to call the parent class’s methods. In
particular, it is commonly used in the child class’s __init__()
method to initialize inherited attributes. This way, the child class
can leverage the functionality of the parent class.

Example:
# Parent Class: Person
class Person:
def __init__(self, name, idnumber):
[Link] = name
[Link] = idnumber

def display(self):
print([Link])
print([Link])

# Child Class: Employee


class Employee(Person):
def __init__(self, name, idnumber, salary, post):
super().__init__(name, idnumber) # Using super() to call Person's
__init__()
[Link] = salary
[Link] = post
Explanation:
 The super() function is used inside the __init__() method
of Employee to call the constructor of Person and
initialize the inherited attributes (name and idnumber).
 This ensures that the parent class functionality is reused
without needing to rewrite the code in the child class.
Add Properties
Once inheritance is established, both the parent and child
classes can have their own properties. Properties are attributes
that belong to a class and are used to store data.
Example:
# Parent Class: Person
class Person:
def __init__(self, name, idnumber):
[Link] = name
[Link] = idnumber

def display(self):
print([Link])
print([Link])

# Child Class: Employee


class Employee(Person):
def __init__(self, name, idnumber, salary, post):
super().__init__(name, idnumber)
[Link] = salary
[Link] = post
Explanation:
 Person class has properties name and idnumber.
 Employee class adds properties salary and post.
 The properties are initialized when an object is created,
and they represent the specific data related to the
Person and Employee.

Method Overriding in Python


 The Child class overrides the show() method of the Parent class, so
when show() is called on an instance of Child, it uses the Child class’s
implementation.
# Python program to demonstrate
# Defining parent class
class Parent():

# Constructor
def __init__(self):
[Link] = "Inside Parent"

# Parent's show method


def show(self):
print([Link])

# Defining child class


class Child(Parent):

# Constructor
def __init__(self):
super().__init__() # Call parent constructor
[Link] = "Inside Child"

# Child's show method


def show(self):
print([Link])

# Driver's code
obj1 = Parent()
obj2 = Child()

[Link]() # Should print "Inside Parent"


[Link]() # Should print "Inside Child"

Python magic methods or special functions for operator overloading


Binary Operators:
Operat
or Magic Method

+ __add__(self, other)

- __sub__(self, other)

* __mul__(self, other)

__truediv__(self,
/ other)

__floordiv__(self,
// other)

__mod__(self,
% other)
** __pow__(self, other)

__rshift__(self,
>> other)

__lshift__(self,
<< other)

& __and__(self, other)

| __or__(self, other)

^ __xor__(self, other)

Operator Overloading means giving extended


meaning beyond their predefined operational meaning. For
example operator + is used to add two integers as well as join
two strings and merge two lists. It is achievable because '+'
operator is overloaded by int class and str class.

How to overload the operators in Python?


Consider that we have two objects which are a physical
representation of a class (user-defined data type) and we have
to add two objects with binary '+' operator it throws an error,
because compiler don't know how to add two objects. So we
define a method for an operator and that process is called
operator overloading. We can overload all existing operators but
we can't create a new operator. To perform operator
overloading, Python provides some special function or magic
function that is automatically invoked when it is associated with
that particular operator. For example, when we use + operator,
the magic method __add__ is automatically invoked in which the
operation for + operator is defined.

Overloading binary operator “+”


class A:
def __init__(self, a):
self.a = a

# adding two objects


def __add__(self, o):
return self.a + o.a
ob1 = A(1)
ob2 = A(2)
ob3 = A("Geeks")
ob4 = A("For")

print(ob1 + ob2)
print(ob3 + ob4)

Output
3
GeeksFor
Here, We defined the special function "__add__( )" and when
the objects ob1 and ob2 are coded as "ob1 + ob2", the special
function is automatically called as ob1.__add__(ob2) which
simply means that ob1 calls the __add__( ) function with ob2 as
an Argument and It actually means A .__add__(ob1, ob2).
Hence, when the Binary operator is overloaded, the object before
the operator calls the respective function with object after
operator as parameter.

Python super()
Last Updated : 19 Mar, 2025



In Python, the super() function is used to refer to the parent class
or superclass. It allows you to call methods defined in the
superclass from the subclass, enabling you to extend and
customize the functionality inherited from the parent class.

How does Inheritance work without super() ?


In the given example, there is an issue with the Emp class's
__init__ method. The Emp class is inherited from the Person
class, but in its __init__ method, it is not calling the parent class's
__init__ method to initialize the name and id attributes.
# code
class Person:

# Constructor
def __init__(self, name, id):
[Link] = name
[Link] = id

# To check if this person is an employee


def Display(self):
print([Link], [Link])

class Emp(Person):

def __init__(self, name, id):


self.name_ = name

def Print(self):
print("Emp class called")

Emp_details = Emp("Mayank", 103)

# calling parent class function


Emp_details.name_, Emp_details.name

Output :

AttributeError: 'Emp' object has no attribute 'name'

Fixing the above problem with Super in Python


In the provided code, the Emp class is correctly inheriting from
the Person class, and the Emp class's __init__ method is now
properly calling the parent class's __init__ method using super()
in Python.
# code
# A Python program to demonstrate inheritance

class Person:

# Constructor
def __init__(self, name, id):
[Link] = name
[Link] = id

# To check if this person is an employee


def Display(self):
print([Link], [Link])

class Emp(Person):
def __init__(self, name, id):
self.name_ = name
super().__init__(name, id)

def Print(self):
print("Emp class called")

Emp_details = Emp("Mayank", 103)

# calling parent class function


print(Emp_details.name_, Emp_details.name)
Output :
Mayank Mayank

Super with Multiple Inheritances


class Animal(canFly, canSwim):

def __init__(self, name):


super().__init__(name)

# Driver Code
Carol = Animal("Dog")
Output :
The class Animal inherits from two-parent classes - canFly and
canSwim. So, the subclass instance Carol can access both of the
parent class constructors using super()

MultipleInheritance
When a class is derived from more than one base class it is
called multiple Inheritance. The derived class inherits all the
features of the base case.

The Diamond Problem

It refers to an ambiguity that arises when two classes Class2 and


Class3 inherit from a superclass Class1 and class Class4 inherits
from both Class2 and Class3. If there is a method "m" which is
an overridden method in one of Class2 and Class3 or both then
the ambiguity arises which of the method "m" Class4 should
inherit.

# Python program to demonstrate


# super()

class Class1:
def m(self):
print("In Class1")

class Class2(Class1):
def m(self):
print("In Class2")
super().m()

class Class3(Class1):
def m(self):
print("In Class3")
super().m()

class Class4(Class2, Class3):


def m(self):
print("In Class4")
super().m()

obj = Class4()
obj.m()
Output:
In Class4
In Class2
In Class3
In Class1

Super() is generally used with the __init__ function when the


instances are initialized. The super function comes to a
conclusion, on which method to call with the help of the method
resolution order (MRO).

Method resolution order:

In Python, every class whether built-in or user-defined is derived


from the object class and all the objects are instances of the
class object. Hence, the object class is the base class for all the
other classes.
In the case of multiple inheritance, a given attribute is first
searched in the current class if it's not found then it's searched
in the parent classes. The parent classes are searched in a left-
right fashion and each class is searched once.
If we see the above example then the order of search for the
attributes will be Derived, Base1, Base2, object. The order that is
followed is known as a linearization of the class Derived and this
order is found out using a set of rules called Method
Resolution Order (MRO).
To view the MRO of a class:

 Use the mro() method, it returns a list


Eg. [Link]()
 Use the _mro_ attribute, it returns a tuple
Eg. Class4.__mro__

Example:
# Python program to demonstrate
# super()

class Class1:
def m(self):
print("In Class1")

class Class2(Class1):
def m(self):
print("In Class2")
super().m()

class Class3(Class1):
def m(self):
print("In Class3")
super().m()

class Class4(Class2, Class3):


def m(self):
print("In Class4")
super().m()

print([Link]()) #This will print list


print(Class4.__mro__) #This will print tuple
Output:
[<class '__main__.Class4'>, <class '__main__.Class2'>, <class
'__main__.Class3'>, <class '__main__.Class1'>, <class 'object'>]
(<class '__main__.Class4'>, <class '__main__.Class2'>, <class
'__main__.Class3'>, <class '__main__.Class1'>, <class 'object'>)

Polymorphism in OOPs
In OOP, polymorphism allows methods in different classes to
share the same name but perform distinct tasks.
Example:

class Shape:
def area(self):
return "Undefined"

class Rectangle(Shape):
def __init__(self, length, width):
[Link] = length
[Link] = width

def area(self):
return [Link] * [Link]

class Circle(Shape):
def __init__(self, radius):
[Link] = radius

def area(self):
return 3.14 * [Link] ** 2

shapes = [Rectangle(2, 3), Circle(5)]


for shape in shapes:
print(f"Area: {[Link]()}")

A list of shape objects (Rectangle and Circle) is created. A for


loop iterates through the list, calling the area method on each
object. The method executed is determined by the object's type,
showcasing polymorphism.

Compile-time Polymorphism
 behavior of a function or operator is resolved during the
program's compilation phase.
 Examples include method overloading and operator
overloading, where multiple functions or operators can
share the same name but perform different tasks based
on the context.

Runtime Polymorphism
 Occurs when the behavior of a method is determined at
runtime based on the type of the object.
 In Python, this is achieved through method overriding: a
child class can redefine a method from its parent class to
provide its own specific implementation.

Method Overloading in Python


Define multiple methods with the same name but different
parameter lists.

def add(datatype, *args):


if datatype == 'int':
res = 0
elif datatype == 'str':
res = ''

for item in args:


res += item

print(res)

add('int', 5, 6)
add('str', 'Hi ', 'Geeks')

Data Abstraction in Python


Abstraction classes
Abstract class is a class in which one or more abstract methods
are defined.

Abstract Method: When a method is declared inside the class


without its implementation is known as abstract method. To
create abstract method and abstract classes we have to import
the "ABC" and "abstractmethod" classes from abc (Abstract
Base Class) library. Abstract method of base class force its child
class to write the implementation of the all abstract methods
defined in base class. If we do not implement the abstract
methods of base class in the child class then our code will give
error

Concrete Method: Concrete methods are the methods defined


in an abstract base class with their complete implementation.

Steps to Create Abstract Base Class and Abstract Method:


1. Firstly, we import ABC and abstractmethod class from
abc (Abstract Base Class) library.
2. Create a BaseClass that inherits from the ABC class. In
Python, when a class inherits from ABC, it indicates that
the class is intended to be an abstract base class.
3. Inside BaseClass we declare an abstract method named
"method_1" by using "abstractmethod" decorater. Any
subclass derived from BaseClass must implement
this method_1 method

from abc import ABC, abstractmethod


class BaseClass(ABC):
@abstractmethod
def method_1(self):
#empty body
pass

from abc import ABC, abstractmethod


# Define an abstract class
class Animal(ABC):
@abstractmethod
def sound(self):
pass # This is an abstract method, no implementation
here.

# Concrete subclass of Animal


class Dog(Animal):
def sound(self):
return "Bark" # implementation of the abstract method

# Create an instance of Dog


dog = Dog()
print([Link]()) # Output: Bark
 Abstract Base Class: Animal is an abstract class that
inherits from ABC (Abstract Base Class). This class
cannot be instantiated directly because it contains an
abstract method sound(). The @abstractmethod
decorator is used to mark sound() as an abstract method.
This means any subclass must implement this method to
be instantiated.
 Concrete Subclass: Dog is a subclass of Animal that
provides an implementation for the sound() method. This
allows the Dog class to be instantiated and used.
 Instantiation: We create an instance of Dog and call
the sound() method, which returns "Bark".

Abstract Methods
Abstract methods are methods that are defined in an abstract
class but do not have an implementation. They serve as a
blueprint for the subclasses, ensuring that they provide their own
implementation.
Example:
from abc import ABC, abstractmethod

class Animal(ABC):
@abstractmethod
def make_sound(self):
pass # Abstract method, no implementation here

Abstract Properties
Abstract properties work like abstract methods but are used
for properties. These properties are declared with
the @property decorator and marked as abstract
using @abstractmethod. Subclasses must implement these
properties.
Example:
from abc import ABC, abstractmethod

class Animal(ABC):
@property
@abstractmethod
def species(self):
pass # Abstract property, must be implemented by subclasses

class Dog(Animal):
@property
def species(self):
return "Canine"
# Instantiate the concrete subclass
dog = Dog()
print([Link])
Explanation:
 species is an abstract property in the Animal class and it
is marked as @abstractmethod.
 The Dog class implements the species property, making
it a concrete subclass that can be instantiated.
 Abstract properties enforce that a subclass provides the
property’s implementation.

Abstract Class Instantiation


Abstract classes cannot be instantiated directly. This is because
they contain one or more abstract methods or properties that
lack implementations. Attempting to instantiate an abstract class
results in a TypeError.

Python-interface module

Interface is a collection of method signatures that should be


provided by the implementing class. The
package [Link] provides an implementation of "object
interfaces" for Python. It is maintained by the Zope Toolkit
project.

Declaring interface
In python, interface is defined using python class statements and
is a subclass of [Link] which is the parent
interface for all interfaces.

Syntax :
class IMyInterface([Link]):
# methods and attributes

Example
import [Link]

class MyInterface([Link]):
x = [Link]("foo")
def method1(self, x):
pass
def method2(self):
pass

# get attribute
x = MyInterface['x']
print(x)

Implementing interface

interfaces are implemented using implementer decorator on


class. If a class implements an interface, then the instances of
the class provide the interface. Objects can provide interfaces
directly, in addition to what their classes implement.

Syntax :
@[Link](*interfaces)
class Class_name:
# methods

Example
import [Link]

class MyInterface([Link]):
x = [Link]("foo")
def method1(self, x):
pass
def method2(self):
pass

@[Link](MyInterface)
class MyClass:
def method1(self, x):
return x**2
def method2(self):
return "foo"
We declared that MyClass implements MyInterface. This means
that instances of MyClass provide MyInterface.
Methods
 implementedBy(class) - returns a boolean value, True
if class implements the interface else False
 providedBy(object) - returns a boolean value, True if
object provides the interface else False
 providedBy(class) - returns False as class does not
provide interface but implements it
 list([Link](class)) - returns
the list of interfaces implemented by a class
 list([Link](object)) - returns the
list of interfaces provided by an object.
 list([Link](class)) - returns
empty list as class does not provide interface but
implements it.

import [Link]

class MyInterface([Link]):
x = [Link]('foo')
def method1(self, x, y, z):
pass
def method2(self):
pass

@[Link](MyInterface)
class MyClass:
def method1(self, x):
return x**2
def method2(self):
return "foo"
obj = MyClass()

# ask an interface whether it


# is implemented by a class:
print([Link](MyClass))

# MyClass does not provide


# MyInterface but implements it:
print([Link](MyClass))

# ask whether an interface


# is provided by an object:
print([Link](obj))

# ask what interfaces are


# implemented by a class:
print(list([Link](MyClass)))
# ask what interfaces are
# provided by an object:
print(list([Link](obj)))

# class does not provide interface


print(list([Link](MyClass)))
Output :
True
False
True
[<InterfaceClass __main__.MyInterface>]
[<InterfaceClass __main__.MyInterface>]
[]

Interface Inheritance
Interfaces can extend other interfaces by listing the other
interfaces as base interfaces.

Functions

 extends(interface) - returns boolean value, whether


one interface extends another.
 isOrExtends(interface) - returns boolean value,
whether interfaces are same or one extends another.
 isEqualOrExtendedBy(interface) - returns boolean
value, whether interfaces are same or one is extended by
another.

import [Link]

class BaseI([Link]):
def m1(self, x):
pass
def m2(self):
pass

class DerivedI(BaseI):
def m3(self, x, y):
pass

@[Link](DerivedI)
class cls:
def m1(self, z):
return z**3
def m2(self):
return 'foo'
def m3(self, x, y):
return x ^ y

# Get base interfaces


print(DerivedI.__bases__)

# Ask whether baseI extends


# DerivedI
print([Link](DerivedI))

# Ask whether baseI is equal to


# or is extended by DerivedI
print([Link](DerivedI))

# Ask whether baseI is equal to


# or extends DerivedI
print([Link](DerivedI))

# Ask whether DerivedI is equal


# to or extends BaseI
print([Link](DerivedI))
Output :
(<InterfaceClass __main__.BaseI>, )
False
True
False
True

Dunder or magic methods in Python

Python Magic methods are the methods starting and ending


with double underscores '__'. They are defined by built-in classes
in Python and commonly used for operator overloading.
They are also called Dunder methods, Dunder here means
"Double Under (Underscores)".

Python Magic Methods


Examples-
Initialization and Construction
 __new__: To get called in an object's instantiation.
 __init__: To get called by the __new__ method.
 __del__: It is the destructor.
Numeric magic methods
 __trunc__(self): Implements behavior for [Link]()
 __ceil__(self): Implements behavior for [Link]()
 __floor__(self): Implements behavior for [Link]()
Arithmetic operators
 __add__(self, other): Implements behavior for the +
operator (addition).
 __sub__(self, other): Implements behavior for the -
operator (subtraction).

classmethod() in Python

The classmethod() is an inbuilt function in Python, which returns a
class method for a given function. This means that classmethod()
is a built-in Python function that transforms a regular method into
a class method. When a method is defined using the
@classmethod decorator (which internally calls classmethod()),
the method is bound to the class and not to an instance of the
class. As a result, the method receives the class (cls) as its first
argument, rather than an instance (self).

classmethod() Syntax
class MyClass:
@classmethod
def class_method(cls, *args, **kwargs):
# Method implementation
Pass

classmethod() Function
In Python, the classmethod() function is used to define a
method that is bound to the class and not the instance of
the class. This means that it can be called on the class itself
rather than on instances of the class.
Class Method vs Static Method
 A class method takes class(cls) as the first parameter
while a static method needs no specific parameters.
 A class method can access or modify the class state
while a static method can’t access or modify it.
 In general, static methods know nothing about the class
state. They are utility-type methods that take some
parameters and work upon those parameters. On the
other hand class methods must have class as a
parameter.
 We use @classmethod decorator in Python to create a
class method and we use @staticmethod decorator to
create a static method in Python.

class Geeks:
course = 'DSA'
list_of_instances = []

def __init__(self, name):


[Link] = name
Geeks.list_of_instances.append(self)

@classmethod
def get_course(cls):
return f"Course: {[Link]}"

@classmethod
def get_instance_count(cls):
return f"Number of instances: {len(cls.list_of_instances)}"

@staticmethod
def welcome_message():
return "Welcome to Geeks for Geeks!"
# Creating instances
g1 = Geeks('Alice')
g2 = Geeks('Bob')

# Calling class methods


print(Geeks.get_course())
print(Geeks.get_instance_count())

# Calling static method


print(Geeks.welcome_message())

Output
Course: DSA
Number of instances: 2
Welcome to Geeks for Geeks!

we created a class named "Geeks" with a member variable


"course" and created a function named "purchase" which prints
the object. Now, we passed the method [Link] into a
class method using the @classmethod decorator, which converts
the method to a class method. With the class method in place,
we can call the function "purchase" without creating a function
object, directly using the class name "Geeks."

Create class method using classmethod()

class Student:

# create a variable
name = "Geeksforgeeks"

# create a function
def print_name(obj):
print("The name is : ", [Link])

Student.print_name = classmethod(Student.print_name)

# now this method can be called as classmethod


# print_name() method is called a class method
Student.print_name()
Output
The name is : Geeksforgeeks


o Instance Method: Takes self as the first
parameter. It is used to access or modify
instance attributes and can call other
instance methods.
o Example:
class MyClass:
def instance_method(self):
return "This is an instance
method"
 Class Method:
o Class Method: Takes cls as the first
parameter. It is used to access or modify
class state that applies across all instances.
o Decorated with: @classmethod
o Example:
class MyClass:
@classmethod
def class_method(cls):
return "This is a class method"

What is the @classmethod decorator in Python?


The @classmethod decorator defines a method that is bound to the
class and not the instance. It allows you to call the method on
the class itself or on instances of the class. The first parameter
of a class method is cls, which refers to the class and not the
instance.
Example:
class MyClass:
@classmethod
def class_method(cls):
return f"This is a class method of {cls.__name__}"
print(MyClass.class_method()) # Output: This is a class
method of MyClass

What is the difference between self and classmethod?


 self:
o Refers to the instance of the class.
o Used in instance methods to access or
modify instance attributes and methods.
o Example:
class MyClass:
def instance_method(self):
return "This method uses self"
 @classmethod:
o Refers to the class itself through
the cls parameter.
o Used to access or modify class-level
attributes and methods.
o Defined using the @classmethod decorator.
o Example:
class MyClass:
@classmethod
def class_method(cls):
return "This method uses cls"
Destructors in Python
Destructors are called when an object gets destroyed.
The __del__() method is a known as a destructor method in
Python. It is called when all references to the object have been
deleted i.e when an object is garbage collected.
Syntax of destructor declaration :

def __del__(self):
# body of destructor

Note : A reference to objects is also deleted when the object


goes out of reference or when the program ends.

Example 1 : Here is the simple example of destructor. By using


del keyword we deleted the all references of object 'obj',
therefore destructor invoked automatically.
class Employee:

# Initializing
def __init__(self):
print('Employee created.')

# Deleting (Calling destructor)


def __del__(self):
print('Destructor called, Employee deleted.')

obj = Employee()
del obj

Output
Employee created.
Destructor called, Employee deleted.
Note : The destructor was called after the program ended or
when all the references to object are deleted i.e when the
reference count becomes zero, not when object went out of
scope.

Example 2: Notice that the destructor is called after the


'Program End...' printed.

class Employee:

# Initializing
def __init__(self):
print('Employee created')

# Calling destructor
def __del__(self):
print("Destructor called")

def Create_obj():
print('Making Object...')
obj = Employee()
print('function end...')
return obj

print('Calling Create_obj() function...')


obj = Create_obj()
print('Program End...')

Output
Calling Create_obj() function...
Making Object...
Employee created
function end...
Program End...
Destructor called

Opening a File in Python


file = open("filename", "mode")

# Opening a file in read mode


file = open("[Link]", "r")

# Opening a file in write mode


file = open("[Link]", "w")

# Opening a file in append mode


file = open("[Link]", "a")

# Opening a file in binary read mode


file = open("[Link]", "rb")

Reading a File in Python


Reading a file in Python involves opening the file in a mode that allows for
reading, and then using various methods to extract the data from the file.
Python provides several methods to read data from a file −

 read() − Reads the entire file.


 readline() − Reads one line at a time.
 readlines − Reads all lines into a list.
To read a file, you need to open it in read mode. The default mode for the
open() function is read mode ('r'), but it's good practice to specify it explicitly.

Example: Using read() method


In the following example, we are using the read() method to read the whole
file into a single string −

with open("[Link]", "r") as file:


content = [Link]()
print(content)

Following is the output obtained −

Hello!!!
Welcome to TutorialsPoint!!!

file_object.read(size)

Where, size is the number of bytes to read from the file. This
parameter is optional. If omitted or set to a negative value, the method reads
until the end of the file.

Reading Specific Parts of a File


Sometimes, we may only need to read a specific part of a file,
such as the first few bytes, a specific line, or a range of lines.

Example: Reading the First N Bytes

# Open the file in read mode


file = open("[Link]", "r")

# Read the first 10 bytes


content = [Link](10)

print(content)

# Close the file


[Link]()
Output:
Hello World
Explanation: This code reads only the first 10 characters of the
file, useful for previewing file contents.
Example: Using readline() method
In here, we are using the readline() method to read one line at a time,
making it memory efficient for reading large files line by line −

with open("[Link]", "r") as file:


line = [Link]()
while line:
print(line, end='')
line = [Link]()

Output of the above code is as shown below −

Hello!!!
Welcome to TutorialsPoint!!!

Example: Using readlines() method


Now, we are using the readlines() method to read the entire file and splits it
into a list where each element is a line −

with open("[Link]", "r") as file:


lines = [Link]()
for line in lines:
print(line, end='')

We get the output as follows −

Hello!!!
Welcome to TutorialsPoint!!!

Writing to a File in Python


Writing to a file in Python involves opening the file in a mode that allows
writing, and then using various methods to add content to the file.

To write data to a file, use the write() or writelines() methods. When opening
a file in write mode ('w'), the file's existing content is erased.

Example: Using the write() method


In this example, we are using the write() method to write the string passed to
it to the file. If the file is opened in 'w' mode, it will overwrite any existing
content. If the file is opened in 'a' mode, it will append the string to the end of
the file −
Open Compiler
with open("[Link]", "w") as file:
[Link]("Hello, World!")
print ("Content added Successfully!!")

Output of the above code is as follows −

Content added Successfully!!

Example: Using the writelines() method


In here, we are using the writelines() method to take a list of strings and
writes each string to the file. It is useful for writing multiple lines at once −

lines = ["First line\n", "Second line\n", "Third line\n"]


with open("[Link]", "w") as file:
[Link](lines)
print ("Content added Successfully!!")

The result obtained is as follows −

Content added Successfully!!

Closing a File in Python


We can close a file in Python using the close() method. Closing a file is an
essential step in file handling to ensure that all resources used by the file are
properly released. It is important to close files after operations are completed
to prevent data loss and free up system resources.

Example
In this example, we open the file for writing, write data to the file, and then
close the file using the close() method −

file = open("[Link]", "w")


[Link]("This is an example.")
[Link]()
print ("File closed successfully!!")

The output produced is as shown below −

File closed successfully!!


Using "with" Statement for Automatic File
Closing
The with statement is a best practice in Python for file operations because it
ensures that the file is automatically closed when the block of code is exited,
even if an exception occurs.

Example
In this example, the file is automatically closed at the end of the with block,
so there is no need to call close() method explicitly −

Open Compiler
with open("[Link]", "w") as file:
[Link]("This is an example using the with statement.")
print ("File closed successfully!!")

Following is the output of the above code −

File closed successfully!!

Handling Exceptions When Closing a File


When performing file operations, it is important to handle potential
exceptions to ensure your program can manage errors gracefully.

In Python, we use a try-finally block to handle exceptions when closing a


file. The "finally" block ensures that the file is closed regardless of whether an
error occurs in the try block −

try:
file = open("[Link]", "w")
[Link]("This is an example with exception handling.")
finally:
[Link]()
print ("File closed successfully!!")
File closed successfully!!

Problems with working in text(r/w) mode-


 can't work with binary files like images,videos
 not good for other data types like int/float/list/tuples
# working with binary file in text(r/w)
mode

with open('[Link]','r') as f:
[Link]()

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0:


invalid start byte

# working with other data types


with open('[Link]','w') as f:
[Link](5)
TypeError: write() argument must be str, not int
text(r/w) mode- support only string data type
read/write(writing lists/integer/dict/tuple/float not
supported – go for binary mode )

Reading/ Writing to a New File in Binary Mode


By default, read/write operations on a file object are performed on
text string data. If we need to handle files of different types, such as
media files (mp3), executables (exe), or pictures (jpg), we must open
the file in binary mode by adding the 'b' prefix to the read/write
mode.

Reading Binary Data from a File


To read a binary file, we need to open it in 'rb' mode. The returned value of
the read() method is then decoded before printing −

# Open the file in binary read mode


with open('[Link]', 'rb') as f:
data = [Link]()
print([Link](encoding='utf-8'))

Writing Binary Data to a File


To write binary data to a file, open the file in binary write mode ('wb'). The
following example demonstrates this −

with open('[Link]', 'wb') as f:


# Binary data
data = b"Hello World"
[Link](data)

Converting Text Strings to Bytes


Conversion of a text string to bytes can be done using the encode() function.
This is useful when you need to write text data as binary data −

with open('[Link]', 'wb') as f:


# Convert text string to bytes
data = "Hello World".encode('utf-8')
[Link](data)

Writing an Integer to a Binary File


Following is an example on how to write an integer to a binary file −

# Convert the integer to bytes and write to a binary file


n = 25
data = n.to_bytes(8, 'big')

with open('[Link]', 'wb') as f:


[Link](data)

Reading an Integer from a Binary File


To read back the integer data from the binary file, convert the output of the
read() function back to an integer using the from_bytes() method −

# Read the binary data from the file and convert it back to an integer
with open('[Link]', 'rb') as f:
data = [Link]()
n = int.from_bytes(data, 'big')
print(n)

Writing a Float to a Binary File


To write floating-point data to a binary file, we use the [Link]() method
to convert the float into a bytes object −
import struct

# Define a floating-point number


x = 23.50

# Pack the float into a binary format


data = [Link]('f', x)

# Open the file in binary write mode and write the packed data
with open('[Link]', 'wb') as f:
[Link](data)

Reading Float Numbers from a Binary File


To read floating-point data from a binary file, we use the [Link]()
method to convert the bytes object back into a float −

import struct

# Open the file in binary read mode


with open('[Link]', 'rb') as f:
# Read the binary data from the file
data = [Link]()

# Unpack the binary data to retrieve the float


x = [Link]('f', data)[0]

# Print the float value


print(x)

Q. Copying data from binary file to another


with open('[Link]','rb') as f:

with open('screenshot_copy.png','wb') as wf:


[Link]([Link]())

Q. Moving within a file -> 10 char then 10 char


with open('[Link]','r') as f:
print([Link](10))
print([Link](10))
print([Link](10))
print([Link](10))

Q. Reading big file in chunks

with open('[Link]','r') as f:

chunk_size = 10

while len([Link](chunk_size)) > 0:


print([Link](chunk_size),end='***')
[Link](chunk_size)

seek()
The seek() function in Python is used to move the file cursor to the
specified location. When we read a file, the cursor starts at the
beginning, but we can move it to a specific position by passing an arbitrary
integer (based on the length of the content in the file) to the seek() function.

with open('[Link]', 'r') as file:


# Setting the cursor at 62nd position
[Link](62)
# Reading the content after the 62nd character
data = [Link]()
print(data)

We’ve moved the cursor to the 62nd position, which means that if we read
the file, we’ll begin reading after the 62nd character.

Syntax
seek(offset, whence)
Here,

offset– Required parameter. Sets the cursor to the specified


position and starts reading after that position.
whence – Optional parameter. It is used to set the point of
reference to start from which place.
0 – Default. Sets the point of reference at the beginning of the
file. Equivalent to os.SEEK_SET.
1 – Sets the point of reference at the current position of the file.
Equivalent to os.SEEK_CUR.
2 – Sets the point of reference at the end of the file. Equivalent
to os.SEEK_END.

Note: In text mode, WHENCE can only be 0. Using 1 or 2


requires binary mode ('rb').

The seek() function is used to move the read/write pointer to


any desired byte position within the file.

Using the seek() Method


The seek() method is used to set the position of the read/write pointer within
the file. The syntax for the seek() method is as follows −

[Link](offset[, whence])

Where,

 offset − This is the position of the read/write pointer within the file.
 whence − This is optional and defaults to 0 which means absolute file
positioning, other values are 1 which means seek relative to the
current position and 2 means seek relative to the file's end.
Example
The following program demonstrates how to open a file in read-write mode
('w+'), write some data, seek a specific position, and then overwrite part of
the file's content −

# Open a file in read-write mode


fo = open("[Link]", "w+")

# Write initial data to the file


[Link]("This is a rat race")

# Move the read/write pointer to the 10th byte


[Link](10, 0)

# Read 3 bytes from the current position


data = [Link](3)

# Move the read/write pointer back to the 10th byte


[Link](10, 0)

# Overwrite the existing content with new text


[Link]('cat')

# Close the file


[Link]()

If we open the file in read mode (or seek to the starting position while in 'w+'
mode) and read the contents, it will show the following −

Reading a File from Specific Offset


We can set the he file's current position at the specified offset using
the seek() method.

 If the file is opened for appending using either 'a' or 'a+', any
seek() operations will be undone at the next write.
 If the file is opened only for writing in append mode using 'a', this
method is essentially a no-op, but it remains useful for files
opened in append mode with reading enabled (mode 'a+').
 If the file is opened in text mode using 't', only offsets returned
by tell() are legal. Use of other offsets causes undefined
behavior.
Note that not all file objects are seekable.

Example
The following example demonstrates how to use the seek() method to
perform simultaneous read/write operations on a file. The file is opened in w+
mode (read-write mode), some data is added, and then the file is read and
modified at a specific position −

Open Compiler
# Open a file in read-write mode
fo = open("[Link]", "w+")

# Write initial data to the file


[Link]("This is a rat race")

# Seek to a specific position in the file


[Link](10, 0)

# Read a few bytes from the current position


data = [Link](3)
print("Data read from position 10:", data)

# Seek back to the same position


[Link](10, 0)

# Overwrite the earlier contents with new text


[Link]("cat")

# Rewind to the beginning of the file


[Link](0, 0)

# Read the entire file content


data = [Link]()
print("Updated file content:", data)

# Close the file


[Link]()
tell()
tell() method returns the current file position in a file stream.

Syntax
[Link]()

Using seek() in Text Mode


Let's say [Link] contains:
Code is like humor. When you have to explain it, it’s bad.
f = open("[Link]", "r")

[Link](20)
print([Link]())
print([Link]())

[Link]()
Output:
20
When you have to explain it, it’s bad.
Explanation:
 seek(20) moves the cursor to character 20.
 tell() confirms the cursor is at position 20.
 readline() reads from that position onward.

Using seek() in Binary Mode


Suppose [Link] contains the following binary content:
b'Code is like humor. When you have to explain it, its bad.'
f = open("[Link]", "rb")

[Link](-10, 2)
print([Link]())
print([Link]().decode('utf-8'))

[Link]()
Output:
47
, its bad.
Explanation:
 File is opened in binary mode ('rb').
 seek(-10, 2) moves 10 bytes before the end of the file.
 readline() reads from that point to the end.
 Output is decoded from binary to string.

Working With JSON Data in Python


JSON is a lightweight data format for data interchange that can
be easily read and written by humans, and easily parsed and
generated by machines. It is a complete language-independent
text format. To work with JSON data, Python has a built-in
package called JSON.

Example of JSON String

s = '{"id":01, "name": "Emily", "language": ["C++",


"Python"]}'

The syntax of JSON is considered a subset of the syntax


of JavaScript including the following:
 Name/Value pairs: Represents Data, the name is
followed by a colon(:), and the Name/Value pairs are
separated by a comma(,).
 Curly braces: Holds objects.
 Square brackets: Hold arrays with values separated by
a comma (,).
Keys/Name must be strings with double quotes and values must
be data types amongst the following:
 String
 Number
 Object (JSON object)
 array
 Boolean
 Null

Example of JSON file:


{
"employee": [
{
"id": "01",
"name": "Amit",
"department": "Sales"
},
{
"id": "04",
"name": "sunil",
"department": "HR"
}
]
}

Serializing/ Encoding JSON:


Writing data to files

The process of encoding JSON is usually called serialization. This term refers to
the transformation of data into a series of bytes (hence serial) to be stored or
transmitted across a network. To handle the data flow in a file, the JSON library in
Python uses dump() function to convert the Python objects into their respective
JSON object, so it makes it easy to write data to files. See the following table given
below.

Convert Python Dict to JSON


In the below code, we are converting a Python dictionary to a
JSON object using [Link]() method of JSON module in
Python. We first import the JSON module and then make a small
dictionary with some key-value pairs and then passed it into
[Link]() method with 'indent=4' to convert this Python
dictionary into a JSON object. As we have given the value of
indent to 4 there are four whitespaces before each data as seen
in the output.

import json

# Data to be written
dictionary = {
"id": "04",
"name": "sunil",
"department": "HR"
}

# Serializing json
json_object = [Link](dictionary, indent = 4)
print(json_object)

Output
{
"id": "04",
"name": "sunil",
"department": "HR"
}

The following types of Python objects can be converted into JSON


strings:
 dict
 list
 tuple
 string
 int
 float
 True
 False
 None

Python objects and their equivalent conversion to JSON:

JSON
Python Equivalent

dict object

list,
array
tuple

str string

int, float number

True true

False false

None null
Method 1: Writing JSON to a file in Python using [Link]()
The JSON package in Python has a function called [Link]() that helps in
converting a dictionary to a JSON object. It takes two parameters:
 dictionary: the name of a dictionary which should be converted to a
JSON object.
 indent: defines the number of units for indentation
After converting the dictionary to a JSON object, simply write it to a file using the
"write" function.

import json

dictionary = {
"name": "sathiyajith",
"rollno": 56,
"cgpa": 8.6,
"phonenumber": "9976770500"
}

# Serializing json
json_object = [Link](dictionary, indent=4)

# Writing to [Link]
with open("[Link]", "w") as outfile:
[Link](json_object)

Output:
Method 2: Writing JSON to a file in Python using [Link]()
Another way of writing JSON to a file is by using [Link]() method The JSON
package has the "dump" function which directly writes the dictionary to a file in
the form of JSON, without needing to convert it into an actual JSON object. It
takes 2 parameters:
 dictionary - the name of a dictionary which should be converted to a
JSON object.
 file pointer - pointer of the file opened in write or append mode.

import json

# Data to be written
dictionary = {
"name": "sathiyajith",
"rollno": 56,
"cgpa": 8.6
}

with open("[Link]", "w") as outfile:


[Link](dictionary, outfile)

Output:

Deserializing/Decoding JSON:
Reading data from files

Deserialization is the opposite of Serialization, i.e. conversion of JSON objects


into their respective Python objects. The load() method is used for it. If you have
used JSON data from another program or obtained it as a string format of JSON,
then it can easily be deserialized with load(), which is usually used to load from a
string, otherwise, the root object is in a list or dict.
with open("[Link]", "r") as read_it:
data = [Link](read_it)
Example: Deserialization
json_var ="""
{
"Country": {
"name": "INDIA",
"Languages_spoken": [
{
"names": ["Hindi", "English", "Bengali", "Telugu"]
}
]
}
}
"""
var = [Link](json_var)

Python read JSON file


Let's suppose we have a JSON file that looks like this.

Here, we have used the open() function to read the JSON file.
Then, the file is parsed using [Link]() method which gives us a
dictionary named data.
import json

# Opening JSON file


f = open('[Link]',)

# returns JSON object as


# a dictionary
data = [Link](f)
# Iterating through the json
# list
for i in data['emp_details']:
print(i)

# Closing file
[Link]()

Output:

Updating a JSON file


The write_json() function reads the existing data, updates it,
and then writes the updated data back to the file. Suppose the
JSON file looks like this.

We want to add another JSON data after emp_details. Below is


the implementation.

import json

# Function to append new data to JSON file


def write_json(new_data, filename='[Link]'):
with open(filename, 'r+') as file:
# Load existing data into a dictionary
file_data = [Link](file)

# Append new data to the 'emp_details' list


file_data["emp_details"].append(new_data)
# Move the cursor to the beginning of the file
[Link](0)

# Write the updated data back to the file


[Link](file_data, file, indent=4)

# New data to append


new_employee = {
"emp_name": "Nikhil",
"email": "nikhil@[Link]",
"job_profile": "Full Time"
}

# Call the function to append data


write_json(new_employee)

Output:

 [Link](d, indent=4) converts the dictionary to a


JSON-formatted string with 4-space indentation for
readability.
 [Link](d, sort_keys=True) converts the
dictionary to a JSON string with keys sorted
alphabetically.
 [Link](d, ensure_ascii=False) converts the
dictionary to a JSON string while preserving non-ASCII
characters. If set to True (default), non-ASCII characters
are escaped.
 [Link](d, outfile) writes the dictionary d to a file
sample_default.json in JSON format without formatting.
 [Link](d, outfile, indent=4) writes the
dictionary d to sample_pretty.json with 4-space
indentation.
 [Link](d, outfile, sort_keys=True) writes d to
sample_sorted.json with keys sorted alphabetically.
 [Link](d, outfile,
ensure_ascii=False) writes d to sample_ascii.json,
preserving non-ASCII characters.

Difference Between Dictionary and JSON


S.N
o. JSON Dictionary

JSON (JavaScript Object


Notation) is a data A dictionary in Python is a built-in data
interchange format used to structure used to store a collection of
store and exchange data key-value pairs.
1. between systems.

JSON keys must be strings Dictionary keys can be of various data


and enclosed in double types, including strings, numbers, and
2. quotes. tuples (immutable types).

JSON has a strict syntax with


key-value pairs separated by
Python dictionaries use curly braces {}
colons (:), and pairs
to enclose key-value pairs, with
separated by commas (,).
colons : separating keys and values.
Curly braces {} enclose JSON
3. objects.

In Python dictionaries, keys can be


JSON keys and string values
specified without quotes (e.g., key:
must be enclosed in double
"value"), although quotes are also
quotes (e.g., "key": "value").
4. allowed.

Eg. {"name": "Ram", "age":


Eg. {"name": "Shyam", "age": 30}
5. 30}

JSON values are accessed Dictionary values are accessed using


using keys as strings (e.g., keys (e.g., data["name"]) or using the
6. data["name"]). get() method.

7. JSON data can be saved to Python dictionaries can also be


S.N
o. JSON Dictionary

serialized to files using various


and loaded from files using
methods, but you need to handle the
functions like [Link]()
serialization/deserialization logic
and [Link]().
yourself.

Convert Python dictionary to JSON string :


using [Link](dict)

# create a sample dictionary


a = {"name" : "GeeksforGeeks", "Topic" : "Json to String", "Method": 1}
y = [Link](a)

[Link](a) converts the dictionary a into a JSON-formatted


string which we store in a variable which we can write to a file

Convert String to Python dictionary –


using [Link](json string)
# create a sample json string
s = '{"name": "John", "age": 30, "city": "New York"}'
res= [Link](s)

For example, a JSON string like {"name": "John", "age": 30,


"city": "New York"} can be converted into a Python dictionary,
{'name': 'John', 'age': 30, 'city': 'New York'} which we store in a
variable which we can write to a file

Note:
 It is worth mentioning here that the JSON object which is
created during serialization is just a Python string, that's
why you'll find the terms "JSON object" and "JSON string"
used interchangeably in this article
 Also it is important to note that a JSON object
corresponds to a Dictionary in Python. So when you use
loads method, a Python dictionary is returned by
default (unless you change this behaviour as discussed
in the custom decoding section of this article)
Encoding and Decoding Custom
Objects
 Serializing/Encoding Python Objects into
JSON

Suppose we’ve to write an object of Person class in


particular format like:

# format to printed in:


String format: -> Nitish Singh age -> 33 gender -> male
OR
Dict format: {'name': 'Nitish Singh', 'age': 33, 'gender': 'male'}

class Person:
def __init__(self,fname,lname,age,gender):
[Link] = name
[Link] = age
[Link] = gender

#create an object of the Person class


person = Person('Nitish','Singh',33,'male')

# As a string
def show_object(person):
if isinstance(person,Person):
return "{} age -> {} gender ->
{}".format([Link] ,[Link], [Link])

with open('[Link]','w') as f:
[Link](person, f, default=show_object)

# As a dictionary
def show_object(person):
if isinstance(person,Person):
return {'name':[Link] + ' ' +
[Link],'age':[Link],'gender':[Link]}
with open('[Link]','w') as f:
[Link](person, f, default=show_object, indent=4)

 Another way of doing that is to define a method in our


class that will provide the JSON version of our class'
instance.
Suppose we have a user-defined class Student and we want to
make it JSON serializable.

Example:
import json

class Student:
def __init__(self, name, roll_no, address):
[Link] = name
self.roll_no = roll_no
[Link] = address
def to_json(self):
'''
convert the instance of this class to json
'''
return [Link](self, indent = 4, default=lambda o:
o.__dict__)

class Address:
def __init__(self, city, street, pin):
[Link] = city
[Link] = street
[Link] = pin

address = Address("Bulandshahr", "Adarsh Nagar", "203001")


student = Student("Raju", 53, address)

# Encoding
student_json = student.to_json()
print(student_json)
print(type(student_json))

# Decoding
student = [Link](student_json)
print(student)
print(type(student))

Output:
{ "name": "Raju", "roll_no": 53, "address": { "city": "Bulandshahr",
"street": "Adarsh Nagar", "pin": "203001" } } <class 'str'> {'name':
'Raju', 'roll_no': 53, 'address': {'city': 'Bulandshahr', 'street': 'Adarsh
Nagar', 'pin': '203001'}} <class 'dict'>

 Another way of achieving this is to create a new class


that will extend the JSONEncoder and then using that
class as an argument to the dumps method.

Example:

import json
from json import JSONEncoder

class Student:
def __init__(self, name, roll_no, address):
[Link] = name
self.roll_no = roll_no
[Link] = address
class Address:
def __init__(self, city, street, pin):
[Link] = city
[Link] = street
[Link] = pin

class EncodeStudent(JSONEncoder):
def default(self, o):
return o.__dict__

address = Address("Bulandshahr", "Adarsh Nagar", "203001")


student = Student("Raju", 53, address)

# Encoding custom object to json


# using cls(class) argument of
# dumps method
student_JSON = [Link](student, indent = 4,
cls = EncodeStudent)
print(student_JSON)
print(type(student_JSON))

# Decoding
student = [Link](student_JSON)
print()
print(student)
print(type(student))

Output:
{ "name": "Raju", "roll_no": 53, "address": { "city": "Bulandshahr",
"street": "Adarsh Nagar", "pin": "203001" } } <class 'str'> {'name':
'Raju', 'roll_no': 53, 'address': {'city': 'Bulandshahr', 'street': 'Adarsh
Nagar', 'pin': '203001'}} <class 'dict'>

Deserializing/Decoding JSON data to


Custom Python Object
converting JSON data into a custom object is known
as decoding or deserializing JSON data. We can easily convert
JSON data into a custom object by using the [Link]() or
[Link]() methods. The key is the object_hook parameter,
which allows us to define how the JSON data should be converted
into a custom Python object.
object_hook parameter is used to customize the
deserialization process. By providing a custom function to this
parameter, we can convert the JSON data into custom Python
objects.

 Using namedtuple for Custom Objects


namedtuple creates a class with fields that can be
accessed by name, providing an easy way to treat JSON
data as a Python object.

import json
from collections import namedtuple

# Sample JSON data


data = '{"name": "Geek", "id": 1, "location": "Mumbai"}'

# Convert JSON into a namedtuple object


x = [Link](data, object_hook=lambda d: namedtuple('X', [Link]())
(*[Link]()))

# Accessing data like an object


print([Link], [Link], [Link])

Output:

Explanation: the namedtuple allows us to treat the JSON


data as an object, where we can access values by their
keys as attributes.

 Using a Custom Decoder Function

We can also write a custom decoder function that converts


the JSON dictionary into a custom Python object type, and
use this function with [Link]().

import json
from collections import namedtuple

# Custom decoder function


def customDecoder(geekDict):
return namedtuple('X', [Link]())(*[Link]())
# Sample JSON data
geekJsonData = '{"name": "GeekCustomDecoder", "id": 2, "location":
"Pune"}'

# Use custom decoder to parse the JSON data


x = [Link](geekJsonData, object_hook=customDecoder)

print([Link], [Link], [Link])

Output:

Check whether a string is valid json or not


# Sample JSON data
ini_string = "{'akshat' : 1, 'nikhil' : 2}"

# checking for string


try:
json_object = [Link](ini_string)
print ("Is valid json? true")
except ValueError as e:
print ("Is valid json? false")

BUT SERIALIZING & DE-SERIALIZING CUSTOM PYTHON


OBJECTS , i.e., WRITING CUSTOM OBJECTS INTO A FILE
AND READING THEM IN THE SAME OBJECT FORMAT
(NOT DICT. OR STRING) IS COMPLEX USING JSON
MODULE.
SO, WE USE PICKLE MODULE

To read custom objects from a file and write it


back in the same format we use Pickling .
In Pickling , we can convert our custom objects
in binary form , once we convert object to binary
form it becomes transferable. We then use
Unpickling to convert the binary form back to
custom object.

The Python Pickle Module


The pickle module is used for implementing binary protocols for
serializing and de-serializing a Python object structure.
 Pickling: It is a process where a Python object hierarchy
is converted into a byte stream.
 Unpickling: It is the inverse of the Pickling process
where a byte stream is converted into an object
hierarchy.

Pickling is a way to convert a Python object (list, dictionary,


etc.) into a character stream. The idea is that this character
stream contains all the information necessary to reconstruct the
object in another Python script. This Byte stream contains all
essential information about the object so that it can be
reconstructed, or "unpickled" and get back into its
original form in any Python.

Pickling a data structure


In this example, we will serialize the dictionary data and store it
in a byte stream. Then this data is deserialized
using [Link]() function back into the original Python object.
import pickle

# initializing data to be stored in db


Omkar = {'key' : 'Omkar', 'name' : 'Omkar Pathak',
'age' : 21, 'pay' : 40000}
Jagdish = {'key' : 'Jagdish', 'name' : 'Jagdish Pathak',
'age' : 50, 'pay' : 50000}

# database
db = {}
db['Omkar'] = Omkar
db['Jagdish'] = Jagdish

# For storing
# type(b) gives <class 'bytes'>;
b = [Link](db)
# For loading
myEntry = [Link](b)
print(myEntry)
Output:
{'Omkar': {'key': 'Omkar', 'name': 'Omkar Pathak', 'age': 21,
'pay': 40000},
'Jagdish': {'key': 'Jagdish', 'name': 'Jagdish Pathak',
'age': 50, 'pay': 50000}}

Pickling with a File


In this example, we will use a pickle file to first write the data in
it using the [Link]() function. Then using the [Link]()
function, we will load the pickle fine in Python script and print its
data in the form of a Python dictionary.

import pickle

def storeData():
# initializing data to be stored in db
Omkar = {'key' : 'Omkar', 'name' : 'Omkar Pathak',
'age' : 21, 'pay' : 40000}
Jagdish = {'key' : 'Jagdish', 'name' : 'Jagdish Pathak',
'age' : 50, 'pay' : 50000}

# database
db = {}
db['Omkar'] = Omkar
db['Jagdish'] = Jagdish

# Its important to use binary mode


dbfile = open('examplePickle', 'ab')

# source, destination
[Link](db, dbfile)
[Link]()

def loadData():
# for reading also binary mode is important
dbfile = open('examplePickle', 'rb')
db = [Link](dbfile)
for keys in db:
print(keys, '=>', db[keys])
[Link]()

storeData()
loadData()

Output:
Omkar => {'key': 'Omkar', 'name': 'Omkar Pathak', 'age': 21,
'pay': 40000}
Jagdish => {'key': 'Jagdish', 'name': 'Jagdish Pathak',
'age': 50, 'pay': 50000}

Pickling/Unpickling a custom object


We create a custom class ModelTrainer. Next, we have
created the model object. We have created a new file in 'wb'
(Write bytes) mode. The dump() method dumps the object
as bytes stream into the file(PICKLING).
Next, we load the file in a variable “new_model ”- since we
dumped a custom object(model) in binary form into the file, so
on loading the dumped object(model) gets loaded – thus the
variable “new_model ” is a custom object of custom class
ModelTrainer .
Verification is done by successfully accessing an instance
method new_model.get_weights() of the class in a new object.

import pickle

class ModelTrainer:
def __init__(self) -> None:
[Link] = [0,0,0]

def train(self):
for i in range(len([Link])):
[Link][i] = [Link]()

def get_weights(self):
return [Link]

# Create an object
model = ModelTrainer()

# Populate the data


[Link]()

# Open a file to write bytes


p_file = open('[Link]', 'wb')

# Pickle the object


[Link](model, p_file)
p_file.close()

# Deserialization of the file


file = open('[Link]','rb')
new_model = [Link](file)

print('Weights after pickling', new_model.get_weights())

Namespaces
A namespace is a space that holds names(identifiers).Programmatically
speaking, namespaces are dictionary of identifiers(keys) and their
objects(values)
There are 4 types of namespaces:
 Builtin Namespace
 Global Namespace
 Enclosing Namespace
 Local Namespace

Scope
A scope is a textual region of a Python program where a namespace is directly
accessible.

LEGB Rule
The interpreter searches for a name from the inside out, looking in the local,
enclosing, global, and finally the built-in scope. If the interpreter doesn’t find the
name in any of these locations, then Python raises a NameError exception.

# local and global -> same name


a = 2

def temp():
# local var
a = 3
print(a)

temp()
print(a)
output:
3
2

Accessing global variable from local scope:

# local and global -> local does not have but global has
a = 2

def temp():
# local var
print(a)

temp()
print(a)
output:
2
2

If we try to modify a Global variable from inside a local scope- ERROR!

# local and global -> editing global


a = 2

def temp():
# local var
a += 1
print(a)

temp()
print(a)

UnboundLocalError: local variable 'a' referenced before assignment

Use “global” keyword inside local block if modification needs to be


done on global variable

a = 2

def temp():
# local var
global a
a += 1
print(a)

temp()
print(a)
output:
3
3

Creating a Global variable from inside local scope:

# local and global -> global created inside local


def temp():
# local var
global a
a = 1
print(a)

temp()
print(a)

Built-in Scope:

Functions like print(),type(),len() . To use them , we do


NOT need to import any modules, these are available in
Built-in scope

Enclosing scope:
In case of nested functions , the outer function is called
the enclosing scope .
# Enclosing scope
def outer():
def inner():
print(a)
inner()
print('outer function')

outer()
print('main program')

Iterables
Iterables are objects that can return an iterator. These include
built-in data structures like lists, dictionaries, and sets.
Essentially, an iterable is anything you can loop over using a for
loop. An iterable implements the __iter__() method, which is
expected to return an iterator object.
Iterators are the objects that actually perform the iteration.

Iterators
Iterators are the objects that actually perform the iteration. An
iterator holds a sequence of values and provide sequential
traversal through a collection of items such as lists, tuples and
dictionaries. . The Python iterators object is initialized using
the iter() method. It uses the next() method for iteration.
1. __iter__(): __iter__() method initializes and returns the
iterator object itself.
2. __next__(): the __next__() method retrieves the next
available item, throwing a StopIteration exception when
no more items are available.

s = "GFG" # ‘s’ is an iterable


it = iter(s) # ‘it’ is an iterator

print(next(it))
print(next(it))
print(next(it))

Output
G
F
G

What is an Iteration
Iteration is a general term for taking each item of something, one after
another. Any time you use a loop, explicit or implicit, to go over a group of
items, that is iteration.
num = [1,2,3]
for i in num:
print(i)

What is Iterator
An Iterator is an object that allows the programmer to traverse through a
sequence of data without having to store the entire data in the memory

What is Iterable
Iterable is an object, which one can iterate over. It generates an Iterator
when passed to iter() method.
L = [1,2,3]
type(L) # L is an iterable
type(iter(L)) # iter(L) --> iterator

Point to remember
 Every Iterator is also and Iterable
 Not all Iterables are Iterators

How to identify iterable or iterator?


 Every Iterable has an iter function
 Every Iterator has both iter function as well as a next function

StopIteration Exception
The StopIteration exception is integrated with Python’s iterator
protocol. It signals that the iterator has no more items to return.
Once this exception is raised, further calls to next() on the same
iterator will continue raising StopIteration.
Example:
li = [100, 200, 300]
it = iter(li)

# Iterate until StopIteration is raised


while True:
try:
print(next(it))
except StopIteration:
print("End of iteration")
break

Output
100
200
300
End of iteration
In this example, the StopIteration exception is manually handled
in the while loop, allowing for custom handling when the iterator
is exhausted.
Creating a custom iterator
Creating a custom iterator in Python involves defining a class
that implements the __iter__() and __next__() methods according
to the Python iterator protocol.
 Define the Class: Start by defining a class that will act
as the iterator.
 Initialize Attributes: In the __init__() method of the
class, initialize any required attributes that will be used
throughout the iteration process.
 Implement __iter__(): This method should return the
iterator object itself. This is usually as simple as
returning self.
 Implement __next__(): This method should provide the
next item in the sequence each time it's called.

Below is an example of a custom class called EvenNumbers,


which iterates through even numbers starting from 2:

class EvenNumbers:
def __iter__(self):
self.n = 2 # Start from the first even number
return self

def __next__(self):
x = self.n
self.n += 2 # Increment by 2 to get the next even number
return x

# Create an instance of EvenNumbers


even = EvenNumbers()
it = iter(even)

# Print the first five even numbers


print(next(it))
print(next(it))
print(next(it))

Output
2
4
6
Explanation:
 Initialization: The __iter__() method initializes the
iterator at 2, the first even number.
 Iteration: The __next__() method retrieves the current
number and then increases it by 2, ensuring the next call
returns the subsequent even number.
 Usage: We create an instance of EvenNumbers, turn it
into an iterator and then use the next() function to fetch
even numbers one at a time.

what does for do behind the scenes?


When you write:

for x in some_iterable:
print(x)

Python internally does something like this:

_iterator = iter(some_iterable)
while True:
try:
x = next(_iterator)
print(x)
except StopIteration:
break

So the for loop works with:


 Any object that is an iterable (i.e. has an __iter__() method),
 Which gives an iterator (i.e. has a __next__() method),
 And the loop keeps calling next() until the iterator raises StopIteration

Making our own for loop (See how a for loop


works by utilising iterator concepts)
[for i in list/tuple/dict etc. -> for i in iterable ]

[for i in range(start,stop) -> for i in iterable ]


# range(start,stop) is an iterable object -> range is an iterable class

def mera_khudka_for_loop(iterable):
iterator = iter(iterable)
while True:
try:
print(next(iterator))
except StopIteration:
break

a = [1,2,3]
b = (1,2,3)
mera_khudka_for_loop(a)
1
2
3

How range works :


 range is an iterable class that implements __iter__().
 __iter__() method returns a range iterator — an object that has a
__next__() method.
 This is why you can use range in for loops, comprehensions, etc.

Here’s a mock version of range class:

class range:
def __init__(self, start, stop):
[Link] = start
[Link] = stop

def __iter__(self):
return range_Iterator([Link], [Link])

class range_Iterator:
def __init__(self, start, stop):
[Link] = start
[Link] = stop

def __next__(self):
if [Link] >= [Link]:
raise StopIteration
val = [Link]
[Link] += 1
return val

Now:
for num in range(0, 3):
print(num)

Boom — prints 0, 1, 2

range() is an iterable, not an iterator.


 When you do this: r = range(5)
You've created a range object, which is iterable. That means Python can loop
over it (like in a for loop), but it’s not an iterator yet.

when you call: it = iter(range(5))


Now ‘it’ is an iterator, and you can do:
next(it) # gives you 0
next(it) # gives you 1

The range class in Python does have an __iter__() method.


That’s what makes range an iterable.

Making our own range() function


class mera_range: # Iterable class

def __init__(self,start,end):
[Link] = start
[Link] = end

def __iter__(self):
return mera_range_iterator(self)

class mera_range_iterator: # Iterator class

def __init__(self,iterable_obj):
[Link] = iterable_obj

def __iter__(self):
return self

def __next__(self):

if [Link] >= [Link]:


raise StopIteration

current = [Link]
[Link]+=1
return current

x = mera_range(1,11)

type(x)
iter(x)

Some useful Iterators :

1. acuulate(iter, func) :- This iterator takes two arguments,


iterable target and the function which would be followed
at each iteration of value in target. If no function is
passed, addition takes place by [Link] the input iterable is
empty, the output iterable will also be empty.

2. chain(iter1, iter2..) :- This function is used to print all


the values in iterable targets one after another mentioned in
its arguments.

# importing "itertools" for iterator operations


import itertools

# importing "operator" for operator operations


import operator

# initializing list 1
li1 = [1, 4, 5, 7]

# initializing list 2
li2 = [1, 6, 5, 9]

# initializing list 3
li3 = [8, 10, 5, 4]

# using accumulate()
# prints the successive summation of elements
print ("The sum after each iteration is : ",end="")
print (list([Link](li1)))

# using accumulate()
# prints the successive multiplication of elements
print ("The product after each iteration is : ",end="")
print (list([Link](li1,[Link])))

# using chain() to print all elements of lists


print ("All values in mentioned chain are : ",end="")
print (list([Link](li1,li2,li3)))
Output:

The sum after each iteration is : [1, 5, 10, 17]


The product after each iteration is : [1, 4, 20, 140]
All values in mentioned chain are : [1, 4, 5, 7, 1, 6, 5, 9,
8, 10, 5, 4]

3. chain.from_iterable() :- This function is implemented


similarly as chain() but the argument here is a list of lists or
any other iterable container.

# Python code to demonstrate the working of


# chain.from_iterable()

# importing "itertools" for iterator operations


import itertools

# initializing list 1
li1 = [1, 4, 5, 7]

# initializing list 2
li2 = [1, 6, 5, 9]

# initializing list 3
li3 = [8, 10, 5, 4]

# initializing list of list


li4 = [li1, li2, li3]

# using chain.from_iterable() to print all elements of lists


print ("All values in mentioned chain are : ",end="")
print (list([Link].from_iterable(li4)))

5. dropwhile(func, seq) :- This iterator starts printing the


characters only after the func. in argument returns false for
the first time.
6. filterfalse(func, seq) :- As the name suggests, this iterator
prints only values that return false for the passed function.

# Python code to demonstrate the working of


# dropwhile() and filterfalse()

# importing "itertools" for iterator operations


import itertools

# initializing list
li = [2, 4, 5, 7, 8]

# using dropwhile() to start displaying after condition is false


print ("The values after condition returns false : ",end="")
print (list([Link](lambda x : x%2==0,li)))

# using filterfalse() to print false values


print ("The values that return false to function are : ",end="")
print (list([Link](lambda x : x%2==0,li)))
Output:

The values after condition returns false : [5, 7, 8]


The values that return false to function are : [5, 7]

Converting an object into an iterator


Last Updated : 10 Mar, 2025



In Python, we often need to make objects iterable, allowing
them to be looped over like lists or other collections. Instead of
using complex generator loops, Python provides
the __iter__() and __next__() methods to simplify this process.
Iterator Protocol:
 __iter__(): Returns the iterator object itself.
 __next__(): Returns the next item in the sequence or
raises StopIteration when there are no more items.
Example: Creating an Iterable Object
a = ['a', 'e', 'i', 'o', 'u']

iter_a = iter(a)

print(next(iter_a))
print(next(iter_a))
print(next(iter_a))
print(next(iter_a))
print(next(iter_a))

Output
a
e
i
o
u
Explanation: List a is converted into an
iterator iter_a and next() retrieves each element sequentially.
Once exhausted, further calls to next(iter_a) raise
a StopIteration exception.
Python __iter__()
The __iter__() function in Python returns an iterator for the given
object (e.g., array, set, tuple, or a custom object). It creates an
object that can be accessed one element at a time using
__next__(). This is particularly useful when dealing with loops.
Syntax:
iter(object)
iter(callable, sentinel)
object: The object whose iterator is created. It can be a collection
like a list or a user-defined object.
callable, sentinel:
 callable: A function that generates values dynamically.
 sentinel: The value at which iteration stops.
Example: Using iter(callable,sentinel)
import random
rand_iter = iter(lambda: [Link](1, 10), 5) # Stops when 5 is
generated

for num in rand_iter:


print(num)

Output
8
7
1
1
7
9
Explanation: This code creates an iterator that generates
random numbers from 1 to 10, stopping when 5 appears. The for
loop prints numbers until 5 is encountered, making the output
vary each run.
Python __next__()
The __next__() function in Python returns the next element of an
iteration. If there are no more elements, it raises
the StopIteration exception. It is part of the iterable and
iterator interface, which allows us to create custom iterable
objects, such as generators, and control how elements are
retrieved one at a time.
Example 1. Using __next__() in loop
a = [11, 22, 33, 44, 55]

iter_a = iter(a)
while True:
try:
print(iter_a.__next__())
except StopIteration:
break

Output
11
22
33
44
55
Explanation: List a is converted into an iterator iter_a and a
while True loop is used to retrieve elements using __next__().
A try-except block handles StopIteration, ensuring iteration stops
gracefully when the iterator is exhausted.
Example 2. Exception handling
a = ['Cat', 'Bat', 'Sat', 'Mat']

iter_a = iter(a)

try:
print(iter_a.__next__())
print(iter_a.__next__())
print(iter_a.__next__())
print(iter_a.__next__())
print(iter_a.__next__()) # Raises StopIteration error
except StopIteration:
print("\nThrowing 'StopIterationError': Cannot iterate further.")

Output
Cat
Bat
Sat
Mat
Throwing 'StopIterationError': Cannot iterate further.
Explanation: List a is converted into an
iterator iter_a and__next__() retrieves elements sequentially.
When exhausted, StopIteration is caught, displaying a custom
message.
Using __iter__() and __next__() in user-defined objects
We can implement the iterator protocol in user-defined classes by
defining __iter__() and __next__() methods.
The __iter__() method should return the iterator object
and __next__() should return the next element in the sequence.
Example:
class Counter:
def __init__(self, start, end):
[Link] = start
[Link] = end

def __iter__(self):
return self

def __next__(self):
if [Link] > [Link]:
raise StopIteration
else:
[Link] += 1
return [Link] - 1

# Driver code
if __name__ == '__main__':
a, b = 2, 5
c1 = Counter(a, b)
c2 = Counter(a, b)

# Iteration without using iter()


print("Print the range without iter():")
for i in c1:
print("Counting:", i)

print("\nPrint the range using iter():")

# Using iter()
obj = iter(c2)
try:
while True: # Iterate until StopIteration is raised
print("Counting:", next(obj))
except StopIteration:
print("\nIteration completed.")

Output
Print the range without iter():
Counting: 2
Counting: 3
Counting: 4
Counting: 5

Print the range using iter():


Counting: 2
Counting: 3
Counting: 4
Counting: 5

Iteration completed.
Explanation: The Counter class iterates from start to end,
with __iter__() returning itself and __next__() incrementing
until StopIteration. The first loop iterates over c1, while the
second uses iter(c2) and next(obj), handling exhaustion
gracefully.
WHY USE ITERATORS ??
L = [x for x in range(100000)]
This creates a list — it stores all 100,000 numbers in memory at once.

range is an iterable class

x = range(10000000)
This creates a range object — which acts like an iterator factory, but doesn't store all
the numbers.

Then you do:


[Link](L)
[Link](x)

You're asking:
“How much memory do these two objects actually take up?”

Memory results (approximate):


[Link](L) → 800,000+ bytes
[Link](x) → around 48 bytes
🤯 10 million numbers taking only 48 bytes???
Here’s why ⬇️
🔍 What's the difference?
L = [x for x in range(100000)]
This list comprehension stores every number in memory. Imagine 100,000 little boxes in
RAM, all lined up, holding [Link] integer takes space. The list object itself takes some
space too (to store pointers and metadata).
→ So the memory usage is BIG.

x = range(10000000)
This doesn't store 10 million numbers! It’s an iterable that creates numbers on demand,
only when you need them instead of storing them all at once. It just stores: start (default is
0), stop (10,000,000), step (default is 1)

Yield : It replace the return of a function to suspend its execution


without destroying local variables. Code written after yield
statement execute in next function call. Yield statement
function is executed from the last state from where the
function get paused.

Generator Function in Python


A generator function is a special type of function that returns an
iterator object. Instead of using return to send back a single
value, generator functions use yield to produce a series of
results over time. This allows the function to generate values
and pause its execution after each yield, maintaining its
state between iterations.

def fun(max):
cnt = 1
while cnt <= max:
yield cnt
cnt += 1

ctr = fun(5)
for n in ctr:
print(n)
Output
1
2
3
4
5
Explanation: This generator function fun yields numbers from 1
up to a specified max. Each call to next() on the generator
object resumes execution right after the yield statement,
where it last left off.

A generator is a special type of iterator, but way easier to write.


It lets you pause execution and resume later, picking up where it left off.

Instead of doing:

def square(num):
result = []
for i in range(1, num+1):
[Link](i**2)
return result

You write:

def square(num):
for i in range(1, num+1):
yield i**2

The yield turns this from a boring ol' function into a generator function.

As soon as Python sees yield, it knows: “Aha! I’m making a generator.”


Then: gen = square(10)
 doesn’t run the function!

 It just returns a generator object: something that’s ready to produce values, but hasn’t started
yet.

Now,
print(next(gen))

 First call to next() → runs square() up to the first yield


 Yields 1**2 → 1
 Pauses there, remembers where it left off

Then again:

print(next(gen)) # 4
print(next(gen)) # 9

Each call picks up where the last left off

Then we do:
for i in gen:
print(i)

At this point, gen has already given you 1, 4, and 9.


So the loop resumes from the 4th item:
4**2 = 16, and goes until 10**2 = 100

That’s why your final output is:

1
4
9
16
25
36
49
64
81
100

But only because the for loop picked up after the first 3 values were already consumed.

🧠 So... why is this a generator, and how does it help?


✅ It’s a generator because:

 It has yield
 It returns a lazy iterator — no list stored in memory
 It supports next() and can be used in a for loop

💪 Why is it awesome (vs writing an iterator class)?

Let’s compare:
😵 Manual iterator (without using generators):
class Square:
def __init__(self, num):
[Link] = num
[Link] = 1

def __iter__(self):
return self

def __next__(self):
if [Link] > [Link]:
raise StopIteration
val = [Link] ** 2
[Link] += 1
return val

That’s a lot of boilerplate just to square some numbers. 😩

😎 Generator version:
def square(num):
for i in range(1, num+1):
yield i**2

Range Function without Generator


class mera_range: # Iterable class

def __init__(self,start,end):
[Link] = start
[Link] = end

def __iter__(self):
return mera_range_iterator(self)

class mera_range_iterator: # Iterator class

def __init__(self,iterable_obj):
[Link] = iterable_obj

def __iter__(self):
return self

def __next__(self):

if [Link] >= [Link]:


raise StopIteration
current = [Link]
[Link]+=1
return current

x = mera_range(1,11)
iter(x)

Range Function using Generator


def mera_range(start,end):
for i in range(start,end):
yield i

for i in mera_range(15,26):
print(i)

Python Generator Expression


Generator expressions are a concise way to create generators.
They are similar to list comprehensions but use parentheses
instead of square brackets and are more memory efficient.

Syntax:
(expression for item in iterable)

Example:

In this example, we will create a generator object that will print


the squares of integers between the range of 1 to 6 (exclusive).

sq = ( x*x for x in range(1, 6) )


for i in sq:
print(i)

4. Chaining Generators

def fibonacci_numbers(nums):
x, y = 0, 1
for _ in range(nums):
x, y = y, x+y
yield x

def square(nums):
for num in nums:
yield num**2

print(sum(square(fibonacci_numbers(10))))

You might also like