Python Programming — Complete Notes | @Sovit.tech
Python Programming — Complete Notes | @Sovit.tech
knowledge
Python Programming
Complete Notes
From zero to advanced — syntax, data types, OOP, file handling,
decorators, concurrency & async. Every concept, example, and diagram
in one place.
Syntax & Basics Data Types Operators Control Flow Data Structures
2
› 8.1 for Loop › 9.3.9 Real-World Dictionary Use Cases
› 8.2 while Loop › 9.3.10 Nested Dictionaries
› 8.3 break › 9.3.11 Dictionary Comprehensions
› 8.4 continue › 9.3.12 Merging Dictionaries
› 8.5 pass › 9.3.13 Copying Dictionaries
› 8.6 else with Loops › 9.3.14 Dictionary vs List
› 8.7 Nested Loops › 9.3.15 Important Dictionary Operations
› 8.8 range() › 9.4 Sets
› 8.9 enumerate() › 9.4.1 Creating Sets
› 8.10 zip() › 9.4.2 Unique Values
› 8.11 Iterator Protocol Basics › 9.4.3 Set Elements Must Be Immutable
› 8.12 StopIteration › 9.4.4 Accessing Set Values
› 9.4.5 Checking Membership
9 Data Structures
› 9.4.6 Adding Set Items
› 9.1 Lists › 9.4.7 Removing Set Items
› 9.1.1 Creating Lists › 9.4.8 Set Operations
› 9.1.2 Accessing List Values › 9.4.9 Union
› 9.1.3 Updating List Values › 9.4.10 Intersection
› 9.1.4 List Methods › 9.4.11 Difference
› 9.1.5 List Slicing › 9.4.12 Symmetric Difference
› 9.1.6 List Comprehensions › 9.4.13 Subset, Superset, & Disjoint Sets
› 9.1.7 Nested Lists › 9.4.14 Set Methods
› 9.1.8 Sorting and Reversing Lists › 9.4.15 Set Operators
› 9.1.9 Copying Lists › 9.4.16 Updating Sets with Operations
› 9.1.10 Shallow Copy vs Deep Copy › 9.4.17 Copying Sets
› 9.2 Tuples › 9.4.18 Frozen Sets
› 9.2.1 Creating Tuples › 9.4.19 Set Comprehensions
› 9.2.2 Tuple Immutability › 9.4.20 Set Conversion
› 9.2.3 Tuple Packing › 9.4.21 Set vs List vs Tuple
› 9.2.4 Tuple Unpacking › 9.5 Collections Module
› 9.2.5 Named Tuples › 9.5.1 Counter
› 9.2.6 Tuple vs List › 9.5.2 defaultdict
› 9.2.7 Tuple methods › 9.5.3 OrderedDict
› 9.2.8 Tuple operations › 9.5.4 deque
› 9.2.9 Tuple packing › 9.5.5 ChainMap
› 9.2.10 Tuple unpacking
› 9.2.11 Extended Tuple Unpacking 10 Functions
› 9.2.12 Named Tuples › 10.1 What is a Function?
› 9.2.13 Tuple vs List › 10.2 Defining Functions
› 9.3 Dictionaries › 10.3 Calling Functions
› 9.3.1 Creating Dictionaries › 10.4 Parameters
› 9.3.2 Accessing Dictionary Values › 10.5 Arguments
› 9.3.3 Updating Dictionary Values › 10.6 Positional Arguments
› 9.3.4 Dictionary Methods › 10.7 Return Values
› 9.3.5 get() Method › 10.8 Returning Multiple Values
› 9.3.6 Nested Dictionaries › 10.9 Default Parameters
› 9.3.7 Dictionary Comprehensions › 10.10 Keyword Arguments
› 9.3.8 Merging Dictionaries › 10.11 *args
3
› 10.12 **kwargs › 13.15 Virtual Environment Basics
› 10.13 *args vs **kwargs › 13.16 [Link]
› 10.14 Function Parameter Order › 13.17 Third-Party Packages
› 10.15 Docstrings › 13.18 Circular Import Warning
› 10.16 Function Naming Rules
14 Object-Oriented Programming
11 Advanced Functions › 14.1 OOP Fundamentals
› 11.1 Functions as First-Class Objects › 14.1.1 Classes
› 11.2 Lambda Functions › 14.1.2 Objects
› 11.3 map() › 14.1.3 Attributes
› 11.4 filter() › 14.1.4 Methods
› 11.5 reduce() › 14.1.5 self
› 11.6 Recursion › 14.1.6 __init__ Constructor
› 11.7 Nested Functions › 14.1.7 Instance Variables
› 11.8 Closures › 14.1.8 Class Variables
› 11.9 Function Annotations › 14.1.9 Methods vs Functions
› 11.10 Higher-Order Functions › 14.2 OOP Principles
› 14.2.1 Encapsulation
12 Scope and Namespaces
› 14.2.2 Inheritance
› 12.1 Local Scope › 14.2.3 Method Overriding
› 12.2 Global Scope › 14.2.4 Polymorphism
› 12.3 Local vs Global Scope › 14.2.5 Duck Typing
› 12.4 Variable Shadowing › 14.2.6 Abstraction
› 12.5 global Keyword › 14.2.7 Composition
› 12.6 Enclosing Scope › 14.3 Special Methods
› 12.7 nonlocal Keyword › 14.3.1 __str__
› 12.8 Built-in Scope › 14.3.2 __repr__
› 12.9 LEGB Rule › 14.3.3 __len__
› 12.10 Namespace Concept › 14.3.4 __getitem__
› 12.11 locals() and globals() › 14.3.5 __add__
› 12.12 NameError & UnboundLocalError › 14.3.6 __sub__
› 12.13 Important Scope Summary Table › 14.3.7 __call__
› 14.3.8 __enter__ & __exit__
13 Modules and Packages
› 14.3.9 Context Manager Real Use
› 13.1 Importing Modules
› 14.3.10 Operator Overloading
› 13.2 Different Ways to Import
› 14.3.11 Magic Methods / Dunder Methods
› 13.3 Standard Library Modules
› 14.3.12 Reverse and In-place Operator Methods
› 13.4 Creating Your Own Modules › 14.3.13 __bool__
› 13.5 Importing Specific Code from Your Own › 14.3.14 __iter__ and __next__
Module
› 14.3.15 __contains__
› 13.6 Module Search Path
› 13.7 Exploring a Module with dir() 15 Advanced OOP in Python
› 13.8 __name__ == "__main__" › 15.1 @classmethod
› 13.9 Package Structure › 15.2 Class Method as Alternate Constructor
› 13.10 __init__.py › 15.3 @staticmethod
› 13.11 Absolute Imports › 15.4 Instance Method vs Class Method vs Static
› 13.12 Relative Imports Method
› 13.13 Package Management Basics › 15.5 @property
› 13.14 pip Basics
4
› 15.6 @property Setter › 16.3.4 JSON Files
› 15.7 Read-only Property › 16.3.5 [Link]() vs [Link]()
› 15.8 Abstract Base Classes › 16.3.6 XML Files
› 15.9 Why Abstract Base Classes Are Used
17 Advanced Python Concepts
› 15.10 Mixins
› 15.11 Mixin vs Normal Parent Class › 17.1 Decorators
› 15.12 Metaclasses › 17.1.1 Decorators
› 15.13 Data Classes › 17.1.2 Function Decorators
› 15.14 Normal Class vs Data Class › 17.1.3 Decorators with Function Arguments
› 15.15 Default Values in Data Classes › 17.1.4 [Link]
› 15.16 Mutable Defaults in Data Classes › 17.1.5 Decorators with Arguments
› 15.17 Frozen Data Classes › 17.1.6 Multiple Decorators
› 17.1.7 Class Decorators
16 File Handling and Error Management › 17.1.8 Built-in and Standard Decorators
› 16.1 File Operations › 17.2 Generators and Iterators
› 16.1.1 File Handling › 17.2.1 Generators and Iterators
› 16.1.2 Opening Files › 17.2.2 Iterable vs Iterator
› 16.1.3 Closing Files › 17.2.3 Iterator Protocol
› 16.1.4 Reading Files › 17.2.4 __iter__
› 16.1.5 Reading Line by Line › 17.2.5 __next__
› 16.1.6 Writing Files › 17.2.6 Generator Functions
› 16.1.7 Appending Files › 17.2.7 yield
› 16.1.8 File Modes › 17.2.8 Generator Expressions
› 16.1.9 with Statement › 17.2.9 yield from
› 16.1.10 File Object Methods › 17.2.10 One-time Consumption of Iterators
› 16.1.11 Binary Files › 17.2.11 itertools
› 16.1.12 File Paths › 17.2.12 Memory Efficiency
› 16.1.13 Basic os Module › 16.3 Context Managers
› 16.1.14 Basic pathlib Module › 16.3.1 __enter__
› 16.1.15 Encoding › 16.3.2 __exit__
› 16.2 Exception Handling › 16.3.3 Custom Context Manager Using Class
› 16.2.1 try-except › 16.3.4 contextlib
› 16.2.2 Catching Exception Object › 16.3.5 @contextmanager
› 16.2.3 Multiple except Blocks › 16.3.6 Resource Management
› 16.2.4 Handling Multiple Exceptions Together › 16.4 Regular Expressions
› 16.2.5 else in Exception Handling › 16.4.1 re Module
› 16.2.6 finally › 16.4.2 Pattern Matching
› 16.2.7 try-except-else-finally Flow › 16.4.3 Regex Metacharacters
› 16.2.8 Raising Exceptions › 16.4.4 Common Regex Character Classes
› 16.2.9 Re-raising Exceptions › 16.4.5 Groups and Capturing
› 16.2.10 Custom Exceptions › 16.4.6 Non-capturing Groups
› 16.2.11 Exception Hierarchy › 16.4.7 search()
› 16.2.12 Bare except Warning › 16.4.8 match()
› 16.2.13 File Handling with Exception Handling › 16.4.9 fullmatch()
› 15.3 File Formats › 16.4.10 findall()
› 16.3.1 Text Files › 16.4.11 finditer()
› 16.3.2 CSV Files › 16.4.12 sub()
› 16.3.3 [Link] vs [Link] › 16.4.13 split()
5
› 16.4.14 [Link]() › 17.3 Concurrent Futures
› 17.3.1ThreadPoolExecutor
17 Concurrent and Asynchronous
› 17.3.2 ProcessPoolExecutor
Programming › 17.3.3Futures
› 17.1 Multithreading › 17.3.4Async Programming
› 17.1.1 threading Module › 17.4 Async Programming
› 17.1.2 Creating Threads › 17.4.1 asyncio
› 17.1.3 Managing Threads › 17.4.2 async and Coroutines
› 17.1.4 Race Conditions › 17.4.3 await
› 17.1.5 Locks › 17.4.4 Event Loop
› 17.1.6 Synchronization › 17.4.5 Tasks
› 17.2 Multiprocessing › 17.4.6 [Link]()
› 17.1.1 Managing Processes › 17.4.7 Async Futures
› 17.1.2 Process Pools › 17.4.8 Async Context Managers
› 17.1.3 Memory Sharing Basics › 17.4.9 Async vs Threading vs Multiprocessing
› 17.1.4 Concurrent Futures
1 Python Overview
6
PYTHON CODE print("Hello, World!")
Output: Hello, World! Python files are saved with the .py extension. Example: [Link], [Link], [Link]
Python is easy to start with and powerful enough for real-world projects.
Python is useful because:
● It is beginner-friendly. ● It is used in many industries. ● It has simple syntax. ● It has many libraries. ●
It is good for automation. ● It is widely used in AI, data science, and backend development.
Feature Meaning
Large library support Many built-in and external libraries are available
For modern learning, use Python 3 . Python 2 is oldand should not be used for new learning.
To check Python version, use:
python --version or: python3 --version
Example output: Python 3.12.5
◆ Basic flow:
7
Source Code → Bytecode → Python Virtual Machine → Output
For now, remember:
● Python code is written in .py files. ● Python interpreter reads and runs the code. ● Python runs code
from top to bottom. ● Output is shown on the screen.
Before code runs, it must be translated into a form the computer can understand.
There are two common translators:
● Compiler
● Interpreter Compiler
Interpreter
An interpreter runs code more directly.
Flow: Source Code → Interpreter → Output
Python is commonly called an interpreted language.
Compiler vs Interpreter
Translation Translates full code before running Runs code more directly
Error checking Many errors found before running Errors can appear while running
2 Environment Setup
Environment setup means preparing your computer so you can write, run, and manage Python
programs properly.
For Python development, we mainly need:
8
1. Python installed on the system 2. A code editor like VS Code 3. Terminal/Command Prompt basics 4.
Package manager pip 5. Virtual environment setup using venv
Install Python
↓ Check Python Version
↓ Install VS Code
↓ Write Python Code
↓ Run Python File
↓ Use venv and pip for Projects
The safest way is to download Python from the official Python website. The official Python downloads
page provides the latest stable Python release and installers for different operating systems.
For Windows
1. Go to the official Python website. 2. Download the latest stable Python 3 installer. 3. Open the
installer. 4. Select Add [Link] to PATH. 5. Click Install Now. 6. Wait for installation to complete. 7.
Open Command Prompt and check the version.
Important: Always tick: Add [Link] to PATH
This option allows you to run Python from the terminal.
For macOS
Steps:
1. Download the macOS installer from the official Python website. 2. Open the .pkg file. 3. Follow the
installation steps. 4. Open Terminal. 5. Check Python version.
Command: python3 --version
For Linux
Many Linux systems already come with Python installed.
Check version: python3 --version
For Ubuntu/Debian-based systems, Python can usually be installed with:
sudo apt update sudo apt install python3 python3-pip python3-venv
9
2.3 Installing VS Code
VS Code is a code editor used to write and run Python code. Python itself runs the code, but VS Code
helps us write code easily.
Steps to Install VS Code
1. Download VS Code from the official website. 2. Install it. 3. Open VS Code. 4. Go to Extensions. 5.
Search for Python. 6. Install the official Python extension by Microsoft. 7. Open a Python file. 8. Select
Python interpreter if VS Code asks.
Creating First Python File in VS Code
Create a file: [Link]
Write:
The terminal / command prompt is a place where we type commands to interact with the computer.
Windows macOS/Linux
Task Meaning
Command Command
List files and dir ls Shows files and folders inside the
folders current folder
10
Create folder mkdir python- mkdir python-notes Creates a new folder named python-
notes notes
The Python interpreter is the program that reads and runs Python code.
When we write: print("Hello")
the computer does not understand this directly.
The Python interpreter reads this code and executes it.
Basic flow: Python Code → Python Interpreter → Output
Python REPL allows us to run Python code line by line. It is useful for quick testing.
Opening Python REPL
Windows: python or: py
macOS/Linux: python3
You may see something like: >>>
11
Ctrl + Z then Enter on Windows Ctrl + D on macOS/Linux
REPL vs Python File
A Python file is a file that contains Python code. Python files use the .py extension.
Examples:
[Link], [Link], [Link], student_app.py Creating a Python File
Steps:
1. Create a project folder. 2. Open it in VS Code. 3. Create a new file. 4. Save it with the .py extension. 5.
Write Python code. 6. Run the file.
Example File
File name: [Link]
Code:
PYTHON CODE
print("Hello, Python") print("This is my first Python file")
Run:
▶ Output:
12
Output:
Start Name: Nishchal End Common Mistakes
● Saving file as [Link]. ● Forgetting .py extension. ● Running the wrong file. ● Writing Python code
in the terminal instead of a file. ● Not saving file before running. ● Giving file names with spaces.
Bad: my first python [Link]
Good: first_python_file.py
Best Practices
● Use lowercase file names. ● Use underscores for multiple words. ● Keep one project in one folder. ●
Save before running. ● Keep file names meaningful.
A virtual environment is an isolated environment for a Python project. It keeps project packages
separate from other projects.
Python’s official documentation says venv is the standard tool for creating virtual environments, and
each virtual environment has its own independent set of installed Python packages.
Why Virtual Environment is Needed
Suppose you have two projects:
Project A needs package version 1.0 Project B needs package version 2.0
If both projects use the same global Python environment, package conflicts can happen.
Virtual environments solve this problem.
Computer Python
↓ Project A → venv → packages for Project A Project B → venv → packages for Project B Project C →
venv → packages for Project C
Package Use
13
pandas Data analysis
pytest Testing
2.10 [Link]
[Link] is a file that stores the list of packages used in a Python project.
It helps other people install the same packages easily.
Example: requests==2.32.3 pandas==2.2.2 numpy==2.0.1
Why [Link] is Important
Suppose you create a project and install many packages. Later, you share the project with another
person. Instead of telling them every package manually, you give them [Link] . They can
install everything usingone command.
Create [Link]
or:
14
This creates a file like:
requests==2.32.3 urllib3==2.2.2 certifi==2024.7.4
Install Packages from [Link]
or:
Python syntax means the set of rules used to write Python programs.
Just like English has grammar, Python also has grammar. If we do not follow Python syntax rules, the
program gives an error Python is beginner-friendly because its syntax is simple, readable, and close to
normal English.
✎ Example:
Part Meaning
15
◆ Diagram:
✎ Another example:
▶ Output:
16
A Python file can be very simple. It may contain only one line of code. But in larger programs, we
usually follow a clean structure.
◆ Diagram:
17
★ Important point:
Python does not force a fixed file structure for small programs. But writing code in a clean order makes
it easier to read and maintain.
3.3 Comments
Comments are notes written inside a program. Python ignores comments while running the code
Comments are useful for explaining what the code does.
Single-Line Comment
18
Inline Comment
Output: 20
Multi-Line Comments
Python does not have a special multi-line comment symbol. The recommended way is to use # on each
line.
Output: 30
Triple quotes can also be used for multi-line text, but technically they create a string.
19
Output: Program started Best practice for beginners: use # for comments. 3.4 Indentation Rules
Indentation means spaces at the beginning of a line. Python uses indentation to define code blocks. In
many languages, curly braces {} are usedto define blocks. Python uses indentation instead.
Example:
Output: 10 is greater than 5 Here, the print() line is indented because it belongsto the if block.
20
▶ Output:
Explanation:
Wrong Indentation
Correct code:
21
Important Indentation Rules
3.5 Variables
▶ Output:
Rahul 21 5.8
Variable Name Value name ------> "Rahul" age ------> 21 height ------> 5.8
Basic syntax: variable_name = value
Example:
22
Variable Value Type
marks 85 Integer
In Python, we do not need to write the data type before the variable name.
Output: 10
Python In the first line, x stores an integer. Later, x stores a string. This is allowed because Python is
dynamically typed. Multiple Variable Assignment
23
Output: 10 20 30 Same Value to Multiple Variables
These names are not always wrong, but they are less clear. Rules for Naming Variables
24
Cannot use keywords course name _ class
Case-sensitive name,Name —
25
snake case _ student name _ total marks _ user email _
✎ Wrong example:
✎ Correct example:
This prints the list of Python keywords. To check whether a word is a keyword:
26
Output: True
False
The print() function is used to display output onthe screen. Basic Print
27
Output: Name: Arjun Age: 20 Printing Multiple Values
▶ Output:
Hello
Python
Using end:
29
Output:
A-B-C
✎ Example:
Important Point
Example output: Enter your age: 21 21 <class 'str'> Even though the user entered 21 , Python stores itas
"21".
30
Example output: Enter your age: 21 Your age is: 21 <class 'int'> Taking Float Input
To convert input into decimal number, use float().
Example output: Enter product price: 99.50 Price is: 99.5 <class 'float'> Example: Add Two Numbers
Example output: Enter first number: 10 Enter second number: 20 1020 Here, Python joins the two
strings. It does not performmathematical addition because both values are strings. Correct version:
31
Output: 30
Start
| v Take input / define data
| v Process data
| v Display output
| v End Simple structure:
32
Example output: Enter student name: Ravi Enter math marks: 80 Enter science marks: 90 Enter English
marks: 85 Student Name: Ravi Total Marks: 255 Average Marks: 85.0
Syntax errors happen when Python cannot understand the code because syntax rules are broken.
⚠ Wrong:
2. Missing Colon
⚠ Wrong:
PYTHON CODE
age = 20
if age >= 18
33
print("Eligible")
Correct:
PYTHON CODE
age = 20
if age >= 18:
print("Eligible")
A colon: is required after statements like: if, else,elif, for, while, def, class, try, except, finally
3. Wrong Indentation
⚠ Wrong:
PYTHON CODE
if True: print("Hello")
Correct:
⚠ Wrong:
Correct:
⚠ Wrong:
PYTHON CODE
print(name) name = "Aman"
Error: NameError: name 'name' is not defined Correct:
34
6. Missing Quotes Around String
⚠ Wrong:
PYTHON CODE
name = "Aman"
7. Mismatched Quotes
⚠ Wrong:
Correct:
Also correct:
⚠ Wrong:
Correct:
Code:
⚠ Wrong:
35
PYTHON CODE print("Hello Python"
Correct:
⚠ Wrong:
Correct:
36
4 Data Types in Python
age 21 Integer
Example:
37
Output: <class 'int'>
This means x is storing an integer value.
4.1 Numbers
Numbers are used to store numeric values. Python mainly has three number types:
4.1.1 int
int means integer . Integers are whole numbers. Theydo not have decimal points.
Examples:
38
Output: 21 95 -5 0
All these values are integers.
Examples of int
4.1.2 float
float means floating-point number . Float values containdecimal points.
39
Output: 99.5 5.8 -2.5 85.75
Checking type:
Examples of float
40
★ Important point:
Output: 99.5
This does not mean the value is wrong. Python simply removes the unnecessary zero at the end.
4.1.3 complex
complex numbers are numbers with two parts:
Real part + Imaginary part
In mathematics, complex numbers are usually written like this:
3 + 4i
But in Python, we use j instead of i.
Python complex number:
41
Output: (3+4j) <class 'complex'> Here: 3 = real part and 4j = imaginary part
✎ More examples:
42
Output: (2+5j)
(10+0j) (-3+7j) You can access real and imaginary parts like this
Output: 3.0 4.0 Important point: Python uses j for complex numbers, not i. Wrong:
Correct:
4.2 Strings
A string is a sequence of characters. Characters can be: Letters, Numbers, Symbols, Spaces
Examples:
43
Output: <class 'str'>
Output: Aman
44
Using Single Quotes
45
▶ Output:
Hello
Welcome to Python
Empty String
Output:
<class 'str'>
There is no visible text in the first output because the string is empty.
Indexing means accessing a single character from a string. Every character in a string has a position
number. This position number is called an index.
◆ Index diagram:
46
Code:
✎ Example:
47
Output: Phn
Negative Indexing
✎ Example:
Output: n o P
★ Important:
48
Index Error
If you try to access an index that does not exist, Python gives an error.
✎ Example:
PYTHON CODE
word = "Python"
print(word[0:2])
▶ Output:
Py
Explanation:
49
✎ More examples: ✎ Example:
PYTHON CODE
word = "Python"
print(word[0:4])
print(word[1:4])
print(word[2:6])
Output: Pyth yth thon Leaving Start Empty
If start is empty, Python starts from the beginning.
▶ Output:
Pyt
Meaning:
Start from beginning
Stop before index 3 Leaving End Empty
If end is empty, Python goes till the end.
50
Output: thon
Meaning: Start from index 2 and Go till the end Full Slice
Output: Python
This returns the full string. Slicing with Negative Index
Output: hon
Syntax:
✎ Example:
51
Output: Pto Explanation: Start at index 0, Go before index 6, Pick every 2nd character
Output: nohtyP Explanation: [::-1] means read the string from right to left 4.2.4 String Immutability
Strings in Python are immutable. Immutable means: Once created, it cannot be changed directly. name
= "Ravi" Index diagram:
52
Error: TypeError: 'str' object does not support item assignment Why? Because strings cannot be
changed character by character.
Correct Way
So this is allowed: name = "Ravi" name = "Kavi" But this is not allowed: name[0] = "K" Because
changing one character inside the same string is not possible.
4.3 Boolean
53
Output: True False
Checking type:
◆ Diagram:
4.3.1 True
54
▶ Output:
True
True
True
Important: True must start with capital T.
Correct: is_active = True
Wrong: is_active = true
Python will not understand true because Python uses True.
4.3.2 False
False represents no, incorrect, inactive, unavailable, or disabled.
55
Output: False False False Important: False must start with capital F. Correct: is_active = False
Wrong: is_active = false Python uses False , not false.
None means no value or empty value . It is used when a variable exists, but it does not currently store
any actual value.
Output:None
<class 'NoneType'>
● None is not 0. None is not an empty string.
Value Meaning
0 A number
None No value
56
Output:
0
False
None
There is a blank line after 0 because name is an empty string.
Diagram:
✎ Example:
57
Output: None
▶ Output:
None
Aman
Important: None must start with capital N.
Correct:
Wrong:
The type() function is used to check the data typeof a value or variable.
Syntax:
58
✎ Example:
PYTHON CODE
age = 21 print(type(age))
Output: <class 'int'>
Output: <class 'int'> <class 'float'> <class 'str'> <class 'bool'> <class 'NoneType'> <class 'complex'>
59
✎ Example:
▶ Output:
100
<class 'str'>
Even though it looks like a number, it is inside quotes, so it is a string.
✎ Example:
Type conversion means changing one data type into another. Example: String "100" ---> Integer 100
Integer 10 ---> Float 10.0 Number 50 ---> String "50"
Python provides built-in functions for type conversion.
int() Integer
60
float() Float
str() String
bool() Boolean
Output: 100 <class 'int'> Before conversion: x = "100" type is str After conversion: y = 100 type is int
This works:
PYTHON CODE
number = int("50") print(number)
Output: 50
This does not work:
PYTHON CODE number = int("hello") print(number)
Error: ValueError: invalid literal for int() Why? Because "hello" is not a valid number. This also does not
work:
PYTHON CODE number = int("10.5") print(number)
61
Error: ValueError: invalid literal for int() Why? Because "10.5" is a decimal number written as a string. It
cannot be converted directly into int.
Output: 25.5
<class 'float'> Integer to float:
Output: 10.0
<class 'float'> String integer to float:
62
Output: 100.0 <class 'float'> Invalid conversion:
Error: ValueError: could not convert string to float 4.6.3 Converting to str
str() converts a value into a string. Example:
Output:21
<class 'str'>
63
Checking types:
PYTHON CODE
price = 99.5
converted_price = str(price)
print(type(price))
print(type(converted_price))
▶ Output:
<class 'float'>
<class 'str'>
★ Important:
▶ Output:
<class 'int'>
<class 'str'>
Both look similar when printed, but their data types are different.
▶ Output:
True
False
True
False
We will study this more deeply in Truthy and FalsyValues in the Control Flow section.
✎ Example:
Output:
65
(10+0j)
<class 'complex'>
String to complex:
▶ Output:
This is a very important concept in Python. First understand these two words:
Mutable = Can be changed after creation
Immutable = Cannot be changed after creation
Immutable data types cannot be changed directly after they are created. Examples of immutable data
types:
● int ● float ● complex ● str ● bool ● NoneType
66
Example with string:
PYTHON CODE name = "Ravi" name[0] = "K"
Error: TypeError: 'str' object does not support item assignment Because string is immutable. Correct
idea:
PYTHON CODE name = "Ravi"
name = "Kavi"
print(name)
Output: Kavi
Here, Python does not change "Ravi" directly. It creates a new string "Kavi" and makes name refer to
that new string.
Output: 21
Mutable data types can be changed after creation. Some mutable data types in Python are:
67
● list ● dictionary ● set
These will be studied in detail later in the DataStructures [Link] now, only remember:
1. Mutable objects can be modified. 2. Immutable objects cannot be modified directly.
int Immutable
float Immutable
complex Immutable
str Immutable
bool Immutable
NoneType Immutable
list Mutable
dict Mutable
set Mutable
A variable is like a name tag. It points to a value. Example: x = 10 Means x -----> 10 Now: x = 20
Means x -----> 20 The name x now points to 20 . It does not mean 10 changed into 20. This idea is
very useful for understanding mutable and immutable data later.
Topic Meaning
68
String immutability Strings cannot be changed directly
bool StoresTrueorFalse
5 Operators in Python
Operators are special symbols or words used to perform operations on values and variables.
Simple meaning:
69
Python operators are mainly divided into these types:
Operators
│
+ Addition 10 + 5
- Subtraction 10 - 5
* Multiplication 10 * 5
/ Division 10 / 5
// Floor division 10 // 3
70
% Modulus 10 % 3
** Exponent / Power 2 ** 3
Addition +
Subtraction -
Multiplication *
Division /
The / operator divides one number by another. Divisionusing / always gives a float result.
PYTHON CODE
a = 10 b = 5 result = a / b print(result) print(type(result))
Output: 2.0 <class 'float'> Even though 10 / 5 is mathematically 2 , Python gives 2.0. That means the
result is a float.
Floor Division //
71
The% operator gives the remainder after division. Example:
PYTHON CODE
a = 10 b = 3 result = a % b print(result)
Output:1 Explanation: 10 divided by 3 => 3 goes into 10 three times: 3 × 3 = 9 Remainder: 10 - 9 = 1
Exponent / Power **
Comparison operators are used to compare two values. The result of a comparison is always a Boolean
value:
● True
● False
Example:
print(10 > 5)
Output: True
Because 10 is greater than 5.
== Equal to 10 == 10
!= Not equal to 10 != 5
72
Equal To ==
The > operator checks whether the left value is greater than the right value.
PYTHON CODE
print(10 > 5)
print(5 > 10)
Output:
True
False Less Than <
The < operator checks whether the left value is less than the right value.
PYTHON CODE
print(5 < 10)
print(10 < 5)
Output:
True
False
The >= operator checks whether the left value is greaterthan or equal to the right value.
73
PYTHON CODE
print(10 >= 5)
print(10 >= 10)
print(5 >= 10)
Output:
True
True
False
Explanation:
10 >= 5 True because 10 is greater than 5
10 >= 10 True because 10 is equal to 10
5 >= 10 False
The <= operator checks whether the left value is less than or equal to the right value.
PYTHON CODE
print(5 <= 10)
print(10 <= 10)
print(20 <= 10)
Output:
True
True
False
Explanation:
5 <= 10 True because 5 is less than 10
10 <= 10 True because 10 is equal to 10
20 <= 10 False
PYTHON CODE
a = 15
b = 20
print(a == b)
print(a != b)
print(a > b)
74
print(a < b)
print(a >= b)
print(a <= b)
Output:
False
True
False
True
False
True
● or
● not
These operators work with True and False. List of Logical Operators
Operator Meaning
and Operator
The and operator gives True only when both valuesare True.
PYTHON CODE
print(True and True)
print(True and False)
print(False and True)
print(False and False)
Output:
True
75
False
False
False
Truth table:
or Operator
▶ Output:
True
True
True
False
Truth table:
76
True True True
not Operator
▶ Output:
False
True
Simple meaning:
✎ Example:
PYTHON CODE
is_logged_in = True
print(not is_logged_in)
Output: False
Comparison operators return Boolean values. So they can be used with logical operators.
✎ Example:
77
PYTHON CODE
age = 20
marks = 85
print(age > 18 and marks > 80)
Output:
True
Explanation: age > 18 True
marks > 80 True
True and True = True
✎ Example:
PYTHON CODE x = 10
print(x)
Output: 10
Here, 10 is assigned to x.
= x = 10 x = 10
+= x += 5 x=x+5
-= x -= 5 x=x-5
*= x *= 5 x=x*5
/= x /= 5 x=x/5
//= x //= 5 x = x // 5
%= x %= 5 x=x%5
**= x **= 5 x = x ** 5
78
Basic Assignment =
PYTHON CODE x = 10
print(x)
Output: 10
PYTHON CODE
x = 10
x += 5
print(x)
Output: 15
Explanation:
x += 5
Same as:
x=x+5
PYTHON CODE
x = 10
x -= 3
print(x)
Output: 7
Explanation: x -= 3
Same as: x = x - 3
PYTHON CODE x = 10
x *= 2
print(x)
Output:20
Explanation: x *= 2
Same as: x = x * 2
PYTHON CODE x = 10
x /= 2
79
print(x)
Output: 5.0
Important: /= gives float result because / gives float result.
PYTHON CODE x = 10
x //= 3
print(x)
Output: 3
Explanation:x //= 3
Same as:x = x // 3
PYTHON CODE x = 10
x %= 3
print(x)
Output: 1
Explanation: x %= 3
Same as: x = x % 3
PYTHON CODE
x=2
x **= 3
print(x)
Output:8
Explanation: x **= 3
Same as: x = x ** 3
Membership operators are used to check whether a value exists inside another value.
Python has two membership operators:
1. in 2. not in
For now, we will use membership operators with strings because strings are already covered.
80
in Operator
▶ Output:
True
True
False
Explanation:
✎ Example:
PYTHON CODE
ext = "Python"
print("Java" not in text)
print("Py" not in text)
▶ Output:
True
False
Membership Is Case-Sensitive
81
print("P" in text)
print("p" in text)
Output:
True
False
Explanation:
"P" and "p" are different in Python.
Identity operators are used to check whether two variables refer to the same object in memory.
Python has two identity operators:
1. is 2. is not
Important:
== checks value
is checks identity/memory object
is Operator
The is operator checks whether two variables point to the same object.
Example:
PYTHON CODE
a = None
b = None
print(a is b)
Output: True
Explanation:
a refers to None
b refers to None
Both refer to the same None object.
is not Operator
The is not operator checks whether two variables donot point to the same object.
Example:
PYTHON CODE
a = None
82
b = 10
print(a is not b)
▶ Output:
True
Explanation:
a refers to None
b refers to 10
They are not the same object.
▶ Possible output:
True
True
For some simple values, Python may reuse the same object internally.
But beginners should remember this rule: Use == for value comparison. Use is mainly with None.
✎ Best example:
Operator Name
` `
^ Bitwise XOR
~ Bitwise NOT
Example:
PYTHON CODE
a=5
b=3
print(a & b)
84
Output: 1
Example:
Output: 7
85
Explanation:
Bitwise XOR ^
Example:
PYTHON CODE a = 5 b = 3 print(a ^ b)
Output: 6
Explanation:
86
Bitwise NOT ~
Example: x = 5
PYTHON CODE print(~x)
Output: -6
Explanation:
~5 = -(5 + 1)
~5 = -6
87
Simple meaning:
x << n means x multiplied by 2 power n
Example:
PYTHON CODE
x=5
print(x << 1)
Output: 10
Explanation:
5 << 1
5 × 2 = 10
Binary view:
5 in binary = 101
After left shift by 1:
1010
1010 in decimal = 10
88
5.8 Operator Precedence
Using parentheses:
89
Common Operator Precedence Table
1 () Parentheses
2 ** Power
8 ^ Bitwise XOR
9 ` `
10 ==,!=,>,<,>=,<= Comparisons
13 or Logical OR
Without parentheses:
90
print(result)
Output: 18
6 String Operations
Strings can be created using single quotes, double quotes, or triple quotes.
PYTHON CODE
s1 = "Hello"
s2 = 'Hello'
s3 = """Hello Python"""
All three are valid.
Single quotes and double quotes are commonly used for one-line strings. Triple quotes are used for
multi-line strings.
PYTHON CODE
message = """Python is simple.
Python is powerful.
Python is widely used."""
Indexing means accessing one character from a string. Python starts counting from 0.
✎ Example:
PYTHON CODE
word = "Python"
print(word[0])
print(word[3])
Output:
91
P
h
For negative indexing, counting starts from the end.
✎ Example:
PYTHON CODE
print(word[-1])
print(word[-2])
Output: n
o
◆ Index diagram:
Important rule: the start index is included , and the end index is excluded.
✎ Example:
92
Pyth
You can also use step values:
PYTHON CODE print(word[0:6:2])
Output: Pto
To reverse a string:
93
Replaces one part of a string with another.
PYTHON CODE
text = "I like Java"
print([Link]("Java", "Python"))
Output:
I like Python split()
PYTHON CODE
text = "Python"
print([Link]("Py"))
print([Link]("on"))
▶ Output:
True
94
True
These methods are very useful in text checking and validation.
● format()
● old% formatting
6.5.1 f-strings
▶ Output:
95
You can also use position numbers:
print("My name is {0} and I am {1} years old.".format(name, age))
This is useful when you want control over the order of values.
This style is still found in older code, but f-strings are preferred in modern Python.
\n New line
\t Tab space
\\ Backslash
96
\' Single quote
Escape
Meaning Example Output
Character
97
Output: HiHiHi
replace(old, Replaces one substring with "I like "I like Python"
new) another Java".replace("Java","Python")
98
split() Splits a string into a list "a,b,c".split(",") ['a', 'b', 'c']
center(width) Centers the string within the "Python".center(12) " Python "
specified width
7 Control Flow
7.1 if Statement
Syntax
The if statement is used when we want to run somecode only when a condition is True. If the condition
is True , Python executes the indented block. If the condition is False , Python skips the indentedblock.
99
Flow Chart
Example
PYTHON CODE age = 20 if age >= 18:
print("Eligible to vote")
Output: Eligible to vote
✎ example:
100
7.2 if-else Statement
Syntax
Explanation
The if-else statement is used when we want to run one block if the condition is True and another block
if the condition is False.
Only one block runs.
If the condition is True , the if block runs.
If the condition is False , the else block runs.
Flow Chart
101
Example
PYTHON CODE
age = 16 if age >= 18:
print("Eligible to vote") else:
print("Not eligible to vote")
Output: Not eligible to vote
102
7.3 elif Statement
Syntax
103
Explanation
104
7.4 Nested Conditions
Syntax
With else:
Nested condition means writing one condition inside another condition. The inner condition is checked
only when the outer condition is True . Thisis useful when one decision depends on another decision.
105
Flow Chart
Example
106
Output: Entry allowed
Syntax
Common usage:
The ternary operator is a short way to write a simple if-else statement in one line. It is useful when we
need to choose between two values. Use it only for simple conditions. For complex logic, normal if-else
is better.
107
Flow Chart
Normal if-else:
108
7.6 match-case
Syntax
Explanation
match-case is used to compare one value with multiplepossible cases. It is similar to checking many
fixed options.
The _ case works like a default case. It runs whenno other case matches. match-case was introduced in
Python 3.10.
109
Flow Chart
Example
110
Output: Starting program
PYTHON CODE
day = 3 match day:
case 1:
print("Monday") case 2:
print("Tuesday") case 3:
print("Wednesday") case _:
print("Invalid day")
Output: Wednesday
Syntax
111
Explanation
In Python, conditions do not always need direct comparison like: if age >= 18: Python can also treat
values as True or False . Theseare called truthy and falsy values. A truthy value behaves like True. A
falsy value behaveslike False .
Value Meaning
0 Zero number
None No value
Value Meaning
10 Non-zero number
-5 Non-zero number
112
Flow Chart
▶ Output:
Example 3: Number
PYTHON CODE
amount = 0 if amount:
print("Amount available") else:
print("Amount is zero")
Output: Amount is zero
113
8 Loops and Iteration
Loops are used when we want to run the same code multiple times.
Q: Print numbers from 1 to 5
Without a loop, we write many print() [Link] loop, we write the logic once and Python repeats
it.
Syntax
Explanation
1. A for loop is used to repeat code over a sequence. 2. A sequence can be a string, range, list, tuple,
etc. 3. In each round, Python takes one value from the sequence. 4. The loop stops automatically when
all values are finished. Flow Chart
114
Example 1: Loop through a string
115
Output: 1 2 3 4 5 8.2 while Loop
Syntax
Explanation
1. A while loop runs as long as the condition is True. 2. Before every round, Python checks the
condition. 3. If the condition is True , the loop block runs. 4. If the condition becomes False , the loop
stops.
Flow Chart
116
Output: 1 2 3 4 5 for Loop vs while Loop
Main use Used to loop over a sequence Used to repeat while a condition isTrue
8.3 break
❯ Syntax:
Explanation
1. break is used to stop a loop immediately. 2. When Python sees break , it exits the loop. 3. Code
after the loop continues normally.
Flow Chart:
117
Example 1: Stop loop when number is 4
▶ Output:
1
2
3
Explanation:
8.4 continue
Syntax
118
Explanation
▶ Output:
1245
Explanation:
119
8.5 pass
Syntax
1. pass means “do nothing”. It is used when Python needsa statement, but we do not
want to write logic yet. It does not stop or skip the loop like break or continue. Flow Chart
120
Statement Meaning Effect on Loop Common Use
break Stop the loop Exits the loop completely Stop when required value is found
continue Skip current round Moves to next iteration Skip unwanted values
Syntax
Explanation
1. A loop can have an else block. The else block runswhen the loop finishes normally. 2. If the loop
stops because of break , the else blockdoes not run.
Flow Chart
121
Example 1: Loop finishes normally
122
8.7 Nested Loops
Syntax
Explanation
1. Nested loop means one loop inside another loop. 2. The outer loop runs first. 3. For every one round
of the outer loop, the inner loop runs completely. 4. Nested loops are useful for patterns, tables, rows
and columns. Flow Chart
▶ Output:
11
12
13
21
22
23
PYTHON CODE
for row in range(1, 4):
print("*" * row)
▶ Output:
**
***
8.8 range()
Syntax
Explanation
1. range() creates a sequence of numbers. 2. It is commonly used with for loops. 3. The stop value is
excluded. 4. step controls the gap between numbers. Flow Chart
124
Example 1: range(stop)
▶ Output:
0
1
2
3
4
Explanation:
125
Output: 2 4 6 8 10 range() Forms
8.9 enumerate()
Syntax
Explanation
126
Example 1: Enumerate a string
PYTHON CODE
word = "Python"
for index, letter in enumerate(word):
print(index, letter)
▶ Output:
0P
1y
2t
3h
4o
5 n Example 2: Start index from 1
PYTHON CODE
word = "Python"
for index, letter in enumerate(word, start=1):
print(index, letter)
▶ Output:
127
1P
2y
3t
4h
5o
6n enumerate() vs Normal Loop
8.10 zip()
Syntax
Explanation
128
Example 1: Zip two strings
PYTHON CODE
letters = "ABC"
numbers = "123"
for letter, number in zip(letters, numbers):
print(letter, number)
▶ Output:
A1
B2
C3
129
▶ Output:
A1
B2
Explanation:
Syntax
Explanation
1. An iterator is an object that gives values one by one. 2. iter() creates an iterator from an iterable value.
3. next() gets the next value from the iterator. 4. Loops internally use this idea to get values one by one.
Term Meaning
Flow Chart
130
Example 1: Using iter() and next()
131
Output: A B C Example 2: How for loop thinks internally
This loop:
PYTHON CODE
for letter in "ABC":
print(letter)
▶ Output:
A
B
C Internally, the idea is similar to:
PYTHON CODE
iterator = iter("ABC")
print(next(iterator))
print(next(iterator))
print(next(iterator))
Output: A B C Iterable vs Iterator
132
iter() Creates an iterator iter("ABC")
Example 1: Iterable
Output: A
B C Here, "ABC" is iterable because we can loop over it. Example 2: Iterator
Output: A
BC
133
8.12 StopIteration
When an iterator has no more values, Python raises StopIteration . Example 1: Iterator
ends
▶ Output:
A
B
An infinite loop is a loop that never stops. This usually happens when the condition in a while loop never
becomes False. Example 1: Infinite loop
Problem:
number starts as 1 => condition is number <= 5 =>number is never increased=> condition always stays
True . loop never stops
134
Correct version:
Output: 12345
Syntax
Explanation
1. Lists are written using square brackets []. 2. List items are separated by commas. 3. Lists are ordered,
so every item has an index. 4. Lists are mutable, meaning we can change them after creation. 5. Lists
can store duplicate values. 6. Lists can store different data types together.
Example 1
Allows duplicates Same value can appear multiple times [10, 10, 20]
Mixed data allowed Can store different data types ["Aman", 20, True]
Flow Chart
Syntax
1. A list can store numbers, strings, Boolean values, or mixed values. 2. An empty list can also be
created. 3. Lists are useful when many related values need to be stored together.
136
Example 1
Output: [10, 20, 30, 40] ['Aman', 'Riya', 'Kabir'] ['Python', 100, 99.5, True] []
Type Example
137
9.1.2 Accessing Values
Syntax
Explanation
1. List items are accessed using index numbers. 2. Python indexing starts from 0. 3. Positive indexing
starts from the left. 4. Negative indexing starts from the right.
Example 1
Indexing Table
138
students[-2] Second last item "Kabir"
Syntax
139
9.1.4 List Methods
Example 1
140
sorted() Returns sorted copy sorted(numbers)
9.1.5 Slicing
Syntax
list_name[start:end:step] Explanation
1. Slicing is used to get a part of a list.
2. The start index is included.
3. The end index is excluded.
4. Step controls the gap between selected items. Example 1
PYTHON CODE
numbers = [10, 20, 30, 40, 50, 60]
print(numbers[1:4])
print(numbers[:3])
print(numbers[3:])
print(numbers[::2])
print(numbers[::-1])
Output: [20, 30, 40] [10, 20, 30] [40, 50, 60] [10, 30, 50] [60, 50, 40, 30, 20, 10]
Slicing Table
Syntax
With condition:
141
1. List comprehension is a short way to create a new list. 2. It is commonly used when each item needs
to be processed. 3. It can also filter values using if. 4. It makes code shorter and cleaner.
Example 1
Syntax
Explanation
1. A nested list means a list inside another list. 2. It is useful for matrix-like data, rows and columns, or
grouped values. 3. To access nested list values, use multiple indexes.
Example 1
PYTHON CODE
matrix = [
[1, 2, 3], [4, 5, 6], [7, 8, 9]] print(matrix[0]) print(matrix[1][2])
Output: [1, 2, 3]
6
142
Index Diagram
Sorting means arranging values in order. Reversing means changing the order from last to first.
143
Sort descending [Link](reverse=True) Yes Large to small
Example 1
PYTHON CODE
numbers = [40, 10, 30, 20]
[Link]()
print(numbers)
[Link](reverse=True)
print(numbers)
[Link]()
print(numbers)
Output: [10, 20, 30, 40] [40, 30, 20, 10] [10, 20, 30, 40]
sort() vs sorted()
Original list Changes original list Does not change original list
Example 2
PYTHON CODE
numbers = [30, 10, 20]
new_numbers = sorted(numbers)
print(numbers)
print(new_numbers)
Output: [30, 10, 20] [10, 20, 30]
144
9.1.9 Copying Lists
Syntax
new_list = old_list.copy()
Other ways:
new_list = old_list[:]
new_list = list(old_list)
Explanation
1. Copying means creating another list with the same values. 2. Direct assignment does not create a real
copy. 3. Direct assignment makes two variables point to the same list. 4. To create a separate list, use
copy() , slicing, or list().
Direct Assignment
PYTHON CODE
list1 = [10, 20, 30]
list2 = list1
[Link](40)
print(list1)
print(list2)
Output:
[10, 20, 30, 40]
[10, 20, 30, 40]
Explanation:
1. list2 = list1 does not create a new list. 2. Both variables refer to the same list. 3. So changing list2 also
affects list1.
145
▶ Output:
Explanation
This concept matters when a list contains another list. There are two types of copy:
● Shallow copy ● Deep copy
Shallow Copy
A shallow copy creates a new outer list, but nested lists inside are still shared.
146
Example 1: Shallow Copy
PYTHON CODE
list1 = [[10, 20], [30, 40]]
list2 = [Link]()
list2[0][0] = 99
print(list1)
print(list2)
Output:
[[99, 20], [30, 40]]
[[99, 20], [30, 40]]
1. [Link]() creates a new outer list. 2. But the inner lists are still shared. 3. So changing an inner list
affects both lists.
Deep Copy
A deep copy creates a completely separate copy of both the outer list and inner lists.
147
list1 = [[10, 20], [30, 40]]
list2 = [Link](list1)
list2[0][0] = 99
print(list1)
print(list2)
Output: [[10, 20], [30, 40]]
[[99, 20], [30, 40]] Explanation:
1. [Link]() creates a fully independent copy. 2. Inner lists are also copied separately. 3.
Changing list2 does not affect list1.
148
Reverse list [Link]() Reverses original list
Syntax
149
Example 1
Allows duplicates Same value can appear more than once (10, 10, 20)
Mixed data allowed Can store different data types ("Aman", 20, True)
150
Flow Chart
Syntax
Example 1
151
▶ Output:
(10, 20, 30) ('Aman', 'Riya', 'Kabir') ('Python', 100, 99.5, True)()
Type Example
Syntax
tuple_name = (value,)
Explanation
1. A single-item tuple must contain a comma. 2. Without the comma, Python does not treat it as a tuple.
3. Parentheses alone are not enough.
Example 1
PYTHON CODE
a = ("Python")
b = ("Python",)
print(type(a))
print(type(b))
Output: <class 'str'> <class 'tuple'>
Syntax
tuple_name[index]
152
1. Tuple values are accessed using index numbers. 2. Python indexing starts from 0. 3. Positive indexing
starts from the left. 4. Negative indexing starts from the right.
Index Diagram
Example 1
PYTHON CODE students = ("Aman", "Riya", "Kabir", "Neha")
print(students[0])
print(students[2])
print(students[-1])
Output: Aman Kabir Neha
Syntax
tuple_name[start:end:step] Explanation
1. Slicing is used to get a part of a tuple. 2. The start index is included. 3. The end index is excluded. 4.
Step controls the gap between selected values. 5. Slicing returns a new tuple.
153
Example 1
▶ Output:
(20, 30, 40) (10, 20, 30) (40, 50, 60) (10, 30, 50) (60, 50, 40, 30, 20, 10)
Slicing Table
Syntax
tuple_name[index] = new_value
This syntax is not allowed for tuples.
154
Explanation
1. Tuples are immutable. 2. Once a tuple is created, its values cannot be changed directly. 3. We cannot
update, add, or remove tuple items directly. 4. If changes are needed, use a list or create a new tuple.
Example 1
PYTHON CODE
numbers = (10, 20, 30)
numbers[1] = 25
Output: TypeError: 'tuple' object does not supportitem assignment Correct Way
Create a new tuple:
PYTHON CODE
numbers = (10, 20, 30)
numbers = (10, 25, 30)
print(numbers)
Output: (10, 25, 30) Memory Idea
Before: numbers ----> (10, 20, 30) After: numbers ----> (10, 25, 30) The old tuple is not
changed. The variable starts pointing to a new tuple.
Syntax
Example 1
Explanation Table
155
data[0][1] = 99 Allowed
count() Counts how many times a value appears [Link](10) Count of10
Syntax
Explanation
1. Tuple packing means storing multiple values together in a tuple. 2. Python automatically packs
comma-separated values into a tuple. 3. Parentheses are optional, but recommended for readability.
156
Example 1
Syntax
Explanation
1. Tuple unpacking means taking values from a tuple and storing them in separate
variables. 2. The number of variables should match the number of tuple values. 3. Unpacking makes
code cleaner and readable.
157
Example 1
Important Point
Syntax
Example 1
Syntax
1. A named tuple is a tuple with named fields. 2. Normal tuple values are accessed by index. 3. Named
tuple values can be accessed by name. 4. This makes code more readable. 5. Named tuples are
immutable like normal tuples.
Example 1
Output: Aman
21 Python
159
Normal Tuple vs Named Tuple
student[0] [Link]
Immutable Immutable
Best for Data that may change Data that should not change
Best for Data that may change Data that should not change Important Tuple Operations Table
160
Repeat a*2 Repeats tuple
1. A dictionary stores data using keys and values. 2. Each key is connected to one value. 3. Keys are
used to access values. 4. Dictionaries are mutable, so values can be changed. 5. Dictionary keys must
be unique. 6. Dictionaries are written using curly braces {}.
161
Flow Chart
Example 1
PYTHON CODE student = {
"name": "Aman",
"age": 21,
"course": "Python"
}
print(student)
Output: {'name': 'Aman', 'age': 21, 'course': 'Python'}
162
Dictionary Structure
Unique keys Duplicate keys are not allowed Last value replaces old value
Mixed values allowed Values can be any data type string, int, list, tuple, dict
163
9.3.1 Creating Dictionaries Syntax
Explanation
1. Dictionaries are created using {}. 2. Keys and values are separated using a colon:. 3. Each pair is
separated using a comma. 4. Keys are usually strings, but numbers and tuples can also be used. 5.
Values can be any data type.
PYTHON CODE student = {
"name": "Rahul",
"age": 20,
"marks": 85.5,
"is_passed": True
}
print(student)
Output: {'name': 'Rahul', 'age': 20, 'marks': 85.5,'is_passed': True}
Type Example
164
9.3.2 Dictionary Keys and Values
Syntax
Explanation
1. A key is used to identify a value. 2. A value is the data stored against the key. 3. Keys must be unique.
4. Values can be duplicate. 5. Keys should be immutable types like string, number, or tuple.
Output: Aman
165
Duplicate keys Not useful Last value is kept
Syntax
dictionary_name[key]
Explanation
1. Dictionary values are accessed using keys. 2. Unlike lists and tuples, dictionaries are not accessed
mainly by index. 3. If the key exists, Python returns its value. 4. If the key does not exist, Python gives
KeyError.
166
Example 1
167
Output: Aman 21
Accessing Table
KeyError Example
168
Syntax
dictionary_name[key] = new_value
1. Dictionaries are mutable. 2. Existing values can be updated using keys. 3. If the key already exists, its
value is updated. 4. If the key does not exist, a new key-value pair is added.
PYTHON CODE student = {
"name": "Aman",
"age": 21
}
student["age"] = 22
student["course"] = "Python"
print(student)
Output: {'name': 'Aman', 'age': 22, 'course': 'Python'}
Dictionary methods are built-in operations used to access, update, remove, copy, and manage
dictionary data.
Assume this dictionary:
PYTHON CODE
student = {
"name": "Aman",
"age": 21,
"course": "Python"
}
169
pop() Removes key and [Link]("age") Returns21
returns value
170
9.3.6 get() Method
Syntax
Explanation
1. get() is used to access dictionary values safely. 2. If the key exists, it returns the value. 3. If the key
does not exist, it returns None by default. 4. We can also provide our own default value. 5. get() avoids
KeyError.
Flow Chart
Example 1
PYTHON CODE
student = {
"name": "Aman",
"age": 21
}
print([Link]("name"))
171
print([Link]("marks"))
print([Link]("marks", "Not available"))
Output: Aman None Not available
[] vs get() Table
Syntax
Explanation
1. pop(key) removes a specific key and returns its value. 2. popitem() removes the last inserted key-
value pair. 3. del removes a specific key. 4. clear() removes all items.
Example 1
172
Output: {'name': 'Aman', 'course': 'Python'}
Syntax
Explanation
1. A dictionary can be looped through using for. 2. By default, looping over a dictionary gives keys. 3.
Use values() to loop through values. 4. Use items() to loop through both keys and values.
173
Example 1
PYTHON CODE
student = {
"name": "Aman",
"age": 21,
"course": "Python"
}
for key, value in [Link]():
print(key, value)
Output: name Aman age 21 course Python
Syntax
Explanation
1. in checks whether a key exists in the dictionary. 2. It checks keys, not values. 3. It returns True or
False.
174
Example 1
Membership Table
Code Meaning
175
9.3.10 Nested Dictionaries
Syntax
Explanation
176
Example 1
PYTHON CODE students = {
"student1": {
"name": "Aman",
"age": 21
},
"student2": {
"name": "Riya",
"age": 20
}
}
print(students["student1"]["name"])
print(students["student2"]["age"])
Output: Aman 20
177
Updating Nested Dictionary
178
9.3.11 Dictionary Comprehensions
Syntax
With condition:
Explanation
Flow Chart
Take sequence
| v Loop through items
| v Create key-value pair
| v Store in new dictionary
Example 1
PYTHON CODE
numbers = [1, 2, 3, 4]
squares = {number: number * number for number in numbers}
print(squares)
Output:
{1: 1, 2: 4, 3: 9, 4: 16}
PYTHON CODE
numbers = [1, 2, 3, 4, 5, 6]
even_squares = {number: number * number for number in numbers if number % 2 == 0}
print(even_squares)
Output: {2: 4, 4: 16, 6: 36}
Part Meaning
179
numberbefore: Key
PYTHON CODE
student = {
"name": "Aman",
"age": 21
}
extra = {
"course": "Python",
"city": "Delhi"
}
[Link](extra)
print(student)
Output: {'name': 'Aman', 'age': 21, 'course': 'Python', 'city': 'Delhi'}
Example 2: Using |
PYTHON CODE
student = {
"name": "Aman",
"age": 21
}
extra = {
"course": "Python",
"city": "Delhi"
}
result = student | extra
print(result)
180
Output: {'name': 'Aman', 'age': 21, 'course': 'Python', 'city': 'Delhi'}
If both dictionaries have the same key, the second dictionary value wins.
PYTHON CODE
a = {"name": "Aman", "age": 21}
b = {"age": 22, "course": "Python"}
result = a | b
print(result)
Output: {'name': 'Aman', 'age': 22, 'course': 'Python'} 9.3.13 Copying Dictionaries
Syntax
new_dict = old_dict.copy()
Explanation
1. copy() creates a shallow copy of a dictionary. 2. Direct assignment does not create a new dictionary.
3. Direct assignment makes both variables point to the same dictionary.
PYTHON CODE
student1 = {"name": "Aman", "age": 21}
student2 = student1
student2["age"] = 22
print(student1)
print(student2)
Output: {'name': 'Aman', 'age': 22} {'name': 'Aman', 'age': 22}
PYTHON CODE
student1 = {"name": "Aman", "age": 21}
student2 = [Link]()
student2["age"] = 22
print(student1)
print(student2)
▶ Output:
181
{'name': 'Aman', 'age': 22}
Copying Table
Brackets [] {}
182
Get pairs [Link]() Returns key-value pairs
Syntax
Explanation
1. Sets are written using curly braces {}. 2. Set items are separated by commas. 3. Sets store only
unique values. 4. Sets are unordered, so items do not have fixed positions. 5. Sets are mutable, so we
can add or remove items. 6. Set elements must be immutable/hashable values.
Example 1
PYTHON CODE
numbers = {10, 20, 30, 40}
print(numbers)
{40, 10, 20, 30} : The output order may look different because sets are unordered.
Unique values Duplicate values are removed {10, 10, 20}becomes{10, 20}
Mixed data allowed Can store different immutable types {10, "Aman", True}
183
Fast membership check Good for checking existence 10 in numbers
Syntax
Example 1
PYTHON CODE
numbers = {10, 20, 30}
names = {"Aman", "Riya", "Kabir"}
mixed = {"Python", 100, 99.5, True}
empty_set = set()
print(numbers)
print(names)
print(mixed)
print(empty_set)
Output: {10, 20, 30} {'Aman', 'Kabir', 'Riya'} {True, 99.5, 100, 'Python'} set() Order may differ in output.
Type Example
PYTHON CODE
184
a = {}
b = set()
print(type(a))
print(type(b))
Output: <class 'dict'> <class 'set'>
Syntax
Example 1
Syntax
Explanation
1. Set elements must be hashable. 2. Immutable values like numbers, strings, and tuples can be stored
in a set. 3. Mutable values like lists, dictionaries, and sets cannot be stored in a set. 4. This is because
sets internally need stable values to check uniqueness.
Example 1
✎ Invalid example:
185
PYTHON CODE invalid_set = {[1, 2], [3, 4]}
Output: TypeError: unhashable type: 'list'
Syntax
Explanation
1. Sets do not support indexing. 2. Sets do not support slicing. 3. Values can be accessed by looping. 4.
Membership can be checked using in. Example 1
PYTHON CODE
languages = {"Python", "Java", "C++"}
for language in languages:
print(language)
Possible output: Java Python C++ Output order may differ. Invalid Access:
PYTHON CODE languages = {"Python", "Java", "C++"}
print(languages[0])
Output: TypeError: 'set' object is not subscriptable
186
Accessing Table
Indexing No items[0]
Slicing No items[1:3]
Syntax
Explanation
1. Sets are very useful for checking whether a value exists. 2. in returns True if value exists. 3. not in
returns True if value does not exist. 4. Membership checking in sets is usually faster than lists for large
data.
✎ Example:
187
Syntax
Explanation
1. add() adds one item. 2. update() adds multiple items. 3. If an added value already exists, it is not
added again. 4. Sets automatically maintain uniqueness.
Example 1
add() vs update()
✎ Example:
188
PYTHON CODE numbers = {10, 20, 30, 40}
[Link](20)
[Link](50)
print(numbers)
Output: {40, 10, 30}
discard(50) does not give an error even though 50 is missing.
Set operations are used to compare or combine sets. Main set operations:
1. Union 2. Intersection 3. Difference 4. Symmetric difference 5. Subset 6. Superset 7. Disjoint
Assume: a = {1, 2, 3} b = {3, 4, 5} Set Operations Table
189
Example 1
9.4.9 Union
Syntax
Explanation
1. Union combines two sets. 2. It returns all unique values from both sets. 3. Duplicate/common values
appear only once.
Example 1
PYTHON CODE
a = {1, 2, 3}
b = {3, 4, 5}
result = [Link](b)
print(result)
Output: {1, 2, 3, 4, 5}
a = {1, 2, 3} b = {3, 4, 5} Union = all unique values = {1, 2, 3, 4, 5}
9.4.10 Intersection
Syntax
190
9.4.11 Difference
Syntax
1. Difference returns values present in the first set but not in the second set. 2. a - b and b - a can give
different results.
PYTHON CODE a = {1, 2, 3}
b = {3, 4, 5}
print(a - b)
print(b - a)
Output: {1, 2} {4, 5} a - b = values in a but not in b = {1, 2} b - a = values in b but not in a = {4, 5}
set1 ^ set2
set1.symmetric_difference(set2)
1. Symmetric difference returns values that are not common. 2. It removes common values from the
final result.
PYTHON CODE a = {1, 2, 3}
b = {3, 4, 5}
result = a.symmetric_difference(b)
print(result)
Output: {1, 2, 4, 5}
Syntax
191
Comparison Table
Disjoint No common items {1, 2}.isdisjoint({3, 4}) True 9.4.14 Set Methods
symmetric differe _ nce() Items not common [Link] difference(b) _ New set
192
issuperset() Checks superset [Link](b) True/False
` ` Union
- Difference [Link](b)
> Proper superset check a > b 9.4.16 Updating Sets with Operations
Syntax
new_set = old_set.copy()
1. copy() creates a shallow copy of a set. Direct assignmentdoes not create a new set. 2. Direct
assignment makes both variables point to the same set.
193
PYTHON CODE a = {10, 20, 30}
b = [Link]()
[Link](40)
print(a)
print(b)
Output: {10, 20, 30}
{40, 10, 20, 30} Copying Table
Invalid Operation
Mutable Yes No
194
Remove items Allowed Not allowed
Syntax
195
1. Set comprehension is a short way to create a set. 2. It is similar to list comprehension. 3. It
automatically keeps only unique values. 4. It can include conditions.
Example 1
Brackets [] {}
Syntax
set(iterable)
list(set_name)
tuple(set_name)
1. set() converts an iterable into a set. 2. This is often used to remove duplicates. 3. A set can be
converted back to a list or tuple. 4. Order may change after converting to a set.
Example 1
PYTHON CODE
numbers = [10, 20, 10, 30, 20]
unique_numbers = set(numbers)
print(unique_numbers)
196
print(list(unique_numbers))
Output: {10, 20, 30} [10, 20, 30] Order may differ.
Conversion Table
Brackets [] () {}
Best for Changeable ordered data Fixed ordered data Unique unordered data
197
Remove safely [Link](20) Removes without error
Union `a b`
The collections module provides special data structuresthat are more powerful than normal lists, tuples,
dictionaries, and sets.
198
Syntax
1. collections is a built-in Python module. 2. It gives ready-made advanced data structures. 3. These
structures help solve common problems easily. 4. They are useful for counting, grouping, ordering, fast
queue operations, and
combining dictionaries.
199
Syntax
Explanation
1. Counter counts repeated values. 2. It returns a dictionary-like object. 3. Items become keys. 4. Their
counts become values. 5. It is commonly used for frequency counting.
Flow Chart
Input data
| v Counter checks each item
| v Counts repeated items
| v Returns item-count pairs
Example 1
Example 2
200
Common Counter Methods
9.5.2 defaultdict
defaultdict is a dictionary that gives a default valuewhen a key does not exist.
Syntax
Explanation
1. Normal dictionaries give KeyError if a key does notexist. 2. defaultdict avoids this problem. 3. It
automatically creates a default value for missing keys. 4. Common default types are int, list , and set.
Flow Chart
201
marks = defaultdict(int)
marks["math"] += 10
marks["science"] += 20
print(marks)
Output:defaultdict(<class 'int'>, {'math': 10, 'science':20}) Here, missing keys start with default value
0. Common Default Types
int 0 Counting
9.5.3 OrderedDict
Syntax
1. OrderedDict stores key-value pairs in order. 2. Normal dictionaries also preserve insertion order in
modern Python. 3. OrderedDict is still useful because it has extra order-relatedmethods. 4. It can move
items to the beginning or end. 5. It can remove items from either side.
Example 1
PYTHON CODE from collections import OrderedDict
student = OrderedDict()
student["name"] = "Aman"
student["age"] = 21
student["course"] = "Python"
print(student)
Output: OrderedDict([('name', 'Aman'), ('age', 21),('course', 'Python')])
9.5.4 deque
deque means double-ended queue.
It allows fast adding and removing from both ends.
203
Syntax
List vs deque
204
Remove from beginning Slower Fast
9.5.5 ChainMap
ChainMap combines multiple dictionaries into one view.
Syntax
205
10 Functions in Python
A function is a reusable block of code that performsa specific task. Instead of writing the same code
again and again, we write it once inside a function and call it whenever needed.
Basic idea
Simple flow
Define function
| v Call function
| v Function code runs
| v Result/output is produced 10.1 What is a Function?
Syntax
1. A function groups related code together. 2. A function runs only when it is called. 3. Functions help
avoid repeated code. 4. Functions make code clean, reusable, and easy to understand. 5. Python has
built-in functions and user-defined functions.
Flow Chart
Start
| v Function is defined
| v Function is called
206
| v Function body executes
| v Program continues
PYTHON CODE def greet():
print("Hello, welcome to Python")
greet()
Output: Hello, welcome to Python
Syntax
1. def is used to define a function. 2. The function name comes after def. 3. Parentheses() are required.
4. A colon: marks the start of the function body. 5. The function body must be indented.
Empty Function
207
pass
Syntax
function_name()
1. Calling a function means executing it. 2. A function can be called once or many times. 3. The function
body runs every time the function is called. 4. If a function is defined but never called, its code will not
execute.
Example 1
10.4 Parameters
A parameter is a variable written inside the functiondefinition. It receives values when the function is
called. Syntax
PYTHON CODE def function_name(parameter):
statement
Explanation
1. Parameters make functions flexible. 2. Parameters allow us to send data into a function. 3. A function
can have one or more parameters. 4. Parameters are written inside parentheses during function
definition.
Flow Chart
Example 1
208
print("Hello", name)
greet("Aman")
Output: Hello Aman Here, name is a parameter.
10.5 Arguments
Syntax
function_name(argument)
Explanation
1. Parameter is written in function definition. 2. Argument is passed during function call. 3. Arguments
provide real values to parameters.
Parameter vs Argument
Example 1
Code Role
name Parameter
"Riya" Argument
Syntax
function_name(argument1, argument2)
209
Explanation
1. Python passes arguments in the same order as parameters. 2. The first argument goes to the first
parameter. 3. The second argument goes to the second parameter. 4. Order matters in positional
arguments.
Example 1
Flow Chart
student_info("Aman", 21)
||
vv
name age
Syntax
def function_name():
return value
1. return sends a value back to the place where the function was called. 2. A function can return one
value or multiple values. 3. After return , the function stops executing. 4. If there is no return , Python
returns None automatically.
210
Flow Chart
Example 1
▶ Output:
30
211
10.8 Returning Multiple Values
1. Multiple values can be returned using commas. 2. Python returns them as a tuple. 3. Returned values
can be unpacked into variables. Example 1
PYTHON CODE def calculate(a, b):
total = a + b difference = a - b return total, difference sum_result, diff_result = calculate(20, 10)
print(sum_result) print(diff_result)
Output: 30 10
A default parameter has a predefined value. If no argument is passed, the default value is used.
Syntax
1. Default parameters make arguments optional. 2. If an argument is provided, Python uses the given
value. 3. If no argument is provided, Python uses the default value. 4. Non-default parameters must
come before default parameters.
Example 1
212
greet()
▶ Output:
Hello Aman
Hello Guest Correct and Incorrect Order
def show(name, age=18): Yes Default parameter comes after normal parameter
def show(name="Guest", age): No Non-default parameter cannot come after default parameter
Important Warning: Avoid Mutable Default Values Do not use mutable objects like list or dictionary as
default values. Wrong style:
Output: ['A']
['A', 'B'] The same list is reused between function calls. Better style:
213
Output: ['A']
['B']
1. Keyword arguments use names while calling a function. 2. Order does not matter when keyword
arguments are used. 3. They make function calls more readable. 4. Positional arguments must come
before keyword arguments.
Example 1
214
Age: 21 Course: Python
Positional vs Keyword Arguments
Important Rule
Correct:
Incorrect:
10.11 *args
*args is used when we do not know how many positional arguments will be passed.
Syntax
1. *args collects extra positional arguments. 2. The collected values are stored as a tuple. 3. The name
args is a convention; the * is important. 4. Use *args when the number of arguments is flexible.
Flow Chart
215
Example 1
10.12 **kwargs
**kwargs is used when we do not know how many keywordarguments will be passed.
Syntax
Explanation
1. **kwargs collects extra keyword arguments. 2. The collected values are stored as a dictionary. 3.
Keys are argument names. 4. Values are argument values. 5. The name kwargs is a convention; the ** is
important.
Flow Chart
Example 1
216
course Python
Here, details behaves like a dictionary.
Example 1
Syntax
Explanation
1. Normal parameters come first. 2. Default parameters come after normal parameters. 3. *args comes
after normal/default parameters. 4. **kwargs comes last. 5. This order keeps function calls clear and
valid.
217
3 *args *marks
4 **kwargs **details
Example 1
▶ Output:
Name: Aman Age: 21 Marks: (80, 90, 85) Details: {'course': 'Python', 'city': 'Delhi'}
10.15 Docstrings
A docstring is a string written inside a function to explain what the function does.
Syntax
1. A docstring is written using triple quotes. 2. It is usually written as the first statement inside a
function. 3. It explains the purpose of the function. 4. It helps other programmers understand the
function. 5. It can be viewed using help() or .__doc__.
218
Example 1
Output: 30
Return the sum of two numbers.
Syntax
def function_name():
219
statement
1. Function names should be meaningful. 2. Use snake_case for function names. 3. Function names
should usually describe an action. 4. Avoid using Python keywords as function names. 5. Avoid unclear
names like x(), abc() , or test1().
11 Advanced Functions
Advanced functions help us write more flexible, reusable, and compact code.
Before starting, remember:
In Python, functions are objects. This means:
1. A function can be stored in a variable. 2. A function can be passed as an argument. 3. A function can
be returned from another function. 4. A function can be written inside another function.
Syntax
def function_name():
statement
new_name = function_name
In Python, functions behave like normal objects. We can store a function in a variable and call it using
that variable.
Flow Chart
Create function
| v Assign function to variable
| v Call function using new variable
Example 1
220
11.2 Lambda Functions
A lambda function is a small anonymous function. Anonymousmeans it does not need a normal function
name.
Syntax
Example 1
Normal function:
Output: 25 Example 2
221
Output: 30
Lambda is best for simple logic. For complex logic, use normal def functions.
11.3 map()
Syntax
map(function, iterable)
Explanation
1. map() takes a function and an iterable. 2. It applies the function to each item. 3. In Python 3, map()
returns a map object, which isan iterator. 4. To display all results at once, convert it using list().
Example 1
Example 2
map() Table
Part Meaning
222
numbers Iterable
11.4 filter()
Flow Chart
Iterable values
| v filter() checks condition
| ├── True -> keep item | └── False -> remove item | v Filtered result Example 1
PYTHON CODE numbers = [1, 2, 3, 4, 5, 6] even_numbers = filter(lambda number: number % 2 == 0,
numbers) print(list(even_numbers))
Output: [2, 4, 6] map() vs filter()
11.5 reduce()
reduce() combines all items of an iterable into asingle final value. reduce() is not directly available like
map() and filter() . It must be importedfrom functools.
Syntax
223
Explanation
1. reduce() takes a function and an iterable. 2. It combines values step by step. 3. It returns one final
result. 4. It is useful for cumulative calculations. 5. For simple addition, sum() is usually better.
Example 1
11.6 Recursion
Part Meaning
224
Base case Condition that stops recursion
Example 1: Factorial
Factorial means: 5! = 5 × 4 × 3 × 2 × 1
PYTHON CODE def factorial(number):
if number == 1:
return 1
return number * factorial(number - 1)
print(factorial(5))
Output: 120
factorial(5) = 5 * factorial(4) = 5 * 4 * factorial(3) = 5 * 4 * 3 * factorial(2) = 5 * 4 * 3 * 2 * factorial(1)
= 5 * 4 * 3 * 2 * 1 = 120
225
1. A nested function is created inside another function. 2. The inner function can be used only inside the
outer function. 3. Nested functions are useful for hiding helper logic. 4. They are also used in closures
and decorators.
Example 1
1. A closure needs a nested function. 2. The inner function uses a variable from the outer function. 3.
The outer function returns the inner function. 4. The inner function remembers the outer variable. 5.
Closures are useful for creating customized functions.
226
Output: 10
Function annotations are used to add type hints to function parameters and return values. Syntax
def function_name(parameter: type) -> return_type:
statement
1. Function annotations describe expected data types. They make code easier to
understand. 2. They help editors and tools detect possible mistakes. 3. Python does not automatically
enforce these types at runtime. 4. Annotations are stored in the function’s __annotations__ attribute.
Example 1
227
Output: {'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>} Important point: Type hints are hints.
Python does not stop wrong types automatically.
Syntax
OR
228
Explanation
1. Higher-order functions are possible because Python functions are objects. 2. They are used in map(),
filter(), reduce() , decorators,and callbacks. 3. They make code flexible and reusable. 4. They are
common in functional programming.
Syntax
Explanation
1. A local variable is created inside a function. 2. It can be used only inside that function. 3. It cannot be
accessed directly outside the function. 4. Local variables are created when the function is called. 5.
229
They are destroyed after the function finishes.
Example 1
A global scope is the main area of the program. Variablescreated outside all functions are global
variables.
Syntax
Explanation
1. A global variable is created outside functions. 2. It can be accessed inside functions. 3. It can also be
accessed outside functions. 4. Reading a global variable inside a function does not require the global
keyword. 5. To modify a global variable inside a function, we need the global keyword.
Example 1
230
Created where? Inside function Outside functions
Accessible where? Only inside that function Inside and outside functions
Variable shadowing happens when a local variable has the same name as a global variable.
Explanation
1. If a local and global variable have the same name, Python uses the local variable
inside the function. 2. The global variable is not changed. 3. This is called shadowing.
Example 1
▶ Output:
Syntax
global variable_name
Explanation
1. Use global when you want to assign a new value toa global variable inside a
function. 2. Without global , assignment inside a function createsa local variable. 3. Reading a global
variable does not need global . Usingtoo many global variables is
not recommended.
231
Example 1
Without global
232
1. Enclosing scope belongs to the outer function. 2. Inner functions can access variables from the outer
function. 3. This scope is between local and global scope. 4. Enclosing scope is important for nested
functions and closures.
Example 1
The nonlocal keyword is used to modify a variablefrom the nearest enclosing function scope.
Syntax
nonlocal variable_name
1. nonlocal is used inside nested functions. It allows the inner function to modify a
variable from the outer function. 2. It does not work with global variables. 3. The variable must already
exist in the enclosing function. nonlocal is commonly used
in closures.
Example 1
Without nonlocal
233
global vs nonlocal
Explanation
1. Built-in names are available automatically. 2. We do not need to define them. 3. Python searches
built-in scope last in the LEGB rule. 4. Avoid using built-in names as variable names.
Example 1
This is bad because the list is already a built-in name. Do not use names like list, dict, str, int, sum, or
max as variable names. 12.9 LEGB Rule
LEGB is the order Python follows while searching for a variable name. L -> Local E -> Enclosing G ->
Global B -> Built-in When Python sees a variable name, it searches in this order:
1. Local scope : inside the current function. 2. Enclosing scope : inside outer functions. 3. Global scope
: main program/file. 4. Built-in scope : built-in Python names.
Example 1
PYTHON CODE x = "global"
def outer():
234
x = "enclosing"
def inner():
x = "local"
print(x)
inner()
outer()
Output: local ⇒ Python finds x in the local scopefirst, so it does not search further.
4 Built-in print,len,type
Syntax Idea
Example 1
235
Namespace Table
Namespace Contains
Syntax
1. locals() returns the current local namespace as a dictionary. 2. globals() returns the global
namespace as a dictionary. 3. These are mainly used for debugging and learning. 4. Usually, we should
not modify program logic using them.
Example 1
236
Output: NameError: name 'age' is not defined
UnboundLocalError
UnboundLocalError occurs when Python treats a variableas local because it is assigned inside a
function, but it is used before assignment.
PYTHON CODE x = 10 def show():
print(x) x = 20
show()
output: UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
Error Meaning
Concept Meaning
237
13 Modules and Packages in Python
1. To organize large programs. 2. To reuse code. 3. To avoid writing the same logic again. 4. To separate
code into meaningful files. 5. To use built-in Python features from the standard library.
Syntax
import module_name
1. import loads a module. 2. After importing, we can use functions, classes, and variables from that
module. 3. We access module members using dot. notation. 4. Import statements are usually written at
the top of the file.
Example 1
238
Import with alias import module as alias import math as m [Link](25)
Import specific item from module import item from math import sqrt sqrt(25)
Import multiple items from module import a, b from math import sqrt, pow sqrt(25)
Example 1
Important Point
Avoid using from module import * in large programs. It can make code unclear and may cause name
conflicts.
The standard library is a collection of modules that come with Python. We do not need to install them
separately. Explanation
1. Standard library modules are built into Python.
2. They help with math, dates, files, operating system tasks, random values, JSON, and
more.
3. We can use them by importing them.
239
collections Advanced data structures Counter,deque
Example 1
├── [Link]
[Link]
Syntax
from module_name import function_name File structure: project/ │ ├── [Link] └── [Link]
Example 1 [Link]
PYTHON CODE def add(a, b):
return a + b
def subtract(a, b):
return a - b
240
[Link]\
PYTHON CODE from calculator import add
print(add(10, 20))
Output: 30
Explanation
Syntax
Example 1
This is used to control whether code should run directly or only when imported.
241
Syntax
1. Every Python file has a special variable called __name__. 2. If the file is run directly, __name__
becomes "__main__". 3. If the file is imported, __name__ becomes the modulename. 4. This is useful for
testing module code safely. 5. It prevents some code from running during import.
Example 1
[Link]
Flow Chart
242
Basic Package Structure
Explanation
Example 1
mypackage/[Link]
PYTHON CODE def add(a, b):
return a + b
[Link]
PYTHON CODE from [Link] import add
print(add(10, 20))
Output: 30
13.10 __init__.py
Explanation
1. __init__.py is placed inside a package folder. 2. It tells Python that the folder is a regular package. 3. It
can be empty. 4. It can also contain package-level initialization code. 5. It can control what is exposed
when importing from the package.
mypackage/
├── __init__.py
├── [Link]
└── [Link]
Example 1
mypackage/__init__.py
PYTHON CODE from .calculator import add
[Link]
PYTHON CODE from mypackage import add
print(add(10, 20))
Output: 30
243
13.11 Absolute Imports
An absolute import uses the full path from the project/package root. Syntax
from [Link] import name Explanation
1. Absolute imports are clear and easy to understand. 2. They show the full location of the imported
module. 3. They are generally preferred in larger projects. 4. They reduce confusion compared to
complex relative imports.
Example 1
Inside [Link]:
from [Link] import add
This means:
A relative imports code based on the current module’s location inside a package.
Syntax
Explanation
1. Relative imports use dots. 2. One dot. means current package. 3. Two dots.. means parent package.
4. Relative imports are used inside packages. 5. They are not meant for simple standalone scripts.
Syntax Meaning
. Current package
.. Parent package
Example Structure
244
Important Point Relative imports work properly when the module is part of a package. They may fail if
the file is run directly as a script. Better way to run a package module: python -m [Link]
Package management means installing, updating, removing, and tracking external Python packages.
Python commonly uses pip for package management.
Explanation
1. The Python standard library comes with Python. 2. Third-party packages must be installed
separately. 3. pip is used to install third-party packages. 4. Virtual environments are used to keep
project dependencies separate. 5. [Link] is used to record project dependencies.
Task Command
NOTE: Use python -m pip instead of only pip. Thismakes sure pip belongs to the
Python version you are using.
245
Create Virtual Environment
System Command
System Command
Deactivate
deactivate
13.16 [Link]
Syntax
package_name==version
Example
requests==2.32.3
numpy==2.0.0
Task Command
Explanation
246
13.17 Third-Party Packages
pytest Testing
Example Problem
247
14.1.1 OOPS Fundamentals
Basic idea
Class -> blueprint Object -> real item created from class
✎ Example idea:
Syntax
1. A class defines the structure of an object. 2. A class can contain attributes and methods. 3. Class
names usually use PascalCase. 4. A class does not represent one real object by itself. 5. Objects are
created from classes.
Example 1
248
EmployeeRecord Meaningful name 14.1.2 Objects
An object is an instance created from a class. Syntax
object_name = ClassName()
1. An object is created from a class. 2. One class can create many objects. 3. Each object can have its
own data. 4. Objects are also called instances.
Example 1
Class vs Object
Memory No object data yet Stores actual object data 14.1.3 Attributes
Attributes are variables that belong to an object or class.
Syntax
Example 1
249
[Link] = 21
print([Link])
print([Link])
Output: Aman
21
Attribute Table
Code Meaning
[Link] Accessesnameattribute
[Link] Accessesageattribute
14.1.4 Methods
Syntax
1. Methods define object behavior. 2. Methods are functions inside a class. 3. Instance methods usually
take self as the first parameter. 4. Methods are called using an object.
Example 1
250
14.1.5 self
self refers to the current object. Syntax
def method_name(self):
statement
1. self represents the object that is calling the method. 2. It is used to access object attributes and
methods. 3. Python automatically passes the object as self. 4. self is not a keyword, but it is the
standard convention. 5. Always use self for instance methods.
Example 1
14.1.6 __init__
__init__ is a special method used to initialize objectdata.
Syntax
1. __init__ runs automatically when an object is created. 2. It is used to set initial attribute values. 3. It is
commonly called a constructor. 4. Technically, __init__ initializes the object afterit is created. 5. The
actual object creation is handled by __new__ ,which is advanced and usually not
needed in core notes.
Example 1
251
Output: Aman
21
Example 1
Syntax
Explanation
1. Class variables are defined directly inside the class. 2. They are shared by all objects. 3. They are
useful for common data. 4. They can be accessed using the class name or object name. 5. Prefer
accessing class variables using the class name.
252
Example 1
Shared? No Yes
Important Warning
This list is shared by all objects, which can cause unexpected behavior.
253
Comparison Table
14.2.1 Encapsulation
Encapsulation means binding data and methods together inside a class and controlling how data is
accessed or modified. Basic Idea
Data + Methods = Encapsulation
1. Encapsulation keeps related data and behavior inside one class. 2. It helps protect data from direct
unwanted changes. 3. Python does not have strict private variables like Java or C++. 4. Python uses
naming conventions to show access level. 5. Encapsulation is commonly handled using:
1. Public attributes 2. Protected attributes 3. Private/name-mangled attributes 4. Getter and setter
methods 5. @property
PYTHON CODE class BankAccount:
def __init__(self, balance):
self.__balance = balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def get_balance(self):
return self.__balance
account = BankAccount(1000)
[Link](500)
print(account.get_balance())
Output: 1500
Here, __balance is not directly accessed from [Link] is accessed using methods.
254
Access Level Table
Private / Name mangling name __ Avoid accidental outside access self. pin __
Example 1
Important Point
Double underscore does not make data fully private. It performs name mangling to avoid accidental
access. Internally, Python changes: __grade -> _Student__grade So technically it can still be accessed,
but it should not be used directly.
Getter and setter methods are used to read and update private data safely.
255
1. Getter method reads private data. 2. Setter method updates private data. 3. Setter can validate data
before updating. 4. This protects the object from invalid values.
Example 1
256
1. @property is a clean way to control access to data. 2. It allows validation before changing data. 3. It
supports getter and setter behavior. 4. It makes code look simple while still protecting data.
Example 1
14.2.2 Inheritance
Inheritance allows one class to reuse the properties and methods of another class.
257
Syntax
Explanation
1. Inheritance supports code reuse. 2. The parent class is also called base class or superclass. 3. The
child class is also called derived class or subclass. 4. The child class can use parent class attributes
and methods. 5. The child class can also define its own attributes and methods. 6. The child class can
override parent methods. 7. Inheritance represents an is-a relationship.
Basic Example
Inheritance Flow
Use Meaning
258
Maintainability Common logic stays in parent class
Example: Dog is an Animal Car is a Vehicle Student is a Person Types of Inheritance in Python
Python supports these major types of inheritance:
Type Meaning
Multilevel inheritance Child inherits from parent, and another child inherits from that child
Single Inheritance
Single inheritance means one child class inherits from one parent class.
Syntax
Example 1
PYTHON CODE class Animal:
def eat(self):
print("Eating")
class Dog(Animal):
259
def bark(self):
print("Barking")
dog = Dog()
[Link]()
[Link]()
Output: Eating
Barking
Multilevel Inheritance
Multilevel inheritance means a class inherits from a child class, forming a chain.
Syntax
Example 1
PYTHON CODE class Animal:
def eat(self):
print("Eating")
class Dog(Animal):
def bark(self):
print("Barking")
class Puppy(Dog):
260
def weep(self):
print("Weeping")
puppy = Puppy()
[Link]()
[Link]()
[Link]()
Output: Eating Barking Weeping
Hierarchical Inheritance
Hierarchical inheritance means multiple child classes inherit from one parent class.
Syntax
Example 1
PYTHON CODE class Animal:
def eat(self):
print("Eating")
class Dog(Animal):
def bark(self):
print("Barking")
class Cat(Animal):
def meow(self):
261
print("Meowing")
dog = Dog() cat = Cat() [Link]() [Link]() [Link]() [Link]()
Output: Eating
Barking
Eating
Meowing Diagram
Animal
/\
vv
Dog Cat
Multiple Inheritance
Multiple inheritance means one child class inherits from more than one parent class.
Syntax
Example 1
262
child.father_skill() child.mother_skill() child.child_skill()
Output: Gardening Painting Coding Diagram
Father Mother
\/vv
Child
Hybrid Inheritance
Example 1
Diagram
Person / \
vv
Student Employee
263
\/
vv
TeachingAssistant
MRO is the order Python follows while searching for methods in inheritance.
Syntax
OR
1. MRO decides which method is called first. 2. It is important in multiple inheritance. 3. Python uses the
C3 linearization algorithm for MRO. 4. The search starts from the child class. 5. Then Python checks
parent classes according to MRO. 6. Finally, it checks the base object class.
Example 1
264
pass
obj = D()
[Link]()
print([Link]())
Output: B
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class
'object'>]
MRO Flow
Diamond Problem
The diamond problem happens when a child class inherits from two classes that both inherit from the
same parent.
1. Class B and class C both inherit from A. 2. Class D inherits from both B and C. 3. If the same method
exists in multiple classes, Python uses MRO to decide. 4. Python handles this safely using MRO. 5.
super() also follows MRO.
Example 1
265
print("B")
class C(A):
def show(self):
print("C")
class D(B, C):
pass d = D() [Link]()
Output: B Because the MRO is: D -> B -> C -> A -> object
Constructor in Inheritance
When a child object is created, Python runs the child class __init__ method. If the child class does not
have __init__ , Pythonuses the parent class __init__.
266
super()
super() is used to call the next method in the MRO,usually from the parent class.
Syntax
super().method_name()
Explanation
1. super() is commonly used to call parent class methods. 2. It is commonly used inside __init__. 3. It
avoids directly writing the parent class name. 4. In multiple inheritance, super() follows MRO. 5. It helps
avoid repeating parent class logic.
Example 1
Method overriding means a child class defines a method with the same name as a parent class method.
267
Syntax
Explanation
1. The method name is the same in parent and child. 2. The child class provides its own version. 3.
When called on child object, child method runs. 4. This supports polymorphism. 5. Parent method can
still be called using super().
Example 1
268
class Dog(Animal):
def sound(self):
super().sound()
print("Bark")
dog = Dog()
[Link]()
Output: Animal sound
Bark 14.2.4 Polymorphism
Polymorphism means the same method or operation behaves differently for different objects.
Explanation
1. Polymorphism means “many forms”. 2. The same method name can work differently in different
classes. 3. Python supports polymorphism through:
1. Method overriding 2. Duck typing 3. Operator overloading
PYTHON CODE class Dog:
def sound(self):
print("Bark")
class Cat:
def sound(self):
print("Meow")
animals = [Dog(), Cat()]
for animal in animals:
[Link]()
Output: Bark
Meow
Duck typing means Python focuses on what an object can do, not its exact type.
269
Basic Idea
Example 1
14.2.6 Abstraction
Abstraction means hiding internal implementation and showing only essential features.
Explanation
1. Abstraction focuses on what an object does. 2. It hides how the object does it internally. 3. Python
supports abstraction using abstract base classes. 4. Abstract base classes are created using the abc
module. 5. A class with abstract methods cannot be instantiated directly. 6. Child classes must
implement abstract methods.
Example 1
270
Output: Paid 500 using UPI
Important Point
▶ Output:
TypeError: Can't instantiate abstract class Payment with abstract method pay
Encapsulation vs Abstraction
Encapsulation = How data is protected Abstraction = How unnecessary details are hidden
14.2.7 Composition
Composition means one class contains an object of another class. Basic Idea
Inheritance = is-a relationship
Composition = has-a relationship
1. Composition is used when one object is made of another object. 2. It represents a has-a
relationship. 3. It is often preferred over inheritance when there is no true is-a relationship.
Example 1
271
Output:Engine started Explanation: Car has an Engine. So this is composition.
Aggregation One class has another, but both can exist independently Department has Teachers
Important Difference
Example 1
Inheritance vs Composition
272
Code style Child class extends parent Class contains another object
273
Important OOP Scenario Table
Scenario Use
Special methods are predefined methods in Python with double underscores before and after their
names.
They are also called:
● Special methods ● Magic methods ● Dunder methods
Explanation
1. Special methods allow objects to work with Python’s built-in operations. 2. They are called
automatically by Python. 3. They usually start and end with double underscores. 4. We normally do not
call them directly. 5. Instead, we use operators or built-in functions.
274
Example Idea
14.3.1 __str__
Syntax
275
Explanation
1. __str__ is called by str(obj). 2. It is also called by print(obj). 3. It should return a string. 4. It is mainly
for users. 5. It should be readable and simple.
Example 1
14.3.2 __repr__
Syntax
1. __repr__ is called by repr(obj) . It is mainly usedfor debugging. 2. It should return a string. A good
__repr__ often lookslike valid Python code. 3. If __str__ is not defined, Python may use __repr__ while
printing.
PYTHON CODE class Student:
def __init__(self, name, course):
[Link] = name [Link] = course
def __repr__(self):
return f"Student(name={[Link]!r}, course={[Link]!r})" student = Student("Aman", "Python")
print(repr(student))
Output:Student(name='Aman', course='Python')
14.3.3 __len__
__len__ defines the behavior of len(obj).
276
Syntax
Explanation
1. __len__ is called by len(obj). 2. It must return a non-negative integer. 3. It is useful for custom
container-like classes. 4. If __bool__ is not defined, Python may use __len__ to decide truthiness. 5. If
__len__ returns 0 , the object is considered False in Boolean context.
Example 1
14.3.4 __getitem__
Syntax
277
team = Team(["Aman", "Riya", "Kabir"])
print(team[0])
print(team[1])
print(team[0:2])
Output: Aman Riya ['Aman', 'Riya']
14.3.5 __add__
Syntax
Example 1
14.3.6 __sub__
Syntax
278
return result
1. __sub__ is called when obj1 - obj2 is used. 2. It is also part of operator overloading. 3. It should return
a meaningful result. 4. Return NotImplemented if the other type is unsupported.
Example 1
14.3.7 __call__
Syntax
def __call__(self):
statement
Explanation
1. __call__ runs when an object is called using parentheses. 2. It makes an object callable. 3. It is useful
when an object stores data and also performs an action. 4. It is commonly used in decorators,
callbacks, and callable classes.
Example 1
Syntax
Explanation
1. __enter__ runs at the start of the with block. 2. __exit__ runs when the with block ends. 3. __exit__ runs
even if an error occurs inside the with block. 4. __exit__ receives exception details if an error occurs. 5.
If __exit__ returns True , the exception is suppressed. 6. If __exit__ returns False or None , the exception
continues.
PYTHON CODE class SimpleContext:
def __enter__(self):
print("Entering")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting")
with SimpleContext():
print("Inside with block")
Output: Entering Inside with block Exiting
280
Example 1
Explanation
1. open() returns a file object. 2. The file object works as a context manager. 3. The file opens at the
start of the with block. 4. The file closes automatically at the end. 5. This is safer than manually closing
the file.
Operator overloading means giving custom behavior to operators for user-defined classes.
Explanation
1. Operators like +, -, *, ==, < , and [] can be customized. 2. This is done using special methods. 3.
Operator overloading should be logical. 4. Do not overload operators in a confusing way. 5. Operators
internally call matching dunder methods.
== eq __ __ obj1 == obj2
!= ne __ __ obj1 != obj2
281
<= le __ __ obj1 <= obj2
[] getitem __ __ obj[index]
() call __ __ obj()
Syntax
Explanation
1. __eq__ defines equality using ==. 2. __lt__ defines less than using <. 3. Other comparison methods
work similarly. 4. These methods should return True or False. 5. Return NotImplemented if comparison
with the othertype is unsupported.
Example 1
282
return [Link] == [Link]
student1 = Student("Aman", 85)
student2 = Student("Riya", 85)
print(student1 == student2)
Output: True
Here, two students are considered equal because their marks are equal.
Method Operator
eq __ __ ==
ne __ __ !=
lt __ __ <
le __ __ <=
gt __ __ >
ge __ __ >=
Explanation
1. Reverse methods are used when the left object does not support the operation. 2. In-place methods
are used for operators like +=, -=, *=. 3. These are advanced but useful to know.
Table
283
14.3.13 __bool__
__bool__ defines truth value behavior of an object.
Syntax
Explanation
1. __bool__ is called by bool(obj). 2. It is also used in if obj: conditions. 3. It must return True or False. 4.
If __bool__ is not defined, Python may use __len__. 5. If both are missing, most objects are considered
True.
Example 1
284
def __init__(self, limit):
[Link] = 1
[Link] = limit
def __iter__(self):
return self
def __next__(self):
if [Link] > [Link]:
raise StopIteration
value = [Link]
[Link] += 1
return value
counter = CountUpTo(3)
for number in counter:
print(number)
Output: 1 2 3
14.3.15 __contains__
Syntax
Explanation
1. __contains__ is called by item in obj. 2. It should return True or False. 3. It is useful for custom
container-like classes.
Example 1
285
Output:
True
False
Rule Explanation
Do not call directly Use len(obj) , not obj.__len__() Special Methods Summary
286
next __ __ Returns next item Iterator protocol
Advanced OOP topics help us write cleaner, safer, and more reusable class-based code.
This section includes:
1. @classmethod 2. @staticmethod 3. @property 4. Abstract base classes 5. Mixins 6. Metaclasses 7.
Data classes
15.1 @classmethod
A class method is a method that receives the classas its first argument.
The first parameter is usually named cls.
Syntax
class ClassName:
@classmethod def method_name(cls):
statement
Explanation
1. @classmethod is used to create a class method. 2. A class method receives the class automatically
as cls. 3. It can access class variables. 4. It can modify class variables. 5. It can be called using the
class name or object name. 6. It is commonly used to create alternate constructors.
Example 1
287
print(student1.school_name)
print(Student.school_name)
Output:
XYZ School
XYZ School
Important Points
Point Explanation
Receives Class
Syntax
1. A class normally creates objects using __init__. 2. Sometimes data comes in a different format. 3. A
class method can convert that data and return an object. 4. cls(...) creates an object of the current
class. 5. This is useful for flexible object creation.
Example 1
15.3 @staticmethod
A static method is a method inside a class that doesnot receive self or cls.
Syntax
class ClassName:
@staticmethod def method_name():
statement
1. @staticmethod creates a static method. 2. It does not receive the object as self. 3. It does not receive
the class as cls. 4. It behaves like a normal function placed inside a class. 5. It is used when the method
is logically related to the class but does not need object
or class data.
Example 1
Important Points
Point Explanation
Receives object? No
Receives class? No
289
15.4 Instance Method vs Class Method vs Static Method
15.5 @property
Syntax
class ClassName:
@property def attribute_name(self):
return value
Explanation
1. @property is used to create managed attributes. 2. It allows method logic to run when accessing an
attribute. 3. It helps with encapsulation. 4. It can be used for validation. 5. It makes code cleaner than
normal getter methods.
Example 1
[Link] looks like an attribute, but internally it calls the marks() method.
Syntax
Explanation
1. A getter returns the value. 2. A setter updates the value. 3. The setter can validate the value before
saving it. 4. This protects objects from invalid data. 5. The property name and setter name must match.
Example 1
Part Purpose
291
@property Reads value
Syntax
@property
def property_name(self):
return value
Explanation
1. If no setter is defined, the property cannot be assigned directly. 2. This is useful for calculated values.
3. It protects values from direct modification.
PYTHON CODE class Rectangle:
def __init__(self, length, width):
[Link] = length
[Link] = width
@property
def area(self):
return [Link] * [Link]
rectangle = Rectangle(10, 5)
print([Link])
Output:
50
Invalid update:
[Link] = 100
Output:
AttributeError: property 'area' of 'Rectangle' object has no setter
An abstract base class defines a common structurethat child classes must follow. Syntax
292
1. Abstract base classes are created using ABC. 2. Abstract methods are created using
@abstractmethod. 3. A class with abstract methods cannot be instantiated directly. 4. Child classes
must implement all abstract methods. 5. Abstract base classes are useful when many classes should
follow the same
structure.
Abstract class
| v Defines required method
| v Child class must implement method
| v Child object can be created
PYTHON CODE from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod def area(self):
pass
class Square(Shape):
def __init__(self, side):
[Link] = side
def area(self):
return [Link] * [Link]
square = Square(5)
print([Link]())
Output: 25
293
15.9 Why Abstract Base Classes Are Used
Abstract base classes are used when we want to force child classes to implement required methods.
Every payment class must have pay() method. UPI payment -> pay() Card payment -> pay() Cash
payment -> pay()
Benefit Explanation
15.10 Mixins
Syntax
class MixinName:
def method_name(self):
statement
class MainClass(MixinName):
pass
1. A mixin is used to add extra features. 2. A mixin is usually not meant to be used alone. 3. Mixins are
commonly used with multiple inheritance. 4. A mixin should be small and focused. 5. Mixin class names
often end with Mixin.
Example 1
294
Important Points
Point Explanation
15.12 Metaclasses
295
Output: <class '__main__.Student'>
<class 'type'>
Code Meaning
A data class is a class mainly used to store data. It reduces repeated code like __init__, __repr__ , and
comparison methods.
Syntax
Explanation
1. Data classes are created using @dataclass. 2. They are useful for classes that mainly store data. 3.
Fields are declared using type annotations. 4. Python automatically creates __init__. 5. Python
automatically creates useful __repr__. 6. Data classes were introduced in Python 3.7.
296
Example 1
Comparison Table
Do not directly use mutable default values like lists in data classes. Wrong Style
297
This is not allowed in modern Python data classes. Correct Style : Use field(default_factory=list).
Output: ['Python']
298
[] 1. Mutable defaults can accidentally be shared. 2. default_factory=list creates a new list for each
object. 3. This avoids shared mutable data problems.
A frozen data class creates objects that cannot be modified after creation.
Syntax
Explanation
1. frozen=True makes data class objects immutable-like. 2. After object creation, fields cannot be
reassigned normally. It is useful for fixed data. 3. It is similar in idea to immutability, but internal mutable
fields can still be modified if
they exist.
Example 1
299
16 File Handling and Error Management
With encoding:
Example 1
Syntax
[Link]()
1. Closing a file releases system resources. If a file is not closed, data may not be
saved properly. 2. The with statement is preferred because it closesthe file automatically.
Example 1
300
16.1.4 Reading Files
Method Meaning
Example 1
Syntax
Example 1
Syntax
open("file_name", "w")
1. "w" means write [Link] the file does not exist, Pythoncreates it. 2. If the file already exists, old
content is removed. 3. New content is written from the beginning.
301
Example 1
Syntax
open("file_name", "a")
Explanation
1. "a" means append mode. New data is added at the end. 2. Old content is not removed. If the file does
not exist, Python creates it.
Example 1
Mode Meaning
302
"wt" Write text file
Syntax
Example 1
No need to write:
[Link]()
Method Meaning
303
writelines(list) Writes multiple strings
Syntax
Explanation
1. "rb" means read binary. "wb" means write binary. 2. Binary mode works with bytes, not normal
strings. 3. Encoding is not used in binary [Link] files are useful for non-text data.
Syntax
import os
Common os Functions
Function Meaning
304
[Link]() Lists files and folders
[Link](a, b) Joins paths safely 16.1.14 Basic pathlib Module pathlib is a modern way to work with
file paths.
Syntax
Code Meaning
305
1. Text files store text using an encoding. 2. utf-8 supports most common characters. 3. Always mention
encoding when working with text files. 4. Encoding problems can cause UnicodeDecodeError.
Example 1
An exception is an error that happens while the program is running. Exception handling allows us to
handle errors safely without crashing the whole program.
number = int("abc")
Output: ValueError: invalid literal for int() withbase 10: 'abc'
1. To prevent sudden program crashes. 2. To handle risky code safely. 3. To clean up resources
properly. 4. To continue program execution when possible.
16.2.1 try-except
Syntax
try:
risky_code
except ExceptionType:
handling_code
1. Code that may cause an error is written inside try. 2. Error handling code is written inside except. 3. If
an exception occurs, Python jumps to the matching except block. 4. If no exception occurs, the except
block is skipped.
Flow Chart
Example 1
Example 1
Explanation
1. Different exceptions can need different handling. 2. Specific exceptions should come before general
exceptions. 3. Python runs only the first matching except block. 4. Exception should usually come last.
Example 1
Syntax
307
Example 1
Syntax
16.2.6 finally
The finally block always runs. Syntax
PYTHON CODE try:
risky_code except ExceptionType:
handling_code finally:
cleanup_code
Explanation
1. finally runs whether an exception occurs or not. 2. It is used for cleanup operations. 3. It is useful for
closing files, network connections, or database connections. 4. With file handling, with is usually
cleaner than manually using finally.
Example 1
try
| v Error occurs?
| ├── Yes -> except -> finally | └── No -> else -> finally
Structure
Syntax
raise ExceptionType("message")
1. raise is used to manually trigger an exception. 2. It is useful for validation. 3. It stops normal flow and
sends control to exception handling. 4. We can raise built-in or custom exceptions.
Example 1
Re-raising means raising the same exception again after catching it.
Syntax
raise
1. Plain raise is used inside an except block. 2. It re-raises the current exception. 3. It is useful when we
want to log an error but still allow it to continue upward.
Example 1
309
print("Logging error") raise
Output: Logging error ValueError: invalid literal for int() with base 10: 'abc'
Syntax
Explanation
1. Custom exceptions are created by inheriting from Exception. 2. They make errors more meaningful. 3.
They are useful in larger projects. 4. Custom exception names usually end with Error.
Example 1
310
PermissionError No permission for file operation
Problem Explanation
Can catch system-exit style errors Not safe for normal use
Error Meaning
PermissionError No permission
Example 1
311
with open("[Link]", "r", encoding="utf-8") as file:
content = [Link]() except FileNotFoundError:
print("File not found") else:
print(content)
1. Text files store characters. 2. Text files should be opened with encoding. 3. Common modes are "r",
"w" , and "a". 4. Text mode is default in Python.
312
[Link]() List for each row Simple row-based reading
JSON means JavaScript Object Notation . JSON is commonlyused for APIs and configuration files.
PYTHON CODE {
"name": "Aman", "age": 21, "course": "Python"}
Explanation
1. JSON stores data in key-value format. It looks similar to Python dictionaries. 2. Python provides the
built-in json module. 3. JSON is very common in web development and APIs. JSON keys must be
strings.
Python JSON
dict object
list array
str string
int,float number
True true
False false
None null
<student>
<name>Aman</name> <age>21</age> <course>Python</course> </student>
Advanced Python concepts help us write cleaner, memory-efficient, reusable, and professional Python
code. This chapter covers:
1. Decorators 2. Generators and Iterators 3. Context Managers 4. Regular Expressions
17.1 Decorators
17.1.1 Decorators
A decorator is a function that takes another function and adds extra behavior to it without changing the
original function code.
Basic Idea
314
Syntax
This=>
is equal to:
Flow Chart
Original function
315
| v Decorator receives function
| v Wrapper adds extra behavior
| v Decorated function is returned
If the decorated function has arguments, the wrapper should accept *args and **kwargs. Syntax
PYTHON CODE def decorator_name(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs) return wrapper
Example 1
316
def wrapper(*args, **kwargs):
print("Function is being called") return func(*args, **kwargs) return wrapper
@show_call def add(a, b):
return a + b
print(add(10, 20))
Output: Function is being called
30
17.1.4 [Link]
[Link] preserves the original function’smetadata. Without wraps , the decorated function may
lose its original name and docstring.
Syntax
1. Decorators replace the original function with a wrapper. 2. Because of this, metadata like function
name and docstring can be lost. 3. @wraps(func) copies metadata from the original functionto the
wrapper. 4. Professional decorators should usually use [Link].
PYTHON CODE from functools import wraps
def my_decorator(func):
@wraps(func) def wrapper(*args, **kwargs):
return func(*args, **kwargs) return wrapper
@my_decorator def greet():
"""This function greets the user.""" print("Hello")
print(greet.__name__) print(greet.__doc__)
317
Output: greet
This function greets the user.
Decorators can also accept their own arguments. This requires one extra outer function. Syntax
PYTHON CODE def decorator_with_args(value):
def actual_decorator(func):
def wrapper(*args, **kwargs):
statement
return func(*args, **kwargs)
return wrapper
return actual_decorator
1. The outer function receives decorator arguments. The middle function receives the
original function. 2. The inner wrapper runs extra [Link] is useful when decorator behavior needs
customization.
PYTHON CODE from functools import wraps
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet():
print("Hello")
greet()
Output: Hello
Hello Hello 17.1.6 Multiple Decorators
A function can have more than one decorator. Syntax
PYTHON CODE @decorator1
@decorator2 def function_name():
statement
318
NOTE: Decorators are applied from bottom to top.
PYTHON CODE @decorator1 @decorator2 def greet():
pass
is equal to:
Syntax
Generators and iterators are used to work with values one at a time. They are memory-efficient because
they do not need to store all values at once.
319
17.2.1 Iterable vs Iterator
Explanation
An iterable is an object we can loop over. An iterator is an object that gives values one by one using
next().
Iterable Can be looped over list, tuple, string, dictionary, set, range
Example 1
Syntax
Explanation
1. __iter__() returns an iterator object. 2. __next__() returns the next value. 3. When no values are left,
__next__() raises StopIteration. 4. for loops use this protocol internally.
Example 1
17.2.3 __iter__
__iter__ returns an iterator object.
Syntax
Explanation
1. __iter__() is called by iter(object). 2. It is also used automatically for loops. 3. If the object itself is the
iterator, it returns self. 4. If the object is only iterable, it can return a separate iterator object.
Example 1
17.2.4 __next__
Syntax
321
Example 1
Syntax
Explanation
1. A generator function returns a generator object. 2. It does not run fully at once. 3. It pauses at yield.
4. When next() is called again, it continues from whereit paused. 5. Generators are memory-efficient.
Example 1
Correct code:
17.2.6 yield
yield is used to return a value from a generator withoutending the function permanently. Syntax
322
yield value
1. yield gives one value at a time. It pauses the function. 2. The function state is saved. 3. On the next
call, execution continues after the previous yield. 4. When the function finishes, Python raises
StopIteration.
return vs yield
Syntax
Explanation
1. Generator expressions look like list comprehensions. 2. They use parentheses(). 3. They produce
values lazily. 4. They do not create a full list in memory. 5. They are useful for large data.
Example 1
Syntax
323
17.2.9 One-time Consumption of Iterators
Explanation
1. Once a value is taken from an iterator, it is not repeated. 2. After all values are consumed, the iterator
is exhausted. 3. To iterate again, create a new iterator or generator.
Example 1
▶ Output:
[0, 1, 2]
[]
The second list is empty because the generator was already consumed.
17.2.10 itertools
Syntax
import itertools
Explanation
Tool Meaning
324
permutations() All possible arrangements
Generators are memory-efficient because they produce values only when needed.
1. Lists store all values in memory. 2. Generators produce one value at a time. 3. This is called lazy
evaluation. 4. Generators are useful for large files, large ranges, and data streams.
Example 1
Syntax
Flow Chart
Example 1
17.3.1 __enter__
1. __enter__() is called when the with block [Link] usually prepares or opens a
resource. 2. The value returned by __enter__() is stored after as . It is part of the context manager
protocol.
17.3.2 __exit__
Syntax
1. __exit__() is called at the end of the with [Link] is used for cleanup. 2. It receives exception details if
an error occurs. If it returns True , the exception is
suppressed. 3. If it returns False or None , the exception continuesnormally.
__exit__ Parameters
Parameter Meaning
Syntax
326
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
cleanup_code
Example 1
17.3.4 contextlib
contextlib is a standard library module for creatingand working with context managers.
Syntax
17.3.5 @contextmanager
@contextmanager converts a generator function intoa context manager.
Syntax
Explanation
1. Code before yield works like __enter__ . The yieldedvalue is used after as. 2. Code after yield works
like __exit__ . Cleanup shouldbe placed in finally for safety. 3. This is useful for simple context
managers.
327
Class Context Manager vs @contextmanager
A regular expression, or regex , is a pattern used to search, match, extract, replace, or split text.
Basic Idea
Example Uses
1. Validate email format. 2. Extract phone numbers. 3. Find dates in text. 4. Replace unwanted
characters. 5. Split text using complex patterns.
17.4.1 re Module
Syntax
import re
Explanation
1. re is Python’s regular expression module. 2. It provides functions like search(), match(), findall(), sub()
, and split(). 3. Regex patterns are usually written as raw strings. 4. Raw strings use prefix r.
328
Raw String Example
* Zero or more a*
+ One or more a+
? Zero or one a?
` ` OR
() Group (ab)+
\ Escape character \.
329
17.4.4 Common Regex Character Classes
Pattern Meaning
\D Non-digit
\W Non-word character
\s Whitespace
\S Non-whitespace
\b Word boundary
\A Start of string
\Z End of string
Syntax
(pattern)
Explanation
1. Parentheses create groups. 2. Capturing groups store matched parts. 3. group(0) gives the full match.
4. group(1) gives the first captured group. 5. group(2) gives the second captured group.
Syntax
(?:pattern)
Explanation
1. Non-capturing groups are used for grouping only. 2. They do not create a captured group number. 3.
They are useful when we need grouping but do not need to extract that part.
17.4.7 search()
330
Syntax
[Link](pattern, text)
Explanation
1. Searches the entire string. Returns the first match object. 2. Returns None if no match is found. 3. Use
.group() to get matched text.
17.4.8 match()
match() checks for a match only at the beginning ofthe string.
Syntax
[Link](pattern, text)
Explanation
1. Checks only from the start of the string. Returns match object if pattern matches at
the beginning. 2. Returns None if pattern appears later.
17.4.9 fullmatch()
Syntax
[Link](pattern, text)
Explanation
1. It checks the entire string. 2. It returns a match only if the full string matches. 3. It is useful for
validation.
17.4.10 findall()
findall() returns all non-overlapping matches as alist.
Syntax
[Link](pattern, text)
Explanation
1. Finds all matches. 2. Returns a list. 3. If the pattern has capturing groups, it returns captured groups.
4. If no match is found, it returns an empty list.
17.4.11 finditer()
Syntax
[Link](pattern, text)
331
1. It finds all matches. It returns match objects one by one. 2. It is useful when we need match positions.
3. It is more memory-friendly for large text than findall().
17.4.12 sub()
Syntax
Explanation
1. Finds matches using pattern. Replaces them with replacement text. 2. Returns the modified string.
Original string is not changed.
17.4.13 split()
split() splits a string using a regex pattern.
Syntax
[Link](pattern, text)
1. Splits text wherever the pattern matches. 2. More powerful than normal string split(). 3. Useful when
separators are multiple or irregular.
17.4.14 [Link]()
Syntax
pattern = [Link](r"pattern")
Explanation
1. Compiled patterns can be reused. 2. This makes code cleaner when using the same pattern many
times. 3. It can be useful for repeated matching. 4. Pattern objects have methods like search(), findall(),
sub() , and split()
Concurrent programming means handling multiple tasks during the same time period. It does not
always mean tasks are running at the exact same instant.
332
Basic Terms
Term Meaning
I/O-bound task Task waiting for input/output, like file, network, database
18.1 Multithreading
Syntax
import threading
1. A thread is a small unit of execution. 2. Multiple threads can run inside one process. 3. Threads share
the same memory. 4. Threads are useful for I/O-bound tasks. 5. Threads can cause race conditions
when shared data is modified. 6. Locks are used to protect shared data.
Flow Chart
Main program
| v Create threads
333
| v Start threads
| v Threads run tasks
| v Join threads
| v Program continues
The threading module provides classes and tools forworking with threads.
Tool Purpose
Lock Prevents multiple threads from changing shared data at the same time
Syntax
Explanation
1. target is the function that the thread will run. 2. start() starts the thread. 3. join() waits for the thread to
finish. 4. Without join() , the main program may continue whilethe thread is still running.
Example 1
334
Thread is running
Main program finished
A race condition happens when multiple threads access and modify shared data at the same time,
causing incorrect results.
Explanation
1. Threads share memory. 2. If two threads change the same variable together, the result can become
unpredictable. 3. This problem is called a race condition. 4. Locks are used to avoid race conditions.
Example Idea
18.1.5 Locks
Syntax
335
Example 1
18.1.6 Synchronization
Tool Purpose
18.2 Multiprocessing
336
Python provides the multiprocessing module for process-based parallelism. ProcessPoolExecutor is
also documented as a higher-levelinterface for running tasks in background processes.
Syntax
import multiprocessing
Explanation
1. A process has its own Python interpreter and memory space. 2. Processes do not share normal
memory like threads. 3. Multiprocessing is useful for CPU-bound tasks. 4. It can use multiple CPU
cores. 5. Communication between processes needs special tools like Queue, Pipe, Manager,
or shared memory.
Thread vs Process
pid Process ID
337
Syntax
Tool Purpose
Syntax
Explanation
338
18.3.1 ThreadPoolExecutor
ThreadPoolExecutor runs tasks using a pool of threads. Best for I/O-bound tasks
Example 1
18.3.2 ProcessPoolExecutor
ProcessPoolExecutor runs tasks using a pool of [Link] for CPU-bound tasks
PYTHON CODE from [Link] import ProcessPoolExecutor
def square(number):
return number * number
if __name__ == "__main__":
with ProcessPoolExecutor() as executor:
results = [Link](square, [1, 2, 3, 4])
print(list(results))
Output: [1, 4, 9, 16]
18.3.3 Futures
Method Meaning
339
Example 1
Async programming is used to write concurrent code using async and await.
Python’s official asyncio documentation describesit as a library for writing concurrent code using async
/ await , commonly used for high-performancenetwork servers, web servers, database libraries, and
distributed task queues. Best for I/O-bound tasks with many waiting operations
18.4.1 asyncio
asyncio is Python’s standard library module for asynchronousprogramming.
Syntax
import asyncio
1. asyncio runs asynchronous tasks. 2. It uses an event loop. 3. It is usually single-threaded cooperative
concurrency. 4. Tasks pause when they reach await. 5. While one task is waiting, another task can run.
Flow Chart Event loop starts
| v Task 1 runs
| v Task 1 awaits
| v Task 2 runs
| v Tasks complete
Syntax
Explanation
1. async def defines a coroutine function. 2. Calling a coroutine function returns a coroutine object.
340
3. The coroutine does not run immediately just because it is called. 4. It must be awaited or run by the
event loop. 5. [Link]() is commonly used to start the main coroutine.
Example 1
18.4.3 await
Syntax
await awaitable
Explanation
1. await can be used only inside async def . It pausesthe current coroutine. 2. It allows the event loop to
run other tasks. 3. It is used with coroutines, tasks, and async operations.
Example 1
18.4.5 Tasks
341
Syntax
task = asyncio.create_task(coroutine())
1. A task wraps a coroutine. It schedules the coroutine to run on the event loop. 2. Multiple tasks can
run concurrently. await task getsthe final result.
Example 1
▶ Output:
18.4.6 [Link]()
[Link]() runs multiple awaitables concurrentlyand collects their results.
Future Comparison
[Link] asyncio Event loop and async tasks 18.4.8 Async Context Managers
342
Async context managers are used with async with . Theyuse:
__aenter__
__aexit__
not normal __enter__ and __exit__.
Syntax
Explanation
1. async with is used for async resource management. 2. __aenter__ runs when the async context starts.
3. __aexit__ runs when the async context ends. 4. These methods can use await. 5. They are common in
async database connections, HTTP clients, and network
resources.
Example 1
343
Best for I/O-bound blocking work CPU-bound work I/O-bound non-blocking work
Main risk Race conditions Process overhead Blocking the event loop
344
You made it to the end! 🎉
You now hold a complete Python reference — from your first print() to
async programming. Save it, revise it, and build something you're proud of.
Follow @[Link]
"Every expert was once a beginner who refused to quit. Your consistency
today is the career you'll thank yourself for tomorrow." 💪
More free tech & placement resources on Instagram → @[Link]