SlideShare a Scribd company logo
Python Notes
Python Programming Notes
Disclaimer:
These Python notes are exclusively for students who have enrolled in the Amend
Ed Tech Python course or have purchased the notes through 📌Udemy or 📌
Tutorialspoint or 📌Gumroad or 📌Topmate. This material is intended for personal
learning and reference only. Any unauthorized distribution, resale, reproduction,
or sharing of these notes in any form—whether digital or printed—is strictly
prohibited. Legal action may be taken against individuals or entities found violating
these terms.
Master Python with Visual Learning!
Struggling to understand how Python works behind the scenes? Our course is
designed to give you 100% clarity on program execution, straight from the RAM
perspective!
Python Notes 1
c
o
d
e
r
s
n
o
t
e
.
c
o
m
✅Perfect for Beginners & Non-IT Students
✅Visual Learning Approach – See how code executes in memory!
✅Hands-on Examples & Real-World Scenarios
📌Start your Python journey today! 👉Enroll Now
🎉Struggling with Python? Get 30 Minutes FREE! 🎉
Need help with a Python concept? I’ll explain ANY topic you’re stuck on in a 1-on-
1 online session – in the simplest way possible!
✅First 30 minutes FREE! No risk, just learning!
✅Personalized explanations for your level
✅Visual learning for 100% clarity
📌Book your free session now and start mastering Python!
📩Need Quick Python Help? Chat on WhatsApp! 📩
Stuck on a Python concept? Get instant support and clear your doubts one-on-
one via WhatsApp!
✅Quick & Easy Explanations
✅Ask Anytime, Get Answers Fast!
📌Message me now on WhatsApp and start mastering Python!
Lets Start!
What is Python?
Python is a high-level, versatile programming language known for its simplicity
and readability. It supports multiple programming paradigms, including object-
oriented, procedural, and functional programming. Python is widely used in web
development, data science, artificial intelligence, automation, and more, thanks to
its extensive libraries and community support. It is also platform-independent and
Python Notes 2
c
o
d
e
r
s
n
o
t
e
.
c
o
m
dynamically typed, making it a popular choice for beginners and professionals
alike.
Why is Python Popular?
Python has become one of the most favored programming languages due to its
simple syntax and flexibility. It is widely used in various domains like:
Web Development
Machine Learning & AI
Game Development
Data Science
Python is open-source, easy to learn, and has a vast collection of libraries that
make development faster and more efficient.
2. History of Python
Python was created by Guido van Rossum in the early 1990s while working at
CWI (Centrum Wiskunde & Informatica) in the Netherlands.
How Python was Created:
Guido and his team were developing a new operating system using the C
language but found it too complex.
During his break, he started working on a new language with simpler syntax
and more features.
Inspired by his favorite TV show, "Monty Python’s Flying Circus", he named
the language Python.
The Python logo was inspired by a snake, which is commonly associated with
the name "Python".
3. Why Do Computers Use Binary (0s and 1s)?
Computers process information using only binary values (0 and 1) because of the
way their hardware is designed.
Python Notes 3
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Key Components of a Computer:
1. Microprocessor (CPU)
2. RAM (Random Access Memory)
3. HDD (Hard Disk Drive) or SSD (Solid-State Drive)
How Computers Process Binary:
Microprocessors use billions of transistors that function as switches:
High voltage (ON) → Read as 1
Low voltage (OFF) → Read as 0
RAM uses capacitors:
Charged capacitor → 1
Uncharged capacitor → 0
HDD uses magnetic storage technology:
Magnetic patterns represent 1s and 0s
Why Do We Need RAM if We Have HDD?
RAM is volatile: Data is lost when power is turned off.
HDD is non-volatile: Data is retained even after shutdown.
Microprocessors access data from RAM, which is much faster than
accessing it from HDD.
Example: When you save a program, it is stored on the HDD. But when you run it,
a copy is loaded into RAM, allowing the processor to execute it quickly.
4. Machine-Level and High-Level Languages
Computers understand only binary (0s and 1s), known as Machine-Level
Language (MLL).
Evolution of Programming Languages:
Before 1950: Programs were written in Machine-Level Language (MLL).
Python Notes 4
c
o
d
e
r
s
n
o
t
e
.
c
o
m
After 1950: Assembly Language was introduced.
1957: IBM scientists developed High-Level Languages (HLL) like C and Java.
How Code is Converted:
Assembler: Converts Assembly Language into Machine Code.
Compiler: Converts High-Level Language (HLL) (e.g., C, Java) into Machine-
Level Language (MLL).
Interpreter: Python uses an interpreter instead of a compiler (to be discussed
in the next session).
Python is a High-Level Language (HLL) but differs from compiled languages
because it uses an interpreter, which executes code line by line.
Compiler Vs Interpreter
A compiler and an interpreter are both used to convert high-level programming
languages into machine code, but they work differently.
Compiler
Translates the entire source code into machine code before execution.
Generates an executable file that can be run multiple times without re-
compilation.
Faster execution since the entire program is compiled beforehand.
Example languages: C, C++, Java
Interpreter
Translates code line by line and executes it immediately.
Does not generate an executable file, requiring interpretation every time the
program runs.
Slower execution compared to compiled programs, but easier for debugging.
Example languages: Python, JavaScript
Python Notes 5
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Key Differences
Feature Compiler Interpreter
Execution Entire code at once Line-by-line
Speed Faster (pre-compilation) Slower (real-time execution)
Debugging
Harder (errors shown after
compilation)
Easier (stops at the first
error)
Output Generates an executable file No executable file
Example
Languages
C, C++, Java Python, JavaScript
Why Does Python Use an Interpreter?
Python prioritizes ease of development over execution speed.
Allows faster debugging since it executes code line-by-line.
More flexible and supports dynamic typing.
Installing Python
Installing Python on Windows, macOS, and Linux: Download Python
Setting up Python environment
Installing and using IDEs (Spyder, Notepad++, cmd, online editor)
Execute program in online Interpreter: Programiz Online Compiler
Installing Spyder IDE: Spyder IDE
Python Basics
Writing your first Python program: print("Hello world")
Python syntax and indentation
Single and multi-line comments in Python:
Single-line: # This is a comment
Multi-line: ''' This is a multi-line comment '''
Python Notes 6
c
o
d
e
r
s
n
o
t
e
.
c
o
m
2. Python Execution Modes
Interactive Mode: Executes code line by line in the Python shell.
Script Mode: Runs an entire Python script from a file.
Introduction to RAM Segments - Code, Heap, Stack
Note : Once you complete the course, read this RAM segment again for 100
percent clarity.
When a Python program runs, the memory is divided into different segments:
1. Code Segment (Text Segment)
Stores the compiled program instructions.
Contains the machine code that the CPU executes.
2. Heap Segment
Stores dynamically allocated memory (objects and variables created at
runtime).
Memory in this segment is managed by Python’s Garbage Collector.
Variables and objects remain in the heap as long as they are referenced.
3. Stack Segment
Stores function call frames and local variables.
Follows a Last In, First Out (LIFO) structure.
Each time a function is called, a new stack frame is pushed onto the stack.
When a function returns, its stack frame is removed (popped).
Understanding these memory segments helps in writing efficient programs and
debugging memory-related issues in Python.
Base 2 Format and Two’s Complement
Base 2 (Binary) Representation
Python Notes 7
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Numbers in computers are represented using Base 2 (binary), which consists of
only 0s and 1s .
Example:
Decimal 12 in binary: 1100
Decimal -12 needs Two’s Complement Representation.
Two’s Complement Representation
Two’s complement is a method for representing negative numbers in binary.
Steps to find Two’s Complement:
1. Write the binary representation of the positive number.
2. Take the One’s Complement (invert all bits).
3. Add 1 to the result.
Example: Finding 12 in two’s complement (using 8-bit representation):
1. 12 in binary (8-bit) → 00001100
2. One’s complement (invert bits) → 11110011
3. Add 1 → 11110100
Thus, -12 in two’s complement (8-bit) is: 11110100 .
This method allows simple binary arithmetic operations and is widely used in
computer systems.
Module 2: Variables, Data Types, and Input/Output
1. Variables
1. Creating and Assigning Variables
In Python, variables are created by simply assigning a value to a name using
the assignment operator = . You don’t need to declare the type of the variable
explicitly; Python will automatically determine it based on the value assigned.
Example:
Python Notes 8
c
o
d
e
r
s
n
o
t
e
.
c
o
m
x = 10 # Integer assignment
name = "Alice" # String assignment
pi = 3.14159 # Float assignment
Here, x is assigned the value 10 , name is assigned the string "Alice" , and pi is
assigned the floating-point value 3.14159 .
2. Variable Naming Conventions
There are several rules and best practices to follow when naming variables in
Python:
Rules:
Variable names must start with a letter (a-z, A-Z) or an underscore (_).
The rest of the variable name can include letters, numbers (0-9), and
underscores.
Variable names are case-sensitive ( name , Name , and NAME are all
different).
Reserved words (keywords) like if , else , True , False , and class cannot
be used as variable names.
Best Practices:
Use descriptive names that convey the purpose of the variable.
Use underscores ( _ ) to separate words in variable names
(snake_case).
Avoid using single-letter variables except for counters or temporary
variables (e.g., i , j ).
For constants, use all uppercase letters with underscores between
words.
Examples:
user_age = 25 # Descriptive variable name
max_speed = 120 # Descriptive name using snake_case
Python Notes 9
c
o
d
e
r
s
n
o
t
e
.
c
o
m
3. Constants in Python
In Python, constants are typically defined by convention. Although Python
does not have built-in support for constants like some other programming
languages, constants are usually written in all uppercase letters with
underscores to separate words. By convention, you should not modify the
value of constants after they are set.
Example:
PI = 3.14159 # Constant for Pi
MAX_USERS = 100 # Constant for max number of users
These variables are treated as constants by convention, and you should not
change their values within your code. However, Python won't stop you from
changing them; it's just a best practice to treat them as immutable.
Data Types
Numeric types: int , float , complex
Boolean type: bool
Sequence types: str , list , tuple
Mapping type: dict
Set types: set
1. Numeric Types: int , float , complex
int (Integer):
Description: Represents whole numbers (positive, negative, or zero).
Example:
a = 10 # Positive integer
Python Notes 10
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(a)
x = 10 # Positive integer
y = -3 # Negative integer
print(type(x)) # <class 'int'>
float (Floating-Point Number):
Description: Represents real numbers (numbers with a decimal point).
Example:
x = 10.5 # Positive float
y = -3.14 # Negative float
print(type(x)) # <class 'float'>
complex (Complex Number):
Description: Represents complex numbers in the form of a + bj , where a is the
real part and b is the imaginary part.
Example:
x = 3 + 5j # Complex number
print(type(x)) # <class 'complex'>
2. Boolean Type: bool
bool (Boolean):
Description: Represents True or False .
Example:
Python Notes 11
c
o
d
e
r
s
n
o
t
e
.
c
o
m
a = True
b = False
print(type(a)) # <class 'bool'>
3. Sequence Types: str , list , tuple
str (String):
Description: Represents text data.
Example:
name = "Alice"
print(type(name)) # <class 'str'>
list (List):
Description: A mutable, ordered collection of items (can be of different types).
Example:
fruits = ["apple", "banana", "cherry"]
print(type(fruits)) # <class 'list'>
tuple (Tuple):
Description: An immutable, ordered collection of items.
Example:
point = (2, 3)
print(type(point)) # <class 'tuple'>
4. Set Types: set
Python Notes 12
c
o
d
e
r
s
n
o
t
e
.
c
o
m
set (Set):
Description: A collection of unique, unordered items.
Example:
unique_numbers = {1, 2, 3, 4}
print(type(unique_numbers)) # <class 'set'>
5. Mapping Type: dict
dict (Dictionary):
Description: A collection of key-value pairs, where each key is unique.
Example:
student = {"name": "Alice", "age": 20}
print(type(student)) # <class 'dict'>
1. Type Conversion V7 - 3
Implicit and explicit type casting
Using functions like int() , float() , str() , list() , tuple()
1. Implicit Type Casting (Automatic Type Conversion)
Description: Implicit type casting happens automatically when Python
converts one data type to another without the user’s intervention. It occurs
when a smaller data type is converted into a larger one, for example,
converting an int to a float . Python does this automatically to prevent data
loss.
Example of Implicit Type Casting:
x = 5 # int
y = 2.5 # float
Python Notes 13
c
o
d
e
r
s
n
o
t
e
.
c
o
m
result = x + y # Python automatically converts x (int) to a float
print(result) # Output: 7.5
print(type(result)) # <class 'float'>
Here, x (an integer) is implicitly converted to a float to allow the addition with y (a
float). The result is a float .
2. Explicit Type Casting (Manual Type Conversion)
Description: Explicit type casting occurs when the user manually converts a
data type to another using built-in functions like int() , float() , str() , etc. This is
needed when you want to convert data types in a controlled way.
Example of Explicit Type Casting:
x = 10.5 # float
y = int(x) # manually converting float to int
print(y) # Output: 10
print(type(y)) # <class 'int'>
In this case, the float value of x is explicitly converted to an int using the int()
function. This process truncates the decimal part ( .5 ) and gives 10 as the result.
3. Type Conversion Functions
Below are some commonly used functions for type conversion in Python:
int() : Converts a value to an integer.
Description: Used to convert a number or a string representing a number to
an integer.
Example:
# Converting a float to int
x = 12.75
Python Notes 14
c
o
d
e
r
s
n
o
t
e
.
c
o
m
y = int(x) # Conversion from float to int
print(y) # Output: 12
# Converting a string to int
str_num = "45"
num = int(str_num)
print(num) # Output: 45
float() : Converts a value to a float.
Description: Used to convert an integer, string, or other numeric types to a
float.
Example:
# Converting an integer to float
x = 10
y = float(x) # Conversion from int to float
print(y) # Output: 10.0
# Converting a string to float
str_num = "3.14"
num = float(str_num)
print(num) # Output: 3.14
str() : Converts a value to a string.
Description: Used to convert numbers, lists, tuples, etc., into their string
representation.
Example:
# Converting an integer to string
x = 100
str_x = str(x) # Conversion from int to string
print(str_x) # Output: "100"
print(type(str_x)) # <class 'str'>
Python Notes 15
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Converting a float to string
pi = 3.14159
str_pi = str(pi)
print(str_pi) # Output: "3.14159"
list() : Converts an iterable (like a tuple or string) to a list.
Description: Converts any iterable object (such as a string or tuple) into a list.
Example:
# Converting a string to a list
str_data = "hello"
list_data = list(str_data)
print(list_data) # Output: ['h', 'e', 'l', 'l', 'o']
# Converting a tuple to a list
tuple_data = (1, 2, 3)
list_data = list(tuple_data)
print(list_data) # Output: [1, 2, 3]
tuple() : Converts an iterable (like a list or string) to a tuple.
Description: Converts any iterable object (such as a list or string) into a tuple.
Example:
# Converting a list to a tuple
list_data = [1, 2, 3]
tuple_data = tuple(list_data)
print(tuple_data) # Output: (1, 2, 3)
# Converting a string to a tuple
str_data = "abc"
Python Notes 16
c
o
d
e
r
s
n
o
t
e
.
c
o
m
tuple_data = tuple(str_data)
print(tuple_data) # Output: ('a', 'b', 'c')
Example Program: Demonstrating Type Conversion
# Implicit and Explicit Type Casting Example
# Implicit Type Casting
x = 5 # int
y = 3.2 # float
result = x + y # implicit conversion of x (int) to float
print(result) # Output: 8.2
# Explicit Type Casting
z = "123" # string
num = int(z) # explicit conversion of string to int
print(num) # Output: 123
# Converting to float
float_num = float(num) # explicit conversion of int to float
print(float_num) # Output: 123.0
# Converting to string
str_num = str(float_num) # explicit conversion of float to string
print(str_num) # Output: "123.0"
Output:
8.2
123
123.0
123.0
Python Notes 17
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Key Takeaways:
Implicit Type Casting happens automatically when Python promotes smaller
data types to larger ones, such as from int to float .
Explicit Type Casting requires the use of functions like int() , float() , str() , etc.,
to manually convert between data types.
Functions like int() , float() , str() , list() , and tuple() are commonly used for
converting between different data types, depending on your need.
Input and Output
input() function
print() function
Formatting output using str.format()
Using f-strings (formatted string literals)
1. input() Function
Description: The input() function is used to take user input from the console in
Python. The input is always returned as a string, even if the user enters
numeric values.
Syntax:
input(prompt)
prompt : An optional string to display to the user as a prompt.
Example:
# Basic input example
name = input("Enter your name: ")
print("Hello, " + name + "!")
# Taking numeric input
Python Notes 18
c
o
d
e
r
s
n
o
t
e
.
c
o
m
age = input("Enter your age: ")
age = int(age) # Converting the input to an integer
print("Your age is:", age)
Output:
Enter your name: Harish
Hello, Harish!
Enter your age: 27
Your age is: 27
In this example, we used input() to get the user's name and age. The input is
taken as a string, and we converted the age input to an integer.
2. print() Function
Description: The print() function is used to display output on the screen.
Syntax:
print(*objects, sep=' ', end='n')
objects : The values to print.
sep : A string inserted between the objects (default is a space).
end : A string appended after the last object (default is a newline).
Example:
# Basic print example
print("Hello, World!") # Output: Hello, World!
# Print multiple items with custom separator
print("Hello", "World", sep=" - ") # Output: Hello - World
Python Notes 19
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Print with custom end
print("Hello", end=" ") # Output: Hello (without a newline)
print("World!") # Output: World!
Output:
Hello, World!
Hello - World
Hello World!
The print() function can take multiple arguments and print them with a
customizable separator and end character.
Key Takeaways:
input() is used to get input from the user (always returns a string).
print() displays output and can accept multiple arguments with custom
separators and line endings.
String Formatting in Python
Note: Video tutorial for format strings and f-strings in the strings topic—watch the
tutorial first, or else you won’t be able to understand.
Python provides several ways to format strings. Two popular methods for string
formatting are str.format() and f-strings (formatted string literals).
1. Using str.format()
The str.format() method allows you to embed variables or expressions inside a string
by using placeholders (curly braces {} ). You can then pass values to be formatted
into the string.
Basic Usage
name = "Alice"
age = 25
Python Notes 20
c
o
d
e
r
s
n
o
t
e
.
c
o
m
message = "My name is {} and I am {} years old.".format(name, age)
print(message) # Output: My name is Alice and I am 25 years old.
Positional Arguments
You can specify the order of placeholders in the string, and match them with
arguments passed to format() .
message = "My name is {0} and I am {1} years old. {0} is my first name.".form
at(name, age)
print(message) # Output: My name is Alice and I am 25 years old. Alice is my
first name.
Keyword Arguments
Instead of using positional arguments, you can use keyword arguments to specify
the placeholders.
message = "My name is {name} and I am {age} years old.".format(name="Alic
e", age=25)
print(message) # Output: My name is Alice and I am 25 years old.
Reusing Variables
You can reuse variables multiple times in the format string.
message = "My name is {0} and {0} loves coding.".format(name)
print(message) # Output: My name is Alice and Alice loves coding.
Formatting Numbers
You can format numbers with specific formatting instructions (e.g., rounding,
padding).
pi = 3.14159
formatted = "Pi to two decimal places: {:.2f}".format(pi)
Python Notes 21
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(formatted) # Output: Pi to two decimal places: 3.14
2. f-Strings (Formatted String Literals)
Introduced in Python 3.6, f-strings provide a concise and more readable way to
embed expressions inside string literals.
An f-string is prefixed with f before the string, and you can directly embed
variables or expressions inside curly braces {} within the string.
Basic Usage
name = "Alice"
age = 25
message = f"My name is {name} and I am {age} years old."
print(message) # Output: My name is Alice and I am 25 years old.
Expressions Inside f-strings
You can use expressions within the curly braces inside an f-string.
a = 5
b = 10
message = f"The sum of {a} and {b} is {a + b}."
print(message) # Output: The sum of 5 and 10 is 15.
Formatting Numbers
Just like with str.format() , f-strings also support formatting options.
pi = 3.14159
formatted = f"Pi to two decimal places: {pi:.2f}"
print(formatted) # Output: Pi to two decimal places: 3.14
Using Expressions for Method Calls or Accessing Attributes
You can call methods or access attributes directly within f-strings.
Python Notes 22
c
o
d
e
r
s
n
o
t
e
.
c
o
m
text = "hello world"
message = f"The uppercase version of the text is {text.upper()}"
print(message) # Output: The uppercase version of the text is HELLO WORLD
Comparison: str.format() vs f-strings
Feature str.format() f-strings
Syntax "{} or {0} , {name} f"{}"
Readability More verbose More concise and readable
Performance Slightly slower
Faster and more efficient (since it is
evaluated at runtime)
Use of Expressions
Expressions are passed as
arguments
Directly evaluates expressions inside
{}
Python Version
Requirement
Works in Python 2.7 and
later
Works only in Python 3.6 and later
Both str.format() and f-strings allow you to embed variables and expressions inside
strings. However, f-strings are more concise and efficient, making them the
preferred choice in Python 3.6 and later. If you need to support older versions of
Python, str.format() is a great alternative.
Module 3: Operators and Expressions
1. Arithmetic Operators
Addition ( + ), subtraction ( ), multiplication ( ), division ( / )
Floor division ( // ), modulus ( % ), exponentiation ( * )
1. Arithmetic Operators in Python
Python provides several operators to perform arithmetic operations. These
include basic operations like addition and multiplication, as well as more
advanced operations such as floor division, modulus, and exponentiation.
Python Notes 23
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Basic Arithmetic Operators:
Addition ( + ): Adds two numbers.
Subtraction ( ): Subtracts one number from another.
Multiplication ( ): Multiplies two numbers.
Division ( / ): Divides one number by another and returns a floating-point
result.
Advanced Arithmetic Operators:
Floor Division ( // ): Divides one number by another and returns the
quotient as an integer (rounded down to the nearest whole number).
Modulus ( % ): Returns the remainder after dividing two numbers.
2. Examples of Arithmetic Operations
Let’s go over each operator with examples to understand how they work:
Addition ( + ):
Adds two numbers together.
a = 10
b = 5
result = a + b
print(result) # Output: 15
Subtraction ( ):
Subtracts the second number from the first.
a = 10
b = 5
result = a - b
print(result) # Output: 5
Python Notes 24
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Multiplication ( ):
Multiplies two numbers.
a = 10
b = 5
result = a * b
print(result) # Output: 50
Division ( / ):
Divides the first number by the second, and the result is always a float.
a = 10
b = 3
result = a / b
print(result) # Output: 3.3333333333333335 (float)
Floor Division ( // ):
Divides the first number by the second and returns the quotient rounded down
to the nearest integer.
a = 10
b = 3
result = a // b
print(result) # Output: 3 (rounded down from 3.333)
Modulus ( % ):
Returns the remainder of the division.
a = 10
b = 3
result = a % b
print(result) # Output: 1 (because 10 divided by 3 leaves a remainder of 1)
Python Notes 25
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Exponentiation ( * ):
Raises the first number to the power of the second.
a = 2
b = 3
result = a ** b
print(result) # Output: 8 (2 raised to the power of 3)
4. Summary of Arithmetic Operators
Operator Description Example
+ Addition (adds two numbers) 5 + 3 = 8
- Subtraction (subtracts second number from first) 5 - 3 = 2
* Multiplication (multiplies two numbers) 5 * 3 = 15
/ Division (returns float result) 5 / 3 = 1.6667
// Floor Division (returns integer quotient) 5 // 3 = 1
% Modulus (returns remainder of division) 5 % 3 = 2
**
Exponentiation (raises the first number to the
power of the second)
5 ** 3 = 125
Key Takeaways:
Arithmetic operators are fundamental to working with numerical values in
Python.
Basic operations such as addition, subtraction, multiplication, and division
are straightforward.
Advanced operations like floor division, modulus, and exponentiation
provide useful tools for mathematical calculations.
You can combine these operators in complex expressions to perform a
wide range of calculations.
Comparison Operators
Python Notes 26
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Equal to ( == ), not equal to ( != ), greater than ( > ), less than ( < ), greater than
or equal to ( >= ), less than or equal to ( <= )
Comparison Operators in Python
Comparison operators are used to compare two values or variables. These
operators return a Boolean value ( True or False ), indicating the result of the
comparison.
1. Equal to ( == )
Description: Compares if two values are equal.
Example:
a = 10
b = 10
result = (a == b) # Returns True if a equals b
print(result) # Output: True
2. Not equal to ( != )
Description: Compares if two values are not equal.
Example:
a = 10
b = 5
result = (a != b) # Returns True if a is not equal to b
print(result) # Output: True
3. Greater than ( > )
Description: Checks if the value on the left is greater than the value on the
right.
Example:
Python Notes 27
c
o
d
e
r
s
n
o
t
e
.
c
o
m
a = 10
b = 5
result = (a > b) # Returns True if a is greater than b
print(result) # Output: True
4. Less than ( < )
Description: Checks if the value on the left is less than the value on the right.
Example:
a = 5
b = 10
result = (a < b) # Returns True if a is less than b
print(result) # Output: True
5. Greater than or equal to ( >= )
Description: Checks if the value on the left is greater than or equal to the
value on the right.
Example:
a = 10
b = 5
result = (a >= b) # Returns True if a is greater than or equal to b
print(result) # Output: True
6. Less than or equal to ( <= )
Description: Checks if the value on the left is less than or equal to the value
on the right.
Example:
Python Notes 28
c
o
d
e
r
s
n
o
t
e
.
c
o
m
a = 5
b = 10
result = (a <= b) # Returns True if a is less than or equal to b
print(result) # Output: True
Summary of Comparison Operators
Operator Description Example
== Equal to (checks if two values are equal) a == b
!= Not equal to (checks if two values are not equal) a != b
> Greater than (checks if left is greater than right) a > b
< Less than (checks if left is less than right) a < b
>=
Greater than or equal to (checks if left is greater than or
equal to right)
a >= b
<=
Less than or equal to (checks if left is less than or equal
to right)
a <= b
Key Takeaways:
Comparison operators are essential for conditional checks and decision-
making.
These operators return Boolean values ( True or False ), which are used in
control structures like if , while , etc.
You can chain comparison operators together to create complex conditions.
Logical Operators
and , or , not
Logical Operators in Python
Logical operators are used to perform logical operations on Boolean values (i.e.,
True or False ). They are commonly used in conditional statements to combine
Python Notes 29
c
o
d
e
r
s
n
o
t
e
.
c
o
m
multiple conditions.
1. and Operator
Description: The and operator returns True if both conditions are True . If
either or both conditions are False , the result will be False .
Syntax: condition1 and condition2
Example:
a = 5
b = 10
# Both conditions must be True
result = (a > 0) and (b > 0)
print(result) # Output: True (both conditions are True)
result = (a > 0) and (b < 0)
print(result) # Output: False (second condition is False)
2. or Operator
Description: The or operator returns True if at least one of the conditions is
True . If both conditions are False , the result will be False .
Syntax: condition1 or condition2
Example:
a = 5
b = -10
# At least one condition must be True
result = (a > 0) or (b > 0)
print(result) # Output: True (first condition is True)
Python Notes 30
c
o
d
e
r
s
n
o
t
e
.
c
o
m
result = (a < 0) or (b > 0)
print(result) # Output: False (both conditions are False)
3. not Operator
Description: The not operator is used to invert a Boolean value. It returns True
if the condition is False , and False if the condition is True .
Syntax: not condition
Example:
a = 5
b = -10
# Inverts the result of the condition
result = not (a > 0)
print(result) # Output: False (because a > 0 is True, so not True is False)
result = not (b > 0)
print(result) # Output: True (because b > 0 is False, so not False is True)
Truth Tables for Logical Operators
Here’s how the logical operators behave for all possible combinations of True and
False :
Condition 1 Condition 2
and (Condition1
and Condition2)
or (Condition1
or Condition2)
not (not
Condition1)
True True True True False
True False False True False
False True False True True
False False False False True
Summary of Logical Operators
Python Notes 31
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Operator Description Example
and Returns True if both conditions are True (a > 0) and (b > 0)
or Returns True if at least one condition is True (a > 0) or (b > 0)
not Inverts the Boolean value of a condition not (a > 0)
Key Takeaways:
Logical operators are essential for combining multiple conditions in if
statements or loops.
The and operator ensures all conditions must be true.
The or operator requires only one condition to be true.
The not operator inverts the result of a condition.
Assignment Operators
Basic: = , += , = , = , /= , //= , %= , *=
1. Basic Assignment ( = )
Description: The simplest form of assignment. It assigns the value on the right
to the variable on the left.
Syntax: variable = value
Example:
a = 5
print(a) # Output: 5
2. Addition Assignment ( += )
Description: Adds the value on the right to the variable on the left and assigns
the result back to the variable.
Python Notes 32
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Syntax: variable += value
Example:
a = 5
a += 3 # equivalent to a = a + 3
print(a) # Output: 8
3. Subtraction Assignment ( = )
Description: Subtracts the value on the right from the variable on the left and
assigns the result back to the variable.
Syntax: variable -= value
Example:
a = 10
a -= 4 # equivalent to a = a - 4
print(a) # Output: 6
4. Multiplication Assignment ( = )
Description: Multiplies the variable by the value on the right and assigns the
result back to the variable.
Syntax: variable *= value
Example:
a = 6
a *= 2 # equivalent to a = a * 2
print(a) # Output: 12
5. Division Assignment ( /= )
Python Notes 33
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Description: Divides the variable by the value on the right and assigns the
result back to the variable. The result is always a float, even if both operands
are integers.
Syntax: variable /= value
Example:
a = 10
a /= 2 # equivalent to a = a / 2
print(a) # Output: 5.0
6. Floor Division Assignment ( //= )
Description: Divides the variable by the value on the right using floor division
(returns the integer part of the quotient) and assigns the result back to the
variable.
Syntax: variable //= value
Example:
a = 10
a //= 3 # equivalent to a = a // 3
print(a) # Output: 3
7. Modulus Assignment ( %= )
Description: Takes the modulus (remainder) of the variable when divided by
the value on the right and assigns the result back to the variable.
Syntax: variable %= value
Example:
a = 10
a %= 3 # equivalent to a = a % 3
Python Notes 34
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(a) # Output: 1
8. Exponentiation Assignment ( *= )
Description: Raises the variable to the power of the value on the right and
assigns the result back to the variable.
Syntax: variable **= value
Example:
a = 2
a **= 3 # equivalent to a = a ** 3
print(a) # Output: 8
Summary of Assignment Operators
Operator Description Example Result
=
Assigns the value on the
right to the variable
a = 5 a = 5
+=
Adds the value on the right
to the variable
a += 3 (i.e., a = a
+ 3 )
Adds 3 to a
-=
Subtracts the value on the
right from the variable
a -= 2 (i.e., a = a -
2 )
Subtracts 2 from a
*=
Multiplies the variable by the
value on the right
a *= 4 (i.e., a = a *
4 )
Multiplies a by 4
/=
Divides the variable by the
value on the right
a /= 2 (i.e., a = a /
2 )
Divides a by 2,
result is float
//=
Performs floor division and
assigns the result
a //= 2 (i.e., a = a
// 2 )
Performs floor
division
%=
Assigns the remainder of the
division to the variable
a %= 3 (i.e., a = a
% 3 )
Stores remainder of
a / 3
**=
Raises the variable to the
power of the value
a **= 2 (i.e., a = a
** 2 )
Raises a to the
power of 2
Python Notes 35
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example Program Using Assignment Operators
# Initial value of a
a = 10
# Using different assignment operators
a += 5 # a = a + 5
print(f"a after += 5: {a}") # Output: 15
a -= 3 # a = a - 3
print(f"a after -= 3: {a}") # Output: 12
a *= 2 # a = a * 2
print(f"a after *= 2: {a}") # Output: 24
a /= 4 # a = a / 4
print(f"a after /= 4: {a}") # Output: 6.0
a //= 2 # a = a // 2 (floor division)
print(f"a after //= 2: {a}") # Output: 3.0
a %= 2 # a = a % 2 (remainder)
print(f"a after %= 2: {a}") # Output: 1.0
a **= 3 # a = a ** 3 (exponentiation)
print(f"a after **= 3: {a}") # Output: 1.0
Key Takeaways:
Assignment operators simplify modifying variables in Python, making your
code more concise.
These operators help to combine assignment and arithmetic or other
operations in a single step.
Python Notes 36
c
o
d
e
r
s
n
o
t
e
.
c
o
m
The += , = , = , /= , //= , %= and *= operators are especially useful when
working with numbers.
Module 4: Control Flow
1. Conditional Statements
if statement
if-else statement
if-elif-else statement
Nested if statements
Conditional Statements in Python
In Python, conditional statements allow you to execute different blocks of
code depending on certain conditions. This is how your program can make
decisions based on specific inputs or states.
1. if Statement
The if statement evaluates a condition (a boolean expression) and executes a
block of code if the condition is True .
Syntax:
if condition:
# Code block to execute if condition is True
Example:
age = 18
if age >= 18:
print("You are eligible to vote!")
Python Notes 37
c
o
d
e
r
s
n
o
t
e
.
c
o
m
In this example, the condition age >= 18 is True , so the message "You are
eligible to vote!" will be printed.
2. if-else Statement
An if-else statement provides an alternative action if the condition is False . It
has two code blocks: one that is executed if the condition is True , and the
other if the condition is False .
Syntax:
if condition:
# Code block to execute if condition is True
else:
# Code block to execute if condition is False
Example:
age = 16
if age >= 18:
print("You are eligible to vote!")
else:
print("You are not eligible to vote yet.")
In this case, since the condition age >= 18 is False , the else block will be
executed, and the message "You are not eligible to vote yet." will be printed.
3. if-elif-else Statement
The if-elif-else statement allows you to check multiple conditions. The program
will evaluate the conditions in order and execute the block of code for the first
True condition. If none of the conditions are True , the else block will be
executed.
Syntax:
Python Notes 38
c
o
d
e
r
s
n
o
t
e
.
c
o
m
if condition1:
# Code block for condition1
elif condition2:
# Code block for condition2
else:
# Code block if no conditions are True
Example:
age = 25
if age >= 60:
print("You are a senior citizen.")
elif age >= 18:
print("You are an adult.")
else:
print("You are a minor.")
Here, since age is 25 , the condition age >= 18 is True , so the program will print
"You are an adult."
4. Nested if Statements
You can place one if statement inside another to check additional conditions
only after the outer condition is True . This is called nesting.
Syntax:
if condition1:
if condition2:
# Code block if both conditions are True
else:
# Code block if condition1 is True and condition2 is False
Python Notes 39
c
o
d
e
r
s
n
o
t
e
.
c
o
m
else:
# Code block if condition1 is False
Example:
# Program to check if a number is positive, and if it's even or odd
number = int(input("Enter a number: "))
if number > 0: # Outer if
print("The number is positive.")
if number % 2 == 0: # Nested if
print("It is also an even number.")
else: # Nested else
print("It is an odd number.")
else: # Outer else
print("The number is not positive.")
In this example:
The first if checks if the person is 18 or older.
If the person is eligible to vote ( age >= 18 ), it checks if they have a voter ID
with a nested if statement.
If the person doesn't have a voter ID, the second else block prints a
message saying they cannot vote.
Summary of Conditional Statements:
1. if Statement: Executes code if the condition is True .
2. if-else Statement: Executes one block of code if the condition is True ,
otherwise executes another block if False .
3. if-elif-else Statement: Checks multiple conditions in sequence and executes
the block for the first True condition. If no conditions are True , the else
block is executed.
Python Notes 40
c
o
d
e
r
s
n
o
t
e
.
c
o
m
4. Nested if Statements: Placing if statements inside other if statements to
check additional conditions.
Loops
for loop
Iterating over sequences
Using range() function
for Loop in Python
A for loop in Python is used to iterate over a sequence (like a list, tuple, string,
or range) and execute a block of code multiple times. It is commonly used
when you want to iterate through each item in a collection.
1. Iterating Over Sequences
A sequence can be a list, tuple, string, or any other iterable object. The for
loop will iterate over each element of the sequence and execute the block of
code for each element.
Syntax:
for variable in sequence:
# Code block to execute for each item in the sequence
Example (Iterating over a list):
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
Output:
Python Notes 41
c
o
d
e
r
s
n
o
t
e
.
c
o
m
apple
banana
cherry
In this example, the loop iterates over each element in the list fruits , and the
print(fruit) statement is executed for each element.
Example (Iterating over a string):
word = "hello"
for char in word:
print(char)
Output:
h
e
l
l
o
In this example, the loop iterates over each character in the string "hello" ,
printing each character one by one.
2. Using range() Function
The range() function is commonly used with for loops to generate a sequence
of numbers. It can be used to specify the number of iterations you want the
loop to execute. The range() function can take one, two, or three arguments:
range(stop) : Generates numbers from 0 to stop - 1 .
range(start, stop) : Generates numbers from start to stop - 1 .
range(start, stop, step) : Generates numbers from start to stop - 1 , with a step size
of step .
Python Notes 42
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example (Using range() with one argument):
for i in range(5): # Will iterate over 0, 1, 2, 3, 4
print(i)
Output:
0
1
2
3
4
In this example, range(5) generates the numbers from 0 to 4 , and the loop
prints each number.
Example (Using range() with two arguments):
for i in range(2, 7): # Will iterate over 2, 3, 4, 5, 6
print(i)
Output:
2
3
4
5
6
In this example, range(2, 7) generates the numbers from 2 to 6 , and the loop
prints each number.
Example (Using range() with three arguments):
for i in range(1, 10, 2): # Will iterate over 1, 3, 5, 7, 9
Python Notes 43
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(i)
Output:
1
3
5
7
9
In this example, range(1, 10, 2) generates numbers from 1 to 9 with a step size of
2 , and the loop prints each number.
Combining for Loop and range()
You can use the range() function inside a for loop to repeat a block of code a
specific number of times. This is useful when you want to perform actions a
certain number of times without explicitly creating a sequence.
Example (Using for loop with range() to repeat actions):
for i in range(3):
print(f"Iteration {i + 1}")
Output:
Iteration 1
Iteration 2
Iteration 3
Summary of for Loop Concepts:
1. Iterating Over Sequences: The for loop can be used to iterate over any
iterable object (list, string, tuple, etc.).
2. Using range() :
Python Notes 44
c
o
d
e
r
s
n
o
t
e
.
c
o
m
range(stop) generates numbers from 0 to stop - 1 .
range(start, stop) generates numbers from start to stop - 1 .
range(start, stop, step) generates numbers with a specific step size.
3. Use Cases:
Iterating over items in a collection.
Repeating a block of code a specific number of times using range() .
while loop
Loop conditions and infinite loops
Loop control statements:
break
continue
pass
while Loop in Python
A while loop in Python repeatedly executes a block of code as long as a given
condition is True . Once the condition becomes False , the loop stops.
1. Loop Conditions in while Loop
The while loop continues to execute the code inside it as long as the condition
evaluates to True . Once the condition becomes False , the loop stops, and the
program proceeds to the next line of code after the loop.
Syntax:
while condition:
# Code block
The condition is checked at the start of each iteration.
Python Notes 45
c
o
d
e
r
s
n
o
t
e
.
c
o
m
If the condition evaluates to True , the loop continues.
If the condition evaluates to False , the loop ends.
Example:
count = 0
while count < 3:
print(count)
count += 1
Output:
0
1
2
In this example, the while loop runs as long as count < 3 . After each iteration, the
value of count is incremented, and when it reaches 3 , the condition becomes
False , and the loop stops.
2. Infinite Loops
An infinite loop occurs when the condition in the while loop is always True ,
meaning the loop will run forever unless manually stopped. These are often
unintended and can cause the program to freeze or crash.
Example (Infinite loop):
while True:
print("This will run forever!")
Output (Continuously printing):
This will run forever!
This will run forever!
Python Notes 46
c
o
d
e
r
s
n
o
t
e
.
c
o
m
This will run forever!
...
To stop this infinite loop, you would either manually stop the program (using
Ctrl + C ), or the program must have a control structure like break to stop it under
certain conditions.
Loop Control Statements
Loop control statements are used to control the flow of execution in loops.
They allow you to skip iterations, break out of the loop, or execute certain
code under specific conditions.
1. break Statement
The break statement is used to terminate the loop immediately, regardless of
the loop's condition. It can be used in both for and while loops. When the break
statement is executed, the loop stops, and the program moves on to the next
statement after the loop.
Example (Using break ):
count = 0
while count < 10:
if count == 5:
break # Exit the loop when count is 5
print(count)
count += 1
Output:
0
1
2
3
4
Python Notes 47
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Prime Number
n = 6
for i in range(2,n+1):
if n%i==0:
break
if n==i:
print(n , "is prime")
else:
print(n , "is not prime")
In this example, the loop will stop when count becomes 5 because of the break
statement. It immediately exits the loop, and the program continues to the next
line after the loop.
2. continue Statement
The continue statement is used to skip the current iteration and move on to the
next iteration of the loop. It does not terminate the loop; instead, it skips over
the remaining code in the current iteration and proceeds with the next loop
cycle.
Example (Using continue ):
count = 0
while count < 5:
count += 1
if count == 3:
continue # Skip printing when count is 3
print(count)
Output:
Python Notes 48
c
o
d
e
r
s
n
o
t
e
.
c
o
m
1
2
4
5
In this example, when count equals 3 , the continue statement is executed, and
the print(count) statement is skipped for that iteration. The loop then moves on to
the next value of count .
3. pass Statement
The pass statement is a null operation. It is used as a placeholder when you
need a syntactically valid statement but don’t want to execute any code. It is
often used in loops, functions, or classes where the code is yet to be
implemented.
Example (Using pass ):
count = 0
while count < 5:
count += 1
if count == 3:
pass # Do nothing when count is 3
print(count)
Output:
1
2
3
4
5
In this example, when count equals 3 , the pass statement does nothing, and
the loop continues as normal. The pass statement is often used as a
Python Notes 49
c
o
d
e
r
s
n
o
t
e
.
c
o
m
placeholder for future code.
Summary of Loop Control Statements:
1. break : Terminates the loop immediately, even if the loop condition is still
True .
Example: if count == 5: break
2. continue : Skips the rest of the code in the current iteration and moves to the
next iteration.
Example: if count == 3: continue
3. pass : A null operation, used as a placeholder when no action is needed.
Example: if count == 3: pass
Combining while Loop with Loop Control Statements
You can use break , continue , and pass in a while loop to control its flow based on
certain conditions.
Example (Combining while , break , and continue ): V7-9, V7-
9-1
count = 0
while count < 10:
count += 1
if count == 3:
continue # Skip printing 3
if count == 8:
break # Exit the loop when count is 8
print(count)
Output:
1
2
Python Notes 50
c
o
d
e
r
s
n
o
t
e
.
c
o
m
4
5
6
7
In this example:
The loop skips 3 due to the continue statement.
The loop exits when count reaches 8 due to the break statement.
String Replication in Python
String replication is a technique in Python that allows a string to be repeated
multiple times using the * operator.
Syntax:
string * n
Where:
string is the original text.
n is the number of times the string should be repeated.
Example:
text = "Hello "
print(text * 3)
Output:
Hello Hello Hello
Use Cases of String Replication:
Creating text patterns:
Python Notes 51
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print("-" * 30)
Formatting output:
print("=" * 20 + " TITLE " + "=" * 20)
Repeating characters or words efficiently.
String replication is a simple and efficient way to generate repeated text without
using loops or extra variables.
Interview-Focused Star, Number, and Alpha Pattern
Programs
These types of pattern problems are commonly asked in technical interviews,
especially for freshers. Below, I’ll walk through a variety of examples of Star,
Number, and Alpha patterns that might appear in interview questions.
1. Star Pattern Programs
1.1 Right-Angled Triangle Star Pattern
Example:
*
**
***
****
*****
Code:
n = 5 # number of rows
for i in range(1, n+1):
print('*' * i)
Python Notes 52
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Explanation:
The number of stars increases with each row.
The loop runs from 1 to n , and in each iteration, the number of stars printed
is equal to the current row number.
1.2 Pyramid Star Pattern
Example:
*
***
*****
*******
*********
Code:
n = 5 # number of rows
for i in range(1, n+1):
print(' ' * (n - i) + '*' * (2*i - 1))
Explanation:
In this pattern, we print spaces followed by stars. The spaces decrease as the
row number increases, while the stars increase in the odd sequence.
1.3 Inverted Pyramid Star Pattern
Example:
*********
*******
*****
***
*
Python Notes 53
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Code:
n = 5 # number of rows
for i in range(n, 0, -1):
print(' ' * (n - i) + '*' * (2*i - 1))
Explanation:
This pattern is the reverse of the pyramid. Here, the number of stars
decreases as the row number increases.
2. Number Pattern Programs
2.1 Number Triangle Pattern
Example:
1
12
123
1234
12345
Code:
n = 5 # Number of rows
for i in range(1, n + 1): # Loop through rows
for x in range(1, i + 1): # Loop through numbers in each row
print(x, end="") # Print numbers on the same line
print() # Move to the next line after each row
Explanation:
The first row prints 1 , the second prints 12 , and so on, with each row having a
sequence of numbers from 1 to the row number.
2.2 Inverted Number Triangle
Python Notes 54
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example:
12345
1234
123
12
1
Code:
n = 5 # Number of rows
for i in range(n, 0, -1):
for x in range(1, i + 1): # Loop to print numbers in the current row
print(x,end=" ") # Print numbers without a newline
print() # Print a newline after each row
Explanation:
This pattern is the reverse of the previous one, starting from the highest
number sequence and decreasing the length of the sequence in each row.
11111
22222
33333
44444
55555
n = 5 # Number of rows
for i in range(1, n + 1):
for j in range(1, n + 1):
print(i, end="")
print()
Python Notes 55
c
o
d
e
r
s
n
o
t
e
.
c
o
m
2.3 Diamond Number Pattern
Example:
1
22
333
4444
55555
Code:
n = 5 # Number of rows
for i in range(1, n + 1):
for j in range(1, i+1):
print(i, end="")
print()
Explanation:
This pattern creates a diamond shape by combining ascending and
descending numbers symmetrically.
1
121
12321
1234321
123454321
n = 5 # Number of rows
for i in range(1, n + 1): i=2
# Print leading spaces
print(" " * (n - i), end="")
# Print increasing numbers
Python Notes 56
c
o
d
e
r
s
n
o
t
e
.
c
o
m
for j in range(1, i + 1): j=2
print(j, end="")
# Print decreasing numbers
for j in range(i - 1, 0, -1):
print(j, end="")
print()
3. Alpha Pattern Programs
3.1 Alphabet Triangle Pattern
Example:
A
AB
ABC
ABCD
ABCDE
Code:
n = 5 # number of rows
for i in range(1, n+1):
print(''.join(chr(65 + j) for j in range(i)))
Explanation:
The chr(65 + j) function returns characters starting from A (ASCII value 65).
The loop prints a sequence of characters from A to the i-th character for each
row.
n = 5 # Number of rows
for i in range(1, n + 1):
for j in range(1, n + 1):
Python Notes 57
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(chr(64+i), end="")
print()
AAAAA
BBBBB
CCCCC
DDDDD
EEEEE
3.2 Reverse Alphabet Triangle
Example:
ABCDE
ABCD
ABC
AB
A
Code:
n = 5 # number of rows
for i in range(n, 0, -1):
print(''.join(chr(65 + j) for j in range(i)))
Explanation:
This pattern reverses the previous one by decreasing the number of
characters printed on each row.
3.3 Pyramid of Alphabets
Example:
Python Notes 58
c
o
d
e
r
s
n
o
t
e
.
c
o
m
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
Code:
n = 5 # Number of rows
for i in range(1, n + 1): # Outer loop for each row
# Print leading spaces
print(" " * (n - i), end="")
# Print increasing letters
for j in range(1, i + 1):
print(chr(64 + j), end="") # Convert numbers to letters (A=65 in ASCII)
# Print decreasing letters
for j in range(i - 1, 0, -1):
print(chr(64 + j), end="") # Convert numbers to letters (A=65 in ASCII)
# Move to the next line after each row
print()
Explanation:
In this pattern, each row consists of an ascending sequence of letters followed
by a descending sequence to form the mirrored shape.
Tips for Interview Pattern Programs:
1. Understand the structure: Most patterns can be broken down into a
combination of spaces and symbols (like stars, numbers, or letters).
2. Use loops: Use for or while loops to control the number of rows and to print
each element in the pattern.
Python Notes 59
c
o
d
e
r
s
n
o
t
e
.
c
o
m
3. Manage spaces: Often, patterns require precise handling of spaces (like in
pyramids), so manage the spaces carefully.
4. Practice logic: If you're stuck, focus on how the pattern changes from one
row to the next.
Module 5: Functions
1. Defining Functions
def keyword
User-defined functions (without Input without return, without input with
return, with input without return, with input with return)
Function parameters and arguments - (Positional, Keyword, Default,
Variable Length, Variable Length Keyword)
def add():
num1 = int(input("Enter the first number for addition: "))
num2 = int(input("Enter the second number for addition: "))
num3 = num1 + num2
print("Addition result:", num3)
# Function to multiply two numbers
def multiply():
num1 = int(input("Enter the first number for multiplication: "))
num2 = int(input("Enter the second number for multiplication: "))
num3 = num1 * num2
print("Multiplication result:", num3)
# Calling the functions
add()
multiply()
Python Functions Overview
Python Notes 60
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Functions in Python are defined using the def keyword. Functions are a way to
group related tasks together, allowing you to execute blocks of code multiple
times without repeating yourself. Functions can take inputs (parameters) and
can return outputs. There are various types of functions based on input and
output, and parameters can be specified in different ways.
1. def Keyword
The def keyword is used to define a function in Python. After def , the function
name is followed by parentheses () (with optional parameters) and a colon : .
The body of the function contains the code block that defines its behavior.
Syntax:
def function_name(parameters):
# code block
return value
2. User-defined Functions
User-defined functions can have different combinations of input and return
values.
2.1 Function without Input and without Return
This is the simplest form of a function that neither accepts any arguments nor
returns any value.
Example:
def greet():
print("Hello, welcome to the Python world!")
# Calling the function
greet()
Explanation: The function greet() doesn't take any input or return any output. It
simply prints a message when called.
Python Notes 61
c
o
d
e
r
s
n
o
t
e
.
c
o
m
2.2 Function without Input but with Return
A function can perform some operation and return a result without taking any
input.
Example:
def get_greeting():
return "Hello, welcome to Python!"
# Calling the function
greeting = get_greeting()
print(greeting)
Explanation: The function get_greeting() doesn't take any parameters but returns
a string that can be stored in a variable and printed.
2.3 Function with Input but without Return
This function takes input but doesn't return anything. It usually modifies some
external state or performs an action using the input.
Example:
def greet_user(name):
print(f"Hello, {name}!")
# Calling the function
greet_user("Alice")
Explanation: The function greet_user() takes name as an argument and prints a
greeting message. It doesn't return anything but performs an action (printing).
2.4 Function with Input and Return
This is the most common type of function that takes input, processes it, and
returns a result.
Example:
Python Notes 62
c
o
d
e
r
s
n
o
t
e
.
c
o
m
def add_numbers(a, b):
return a + b
# Calling the function
result = add_numbers(5, 3)
print(result) # Output: 8
Explanation: The function add_numbers() takes two arguments ( a and b ), adds
them, and returns the result.
3. Function Parameters and Arguments
Python allows several types of parameters and arguments. Here’s a
breakdown:
3.1 Positional Parameters
These parameters are assigned based on the order in which they are passed
when calling the function. The first argument is assigned to the first
parameter, the second argument to the second parameter, and so on.
Example:
def subtract(a, b):
return a - b
result = subtract(10, 3) # 10 is assigned to 'a' and 3 to 'b'
print(result) # Output: 7
Explanation: The arguments are assigned to parameters based on their
position in the function call.
3.2 Keyword Parameters
Keyword parameters are passed to the function by explicitly naming the
parameter during the function call. This allows passing arguments in any
order.
Python Notes 63
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example:
def display_info(name, age):
print(f"Name: {name}, Age: {age}")
# Using keyword arguments
display_info(age=25, name="John")
Explanation: By using keyword arguments, we can pass arguments in any
order. The names of the parameters are used to map the values.
3.3 Default Parameters
Default parameters are those that have default values assigned in the function
definition. These parameters are optional when calling the function. If no value
is passed, the default value is used.
Example:
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
# Calling the function with and without default parameter
greet("Alice") # Uses default greeting "Hello"
greet("Bob", "Hi") # Custom greeting
Explanation: The function greet() uses "Hello" as the default greeting if no
greeting is provided during the function call.
3.4 Variable Length Parameters (Arbitrary Arguments)
You can use *args to pass a variable number of positional arguments to a
function. args is a tuple that stores all the arguments passed.
Example:
def sum_numbers(*args):
return sum(args)
Python Notes 64
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Calling the function
result = sum_numbers(1, 2, 3, 4, 5)
print(result) # Output: 15
Explanation: The function sum_numbers() accepts a variable number of
arguments and calculates their sum.
3.5 Variable Length Keyword Parameters (Arbitrary Keyword
Arguments)
for key, value in kwargs.items():
print(f"{key}: {value}")
# Calling the function
display_info(name="John", age=30, occupation="Engineer")
Explanation: The function display_info() accepts an arbitrary number of keyword
arguments (passed as a dictionary). The function then loops through the
dictionary to print each key-value pair.
4. Combining Different Types of Parameters
You can combine positional, keyword, default, and variable-length arguments
in a single function. However, the order of parameters must be maintained as
follows:
1. Positional arguments (e.g., a, b )
2. Default arguments (e.g., greeting="Hello" )
3. Variable-length positional arguments (e.g., args )
4. Variable-length keyword arguments (e.g., *kwargs )
Example:
def complex_function(a, b=5, *args, **kwargs):
print(f"a: {a}, b: {b}")
Python Notes 65
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print("Additional positional arguments:", args)
print("Keyword arguments:", kwargs)
# Calling the function
complex_function(10, 20, 30, 40, name="John", city="New York")
Explanation:
a is a positional argument.
b is a default argument with a default value of 5, but can be overridden.
args collects any additional positional arguments (30, 40 in this case).
*kwargs collects keyword arguments ( name and city ).
5. Recap and Best Practices for Functions
Functions are defined using the def keyword.
They can accept input through parameters and can return a value using
the return keyword.
Function parameters can be positional, keyword, or have default values.
You can pass a variable number of positional arguments using args and
keyword arguments using *kwargs .
Maintain clarity by using descriptive parameter names and comments in
your functions.
Local Variable, Global Variable, and global Keyword in Python
Local Variable
A local variable is a variable declared inside a function and is accessible only
within that function.
Example:
Python Notes 66
c
o
d
e
r
s
n
o
t
e
.
c
o
m
def my_function():
x = 10 # Local variable
print("Inside function:", x)
my_function()
# print(x) # This will cause an error because x is not accessible outside the fu
nction.
Key Points:
Defined inside a function.
Cannot be accessed outside the function.
Memory is allocated only during function execution.
Global Variable
A global variable is declared outside of a function and can be accessed by any
function in the program.
Example:
x = 20 # Global variable
def my_function():
print("Inside function:", x)
my_function()
print("Outside function:", x)
Key Points:
Defined outside a function.
Can be accessed inside functions.
Exists throughout the program's execution.
Python Notes 67
c
o
d
e
r
s
n
o
t
e
.
c
o
m
global Keyword
The global keyword allows modification of a global variable inside a function.
Example:
x = 30 # Global variable
def my_function():
global x
x = 50 # Modifying global variable inside function
print("Inside function:", x)
my_function()
print("Outside function:", x)
Key Points:
Used to modify global variables inside a function.
Without global , assigning a value to a global variable inside a function creates a
new local variable instead.
These concepts are essential for managing variable scope effectively in Python.
Types of Functions
Built-in functions: len() , sum() , max() , min() , abs() , round() , sorted()
Few Built-in Functions in Python
1. len()
The len() function is used to get the length (number of items) of an object, such as
a string, list, tuple, dictionary, etc.
Syntax:
len(object)
Python Notes 68
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example:
# Length of a string
text = "Hello"
print(len(text)) # Output: 5
# Length of a list
numbers = [1, 2, 3, 4]
print(len(numbers)) # Output: 4
Explanation:
len() returns the number of characters in a string or the number of elements in
a list, tuple, or dictionary.
2. sum()
The sum() function is used to sum all the elements of an iterable, such as a list or
tuple.
Syntax:
sum(iterable, start=0)
iterable : Any iterable (e.g., list, tuple) whose elements are numbers.
start : Optional. The value that is added to the sum (default is 0).
Example:
# Sum of a list of numbers
numbers = [1, 2, 3, 4]
print(sum(numbers)) # Output: 10
# Sum with a starting value
print(sum(numbers, 5)) # Output: 15
Explanation:
Python Notes 69
c
o
d
e
r
s
n
o
t
e
.
c
o
m
sum() adds up all the elements in the iterable. The optional start argument can
be used to add a value to the sum.
3. max()
The max() function returns the largest item in an iterable or the largest of two or
more arguments.
Syntax:
max(iterable, *args, key=None)
Example:
# Maximum value in a list
numbers = [1, 2, 3, 4, 5]
print(max(numbers)) # Output: 5
# Maximum of two values
print(max(10, 20)) # Output: 20
Explanation:
max() returns the highest value in the iterable. If multiple arguments are
passed, it returns the largest one.
You can also use the key parameter to specify a function to determine the
sorting criteria.
4. min()
The min() function returns the smallest item in an iterable or the smallest of two or
more arguments.
Syntax:
min(iterable, *args, key=None)
Example:
Python Notes 70
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Minimum value in a list
numbers = [1, 2, 3, 4, 5]
print(min(numbers)) # Output: 1
# Minimum of two values
print(min(10, 20)) # Output: 10
Explanation:
min() returns the lowest value in the iterable. If multiple arguments are passed,
it returns the smallest one.
Like max() , the key parameter can be used to determine the criteria for
comparison.
5. abs()
The abs() function returns the absolute value of a number, which is the non-
negative value of the number.
Syntax:
abs(x)
Example:
# Absolute value of a number
print(abs(-5)) # Output: 5
print(abs(5)) # Output: 5
Explanation:
abs() removes the negative sign from a number, giving you the magnitude
(absolute value).
6. round()
Python Notes 71
c
o
d
e
r
s
n
o
t
e
.
c
o
m
The round() function is used to round a floating-point number to a specified
number of decimal places.
Syntax:
round(number, digits=0)
number : The number to be rounded.
digits : Optional. The number of decimal places to round to (default is 0).
Example:
# Rounding a number
print(round(3.14159, 2)) # Output: 3.14
print(round(5.6789)) # Output: 6
Explanation:
round() rounds the given number to the specified number of decimal places. If
digits is omitted, it rounds to the nearest whole number.
7. sorted()
The sorted() function returns a sorted list of the specified iterable's elements.
Syntax:
sorted(iterable, key=None, reverse=False)
iterable : The iterable to be sorted (list, tuple, string, etc.).
key : Optional. A function to execute to decide the order. Default is None .
reverse : Optional. If True , the list is sorted in descending order. Default is False .
Example:
# Sorting a list
numbers = [5, 2, 9, 1]
print(sorted(numbers)) # Output: [1, 2, 5, 9]
Python Notes 72
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Sorting a string
word = "python"
print(sorted(word)) # Output: ['h', 'n', 'o', 'p', 't', 'y']
# Sorting in reverse order
print(sorted(numbers, reverse=True)) # Output: [9, 5, 2, 1]
Explanation:
sorted() returns a new list that is sorted, leaving the original iterable unchanged.
You can sort in reverse order or provide a custom sorting function using the
key parameter.
Summary of Built-in Functions
These built-in functions are commonly used for basic operations, such as getting
the length of an iterable, summing values, finding the maximum or minimum
values, and rounding numbers. Here’s a quick recap:
len() : Returns the number of items in an object.
sum() : Returns the sum of all elements in an iterable.
max() : Returns the maximum value from an iterable or among multiple
arguments.
min() : Returns the minimum value from an iterable or among multiple
arguments.
abs() : Returns the absolute value of a number.
round() : Rounds a number to a specified number of decimal places.
sorted() : Returns a sorted list of elements.
Modules and Packages
1. Modules
Python Notes 73
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Importing modules ( import , from ... import , as )
Exploring built-in modules like math , os , random , sys , time , datetime
Using dir() to inspect module contents
2. Packages
Introduction to Python packages
Creating and using packages
Importing from packages
1. Modules in Python
Modules are files containing Python code that can define functions, classes, and
variables, and also include runnable code. A module allows you to organize your
code logically. Python provides a rich set of built-in modules that can be used to
add extra functionality to your programs without writing everything from scratch.
Importing Modules
There are several ways to import modules into your Python program:
1.1 Importing an Entire Module
You can import an entire module using the import keyword.
Syntax:
import module_name
Example:
import math
# Using the sqrt function from the math module
print(math.sqrt(16)) # Output: 4.0
1.2 Importing Specific Functions or Variables from a Module
Python Notes 74
c
o
d
e
r
s
n
o
t
e
.
c
o
m
You can import specific functions or variables from a module using the from ... import
syntax.
Syntax:
from module_name import function_name
Example:
from math import pi
print(pi) # Output: 3.141592653589793
1.3 Importing a Module with an Alias
You can give a module or function an alias using the as keyword to make it easier
to refer to within your code.
Syntax:
import module_name as alias
Example:
import math as m
print(m.sqrt(25)) # Output: 5.0
1.4 Exploring Built-in Modules
Python provides many built-in modules for various tasks. Some common ones
include:
math : Provides mathematical functions (e.g., sqrt() , cos() , sin() , pi ).
os : Provides functions to interact with the operating system (e.g., file
operations, environment variables).
Python Notes 75
c
o
d
e
r
s
n
o
t
e
.
c
o
m
random : Provides functions for generating random numbers (e.g., randint() ,
choice() ).
sys : Provides access to system-specific parameters and functions (e.g.,
command-line arguments, exiting the program).
time : Provides time-related functions (e.g., sleep() , time() ).
datetime : Provides classes for manipulating dates and times (e.g., datetime() ,
date() ).
Example:
import os
import random
# Using os to get current working directory
print(os.getcwd())
# Using random to generate a random number
print(random.randint(1, 10))
1.5 Using dir() to Inspect Module Contents
The dir() function is used to find all the attributes and methods of an object,
including a module. It helps you explore what functions or classes are available
within the module.
Example:
import math
# Get a list of all available functions and attributes in the math module
print(dir(math))
2. Packages in Python
A package in Python is a collection of modules in a directory. A package allows
you to organize related modules into a structured hierarchy.
Python Notes 76
c
o
d
e
r
s
n
o
t
e
.
c
o
m
2.1 Introduction to Python Packages
A Python package is a directory that contains multiple Python files (modules).
Packages are often used for large projects to keep related modules together.
2.2 Creating and Using Packages
To create a package, you simply create a directory and add Python modules to it.
Directory Structure:
my_package/
module1.py
module2.py
2.3 Example of Creating and Using a Package
1. Create a directory called my_package .
2. Inside my_package , create two modules ( module1.py , module2.py ).
module1.py:
def greet(name):
return f"Hello, {name}!"
module2.py:
def farewell(name):
return f"Goodbye, {name}!"
1. Now, you can import the functions from these modules using the following
code:
# Importing the package
from my_package import module1, module2
# Calling functions from the modules
Python Notes 77
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(module1.greet("John")) # Output: Hello, John!
print(module2.farewell("John")) # Output: Goodbye, John!
2.4 Importing from Packages
You can import specific functions from modules in a package or import an entire
module.
Syntax:
from package_name.module_name import function_name
Example:
from my_package.module1 import greet
print(greet("Alice")) # Output: Hello, Alice!
Summary
Modules: Files containing Python code that define functions, classes, and
variables. You can import them using import , from ... import , and as .
Built-in Modules: Python provides many useful built-in modules such as math ,
os , random , sys , time , and datetime .
Packages: A collection of modules in a directory.
Creating Packages: You can create your own packages by organizing
modules into directories.
Importing from Packages: You can import modules or specific functions from
a package using the import syntax.
By using modules and packages, you can organize your code efficiently and reuse
functions and classes across different parts of your program.
Lambda functions (anonymous functions using
lambda keyword)
Python Notes 78
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Lambda Functions in Python
In Python, lambda functions are small anonymous functions that are defined
using the lambda keyword. These functions can have any number of arguments but
only one expression. The expression is evaluated and returned when the function
is called.
Syntax of Lambda Functions:
lambda arguments: expression
lambda is the keyword used to define the function.
arguments is a comma-separated list of input parameters.
expression is the expression that gets evaluated and returned by the function.
Key Characteristics of Lambda Functions:
They are anonymous, meaning they don’t have a name.
They are small, typically used for short, simple operations.
They can take any number of arguments, but only one expression.
They are generally used when you need a function for a short period and do
not want to formally define it with a def statement.
Examples of Lambda Functions:
1. Basic Lambda Function
# A simple lambda function that adds two numbers
add = lambda a, b: a + b
print(add(2, 3)) # Output: 5
2. Lambda Function with One Argument
Python Notes 79
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# A lambda function that squares the input number
square = lambda x: x ** 2
print(square(5)) # Output: 25
3. Lambda Function in a List V8-4
Lambda functions are often used with higher-order functions like map() , filter() , or
sorted() to operate on lists or other iterable objects.
from functools import reduce
# Function to add two numbers
def add(x, y):
return x + y
# List of numbers
numbers = [1, 2, 3, 4]
# Use reduce to sum the list
result = reduce(add, numbers)
# Print the result
print("Sum of the list:", result)
Example: Using map() to square a list of numbers:
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # Output: [1, 4, 9, 16, 25]
Example: Using filter() to get even numbers:
numbers = [1, 2, 3, 4, 5, 6, 7, 8]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
Python Notes 80
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(even_numbers) # Output: [2, 4, 6, 8]
Aspect map() filter()
reduce() (requires
functools )
Purpose
Transforms each
element in an
iterable using a
function.
Filters elements
based on a condition
(boolean function).
Reduces an iterable to a
single value by combining
elements.
Syntax map(function, iterable) filter(function, iterable)
reduce(function, iterable[,
initializer])
Input
Iterable and a
function to apply.
Iterable and a
function that returns
True / False .
Iterable and a function to
combine two elements.
Output
Transformed
iterable ( map
object).
Filtered iterable
( filter object).
A single cumulative value.
Function Type
Applies the function
to all elements.
Selects elements
where the function
returns True .
Combines elements
iteratively using the
function.
Use Case
When you need to
apply a
transformation to all
elements.
When you need to
include/exclude
elements based on a
condition.
When you need to
aggregate/summarize
values.
Example
map(lambda x: x * 2, [1,
2, 3]) → [2, 4, 6]
filter(lambda x: x % 2 ==
0, [1, 2, 3]) → [2]
reduce(lambda x, y: x + y, [1,
2, 3]) → 6
Returns
Iterator ( map
object).
Iterator ( filter
object).
Single cumulative value.
Module Built-in. Built-in. Requires functools .
4. Lambda Function with Sorting
Lambda functions are also useful when sorting lists with custom conditions.
Example: Sorting a list of tuples based on the second element:
Python Notes 81
c
o
d
e
r
s
n
o
t
e
.
c
o
m
pairs = [(1, 2), (3, 1), (5, 0)]
pairs_sorted = sorted(pairs, key=lambda x: x[1])
print(pairs_sorted) # Output: [(5, 0), (3, 1), (1, 2)]
When to Use Lambda Functions
Lambda functions are commonly used in situations where:
1. You need a small, simple function temporarily.
2. You don't want to formally define a full function using def .
3. You are passing a function as an argument to higher-order functions like map() ,
filter() , reduce() , etc.
4. You want to write short, readable code for operations that can be performed in
a single line.
Advantages of Lambda Functions:
Concise: Lambda functions are compact and can be written in a single line.
Anonymous: They are often used for short-term, single-use functions.
Functional Programming: They are used extensively in functional
programming approaches with functions like map() , filter() , and reduce() .
Limitations of Lambda Functions:
Limited to one expression: Lambda functions can only have one expression.
You can't use multiple expressions or statements like you can in regular
functions.
Not very readable for complex operations: For complex operations, lambda
functions can reduce readability and maintainability of the code.
Example with Multiple Arguments:
Python Notes 82
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# A lambda function that calculates the area of a rectangle
area = lambda length, width: length * width
print(area(5, 3)) # Output: 15
In conclusion, lambda functions are an efficient way to define small, one-off
functions in Python, especially when working with functional programming
features like map() , filter() , and sorted() .
Recursive Function? V8-6
A recursive function is a function that calls itself to solve smaller instances of a
problem. Recursion continues until it reaches a base case, which stops the
recursion.
Example: Factorial Calculation
Code:
# Recursive function to calculate factorial
def factorial(n):
if n == 1: # Base case
return 1
else:
return n * factorial(n - 1) # Recursive case
# Input from user
a = int(input("Enter a number: "))
print(factorial(a))
Example Output:
1. Input:
Enter a number: 5
Python Notes 83
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Output:
Factorial of 5 is: 120
2. Input:
Enter a number: 0
Output:
Factorial of 0 is: 1
Explanation:
1. Base Case ( if n == 0 ):
When , the function returns 1 to terminate recursion.
n=0n = 0
2. Recursive Case ( n * factorial(n - 1) ):
The function calls itself with until it reaches the base case.
n−1n-1
3. Step-by-Step Execution for factorial(5) :
5!=5×4!5! = 5 times 4!
4!=4×3!4! = 4 times 3!
3!=3×2!3! = 3 times 2!
2!=2×1!2! = 2 times 1!
1!=1×0!1! = 1 times 0!
0!=10! = 1 (base case)
Final Result:
5!=5×4×3×2×1=1205! = 5 times 4 times 3 times 2 times 1 = 120
Python Notes 84
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Another Example: Sum of Natural Numbers
# Recursive function to calculate sum of first n natural numbers
def sum_natural(n):
if n == 0: # Base case
return 0
else:
return n + sum_natural(n - 1) # Recursive case
# Input from user
number = int(input("Enter a number: "))
# Call the recursive function
if number >= 0:
print(f"Sum of first {number} natural numbers is: {sum_natural(number)}")
else:
print("Sum is not defined for negative numbers.")
Module 6: Data Structures
Lists
Creating lists
Accessing list elements using indexing
slicing
List methods: append() , extend() , insert() , pop() , remove() , index() , count() , sort() ,
reverse() , copy()
Nested list
Concatenation
Python Notes 85
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Define two lists
a = [10, 20, 30]
b = [40, 50, 60]
# Concatenate the lists
c = a + b
# Print the result
print(c)
Lists in Python
A list in Python is an ordered collection of items, which can be of any type. Lists
are mutable, meaning their elements can be modified after the list is created. They
are one of the most versatile data structures in Python, used frequently for a
variety of tasks.
1. Creating Lists
A list is created by placing items inside square brackets [] , separated by commas.
# Creating a list with integers
my_list = [1, 2, 3, 4, 5]
# Creating a list with different types of elements
mixed_list = [1, "hello", 3.14, True]
2. Accessing List Elements Using Indexing
List elements are accessed using indexing. Indexing in Python starts at 0 .
Negative indexing can be used to access elements from the end of the list.
# Accessing elements using positive index
my_list = [10, 20, 30, 40, 50]
print(my_list[0]) # Output: 10 (first element)
Python Notes 86
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(my_list[3]) # Output: 40 (fourth element)
# Accessing elements using negative index
print(my_list[-1]) # Output: 50 (last element)
print(my_list[-2]) # Output: 40 (second last element)
3. Slicing
Slicing allows you to access a range of elements from a list by specifying a start
index, an end index, and an optional step value.
# Slicing a list
my_list = [1, 2, 3, 4, 5, 6, 7, 8]
# Accessing elements from index 2 to 5 (excluding index 5)
print(my_list[2:5]) # Output: [3, 4, 5]
# Accessing elements from the start to index 4 (excluding index 4)
print(my_list[:4]) # Output: [1, 2, 3, 4]
# Accessing elements from index 3 to the end
print(my_list[3:]) # Output: [4, 5, 6, 7, 8]
# Slicing with step value
print(my_list[::2]) # Output: [1, 3, 5, 7]
4. List Methods
Python provides several built-in methods to manipulate lists. Below are some of
the most commonly used list methods:
append() : Adds an element at the end of the list.
extend() : Adds all elements of an iterable (like another list) to the list.
insert() : Inserts an element at a specified position in the list.
Python Notes 87
c
o
d
e
r
s
n
o
t
e
.
c
o
m
pop() : Removes and returns the element at the specified index (default is the
last element).
remove() : Removes the first occurrence of a specified element.
index() : Returns the index of the first occurrence of a specified element.
count() : Returns the number of occurrences of a specified element.
sort() : Sorts the list in ascending order.
reverse() : Reverses the order of elements in the list.
copy() : Returns a shallow copy of the list.
Examples:
# Creating a list
my_list = [1, 2, 3, 4]
# append() - Adds an element at the end of the list
my_list.append(5)
print(my_list) # Output: [1, 2, 3, 4, 5]
# extend() - Adds elements of another iterable
my_list.extend([6, 7])
print(my_list) # Output: [1, 2, 3, 4, 5, 6, 7]
# insert() - Inserts an element at the specified position
my_list.insert(2, "Hello")
print(my_list) # Output: [1, 2, 'Hello', 3, 4, 5, 6, 7]
# pop() - Removes and returns the element at the specified index
removed_item = my_list.pop(3)
print(removed_item) # Output: 3
print(my_list) # Output: [1, 2, 'Hello', 4, 5, 6, 7]
# remove() - Removes the first occurrence of a specified element
my_list.remove("Hello")
Python Notes 88
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(my_list) # Output: [1, 2, 4, 5, 6, 7]
# index() - Returns the index of the first occurrence of a specified element
index = my_list.index(5)
print(index) # Output: 3
# count() - Returns the number of occurrences of a specified element
count = my_list.count(7)
print(count) # Output: 1
# sort() - Sorts the list in ascending order
my_list.sort()
print(my_list) # Output: [1, 2, 4, 5, 6, 7]
# reverse() - Reverses the order of elements in the list
my_list.reverse()
print(my_list) # Output: [7, 6, 5, 4, 2, 1]
# copy() - Returns a shallow copy of the list
copied_list = my_list.copy()
print(copied_list) # Output: [7, 6, 5, 4, 2, 1]
5. Nested Lists
A nested list is a list that contains other lists as its elements. You can access
elements in nested lists using multiple indices.
# Creating a nested list
nested_list = [1, [2, 3], [4, 5, 6], 7]
# Accessing elements of the nested list
print(nested_list[1]) # Output: [2, 3] (list at index 1)
print(nested_list[1][0]) # Output: 2 (first element of the list at index 1)
Python Notes 89
c
o
d
e
r
s
n
o
t
e
.
c
o
m
6. List Comprehension
List comprehension is a concise way to create lists by applying an expression to
each element in an iterable. It is often used for transforming or filtering data.
Syntax:
[expression for item in iterable if condition]
expression is the result you want for each item.
item is each element of the iterable.
iterable can be any iterable like a list, tuple, etc.
condition is optional and is used to filter the items.
Examples:
# Create a list of squares of numbers from 1 to 5
squares = [x ** 2 for x in range(1, 6)]
print(squares) # Output: [1, 4, 9, 16, 25]
# Create a list of even numbers from 1 to 10
evens = [x for x in range(1, 11) if x % 2 == 0]
print(evens) # Output: [2, 4, 6, 8, 10]
# Create a list of strings in uppercase
words = ["hello", "world", "python"]
uppercase_words = [word.upper() for word in words]
print(uppercase_words) # Output: ['HELLO', 'WORLD', 'PYTHON']
Conclusion
Lists are one of the most commonly used data structures in Python, providing
an ordered, mutable collection of items.
You can create, access, and manipulate lists using various methods and
techniques like indexing, slicing, list methods, and list comprehensions.
Python Notes 90
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Python's list comprehension provides a concise and efficient way to create
and modify lists, especially for transforming or filtering data.
By understanding lists and their methods, you can efficiently manage collections
of data and perform a wide variety of tasks in Python.
Mutable and Immutable Data Types
1. Understanding Mutability
Definition of mutable and immutable objects
Importance of mutability in Python
2. Mutable Data Types
Lists
Dictionaries
Sets
3. Immutable Data Types
Strings
Tuples
Integers, Floats, Booleans, Complex Numbers
Examples of immutability
Mutable and Immutable Data Types in Python
In Python, the concept of mutability refers to whether or not an object can be
changed after it is created. This distinction is important because it affects how
variables are assigned, how data is shared between variables, and how
memory is managed.
1. Understanding Mutability
Mutable Objects
Python Notes 91
c
o
d
e
r
s
n
o
t
e
.
c
o
m
A mutable object is an object whose state or content can be changed after it
is created. When you modify a mutable object, the change is reflected in the
original object, and no new object is created.
Examples of mutable data types:
Lists
Dictionaries
Sets
Key characteristics of mutable objects:
You can change the contents of the object.
Modifications to mutable objects affect all references to that object.
Immutable Objects
An immutable object is an object whose state or content cannot be changed
after it is created. When you attempt to modify an immutable object, a new
object is created with the new value, and the original object remains
unchanged.
Examples of immutable data types:
Strings
Tuples
Integers
Floats
Booleans
Key characteristics of immutable objects:
You cannot change the contents of the object after it is created.
Modifying an immutable object creates a new object rather than changing
the original one.
2. Importance of Mutability in Python
Python Notes 92
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Mutability plays a crucial role in how variables and objects behave in Python.
Understanding the difference between mutable and immutable types can help
avoid bugs and optimize memory usage.
Effects of Mutability:
Memory Management: Immutable objects can often be optimized by
Python’s internal memory management, such as object interning (e.g., for
strings).
Assignment Behavior: When you assign a mutable object to another
variable, both variables refer to the same object. If you modify the object
through one variable, the change is reflected in the other variable.
# Example of mutable behavior
list1 = [1, 2, 3]
list2 = list1
list2.append(4) # Modifying list2 also affects list1
print(list1) # Output: [1, 2, 3, 4]
print(list2) # Output: [1, 2, 3, 4]
Immutable Assignment: When you assign an immutable object to another
variable, a copy of the value is made, and changes to one variable do not
affect the other.
# Example of immutable behavior
str1 = "Hello"
str2 = str1
str2 = "World" # Modifying str2 does not affect str1
print(str1) # Output: "Hello"
print(str2) # Output: "World"
Key Takeaways:
Mutable objects allow you to modify their content, and multiple variables
can reference the same object. This can lead to unexpected side effects if
you are not careful.
Python Notes 93
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Immutable objects cannot be changed once created. Modifications result
in the creation of new objects, making them safer to use when you don't
want shared references to be affected by changes.
Examples: Mutable vs Immutable
Mutable Example - List
# Mutable data type example: List
my_list = [1, 2, 3]
another_list = my_list # both variables refer to the same list
# Modifying the list through one variable
another_list.append(4)
print(my_list) # Output: [1, 2, 3, 4]
print(another_list) # Output: [1, 2, 3, 4]
In this example, both my_list and another_list refer to the same list object, so
modifying one will affect the other.
Immutable Example - String
# Immutable data type example: String
str1 = "Python"
str2 = str1 # both variables refer to the same string
# Modifying the string (strings are immutable)
str2 = "Java"
print(str1) # Output: "Python"
print(str2) # Output: "Java"
Here, strings are immutable, so when you assign a new value to str2 , Python
creates a new string object and updates str2 to reference the new string,
leaving str1 unchanged.
Python Notes 94
c
o
d
e
r
s
n
o
t
e
.
c
o
m
3. Implications of Mutability and Immutability
Performance Considerations: Immutable objects are typically faster when
used as dictionary keys or set elements because their hash values are
constant and do not change. Mutable objects, on the other hand, cannot
be used as dictionary keys or set elements since their hash values could
change after creation.
Avoiding Side Effects: Immutable objects are useful in avoiding
unintended side effects when working with multiple references to the
same object. Since their state cannot be changed, they are inherently
safer in situations where data integrity is important.
Conclusion
Understanding mutable and immutable data types is essential when working
with Python.
Mutable objects (like lists, dictionaries, and sets) can be modified after
creation.
Immutable objects (like strings, tuples, and integers) cannot be modified,
and any changes create a new object.
This distinction affects how you use these data types in your programs,
particularly when it comes to assignment, memory management, and avoiding
side effects.
Tuples
Creating tuples
Accessing elements using indexing
Tuple immutability
Tuple methods: count() , index()
Tuples in Python
Python Notes 95
c
o
d
e
r
s
n
o
t
e
.
c
o
m
A tuple is a collection data type in Python that is similar to a list, but unlike lists,
tuples are immutable. This means that once a tuple is created, its elements
cannot be modified (i.e., you cannot add, remove, or change elements).
1. Creating Tuples
You can create a tuple by placing a sequence of elements inside parentheses () .
Syntax:
tuple_name = (element1, element2, element3, ...)
Example:
my_tuple = (1, 2, 3, 4)
print(my_tuple) # Output: (1, 2, 3, 4)
You can also create a tuple with a single element by adding a trailing comma:
single_element_tuple = (5,)
print(single_element_tuple) # Output: (5,)
Without the comma, it will not be considered a tuple:
not_a_tuple = (5)
print(type(not_a_tuple)) # Output: <class 'int'>
Creating an empty tuple:
empty_tuple = ()
print(empty_tuple) # Output: ()
Tuple with mixed data types:
Python Notes 96
c
o
d
e
r
s
n
o
t
e
.
c
o
m
mixed_tuple = (1, "hello", 3.14, True)
print(mixed_tuple) # Output: (1, "hello", 3.14, True)
2. Accessing Elements Using Indexing
You can access the elements of a tuple using indexing, similar to lists. Indexing
starts from 0.
Syntax:
tuple_name[index]
Example:
my_tuple = (1, 2, 3, 4, 5)
print(my_tuple[0]) # Output: 1
print(my_tuple[3]) # Output: 4
Negative indexing:
You can also use negative indexing to access elements from the end of the tuple.
Example:
print(my_tuple[-1]) # Output: 5
print(my_tuple[-2]) # Output: 4
Slicing:
You can extract a subset of the tuple using slicing. The syntax for slicing is:
tuple_name[start_index:end_index]
Example:
Python Notes 97
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(my_tuple[1:4]) # Output: (2, 3, 4)
3. Tuple Immutability
One of the most important properties of tuples is that they are immutable. This
means that you cannot change, add, or remove elements after the tuple is created.
Example (Attempting to modify a tuple):
my_tuple = (1, 2, 3)
# Trying to modify an element (this will raise an error)
# my_tuple[1] = 5 # TypeError: 'tuple' object does not support item assignmen
t
However, you can concatenate tuples to create a new tuple:
tuple1 = (1, 2)
tuple2 = (3, 4)
new_tuple = tuple1 + tuple2 # Creating a new tuple by concatenation
print(new_tuple) # Output: (1, 2, 3, 4)
You can also perform operations like repetition using * :
my_tuple = (1, 2)
new_tuple = my_tuple * 3 # Repeating the tuple 3 times
print(new_tuple) # Output: (1, 2, 1, 2, 1, 2)
4. Tuple Methods
count() Method
The count() method returns the number of occurrences of a specified element in
the tuple.
Syntax:
Python Notes 98
c
o
d
e
r
s
n
o
t
e
.
c
o
m
tuple_name.count(element)
Example:
my_tuple = (1, 2, 3, 4, 1, 2, 1)
count_of_1 = my_tuple.count(1)
print(count_of_1) # Output: 3
index() Method
The index() method returns the index of the first occurrence of a specified element
in the tuple. If the element is not found, it raises a ValueError .
Syntax:
tuple_name.index(element)
Example:
my_tuple = (1, 2, 3, 4, 5)
index_of_3 = my_tuple.index(3)
print(index_of_3) # Output: 2
If the element is not in the tuple, it will raise an error:
# This will raise a ValueError because 6 is not in the tuple
# my_tuple.index(6)
Summary of Key Points:
Tuples are immutable data types in Python.
You can create a tuple using parentheses () , and it can contain different data
types.
Indexing and slicing are used to access tuple elements.
Python Notes 99
c
o
d
e
r
s
n
o
t
e
.
c
o
m
The count() method gives the number of occurrences of a specified element in
a tuple.
The index() method returns the first index of a specified element in a tuple.
Tuples can be concatenated or repeated using + and respectively, but the
tuple itself cannot be changed after creation.
Sets
Creating sets
Set methods: add() , update() , remove() , discard() , pop() , clear() , copy()
Sets in Python
A set in Python is an unordered collection of unique elements. Sets are similar to
lists and dictionaries but have no duplicate elements and are unordered, meaning
that the items have no index. They are mutable, meaning you can add or remove
elements, and they are often used for membership tests, removing duplicates from
a collection, and performing mathematical set operations like union, intersection,
and difference.
1. Creating Sets
A set is created by placing comma-separated values inside curly braces {} or by
using the set() constructor.
Syntax:
set_name = {element1, element2, element3, ...}
Alternatively, using the set() constructor:
set_name = set([element1, element2, element3, ...])
Example:
Python Notes 100
c
o
d
e
r
s
n
o
t
e
.
c
o
m
my_set = {1, 2, 3, 4}
print(my_set) # Output: {1, 2, 3, 4}
You can create an empty set using set() , but not using {} as it would create an
empty dictionary:
empty_set = set()
print(empty_set) # Output: set()
3. Set Methods
Sets come with several methods that allow you to manipulate the elements of the
set.
add() Method
The add() method adds an element to the set. If the element already exists, it won't
be added again (since sets don't allow duplicates).
Example:
my_set = {1, 2, 3}
my_set.add(4)
print(my_set) # Output: {1, 2, 3, 4}
update() Method
The update() method adds multiple elements (from an iterable) to the set.
Duplicates will be ignored.
Example:
my_set = {1, 2, 3}
my_set.update([3, 4, 5])
print(my_set) # Output: {1, 2, 3, 4, 5}
Python Notes 101
c
o
d
e
r
s
n
o
t
e
.
c
o
m
remove() Method
The remove() method removes a specified element from the set. If the element is
not found, it raises a KeyError .
Example:
my_set = {1, 2, 3, 4}
my_set.remove(3)
print(my_set) # Output: {1, 2, 4}
discard() Method
The discard() method removes a specified element from the set. If the element is
not found, it does nothing (no error is raised).
Example:
my_set = {1, 2, 3, 4}
my_set.discard(3)
print(my_set) # Output: {1, 2, 4}
my_set.discard(5) # No error raised, even though 5 is not in the set
pop() Method
The pop() method removes and returns an arbitrary element from the set. Since
sets are unordered, there is no guarantee which element will be removed.
Example:
my_set = {1, 2, 3, 4}
popped_element = my_set.pop()
print(popped_element) # Output: 1 (or another element, since the set is unord
ered)
print(my_set) # Output: {2, 3, 4}
clear() Method
Python Notes 102
c
o
d
e
r
s
n
o
t
e
.
c
o
m
The clear() method removes all elements from the set.
Example:
my_set = {1, 2, 3, 4}
my_set.clear()
print(my_set) # Output: set()
copy() Method
The copy() method creates a shallow copy of the set.
Example:
my_set = {1, 2, 3}
new_set = my_set.copy()
print(new_set) # Output: {1, 2, 3}
Summary of Key Points:
A set is an unordered collection of unique elements.
Sets support various mathematical operations like union, intersection, and
difference.
Sets are mutable, meaning elements can be added or removed.
Some common set methods include add() , remove() , discard() , pop() , clear() , and
update() .
Sets are widely used for tasks such as removing duplicates, membership
testing, and performing set operations.
By understanding these set operations and methods, you can effectively use sets
in Python to handle data more efficiently, especially when uniqueness and
mathematical set operations are important in your logic.
Dictionaries
Creating dictionaries
Python Notes 103
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Accessing, modifying, and deleting key-value pairs
Dictionary methods: get() , keys() , values() , items() , update() , pop() , popitem() , clear() ,
fromkeys() , setdefault()
Dictionaries in Python
A dictionary in Python is a collection of key-value pairs. It is an unordered,
mutable, and indexed collection that allows you to store data in the form of a key
and an associated value. Dictionaries are highly optimized for retrieving data and
can hold a mix of data types, such as strings, integers, and other objects.
1. Creating Dictionaries
A dictionary is created by using curly braces {} or the dict() constructor. Each key-
value pair is separated by a colon : and the pairs are separated by commas.
Syntax:
dict_name = {key1: value1, key2: value2, key3: value3, ...}
Example:
my_dict = {"name": "John", "age": 30, "city": "New York"}
print(my_dict) # Output: {'name': 'John', 'age': 30, 'city': 'New York'}
Alternatively, you can use the dict() function to create a dictionary:
my_dict = dict(name="John", age=30, city="New York")
print(my_dict) # Output: {'name': 'John', 'age': 30, 'city': 'New York'}
2. Accessing, Modifying, and Deleting Key-Value Pairs
Accessing Values
You can access the value associated with a key using the square bracket notation
or the get() method.
Python Notes 104
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Using square brackets:
print(my_dict["name"]) # Output: John
Using get() method:
print(my_dict.get("age")) # Output: 30
The get() method is safer than using square brackets because it doesn't raise an
error if the key doesn't exist. Instead, it returns None or a default value if provided.
Modifying Values
You can modify the value associated with a key by assigning a new value to the
key.
my_dict["age"] = 35
print(my_dict) # Output: {'name': 'John', 'age': 35, 'city': 'New York'}
Adding New Key-Value Pairs
You can add new key-value pairs to the dictionary simply by assigning a value to a
new key.
my_dict["email"] = "john@example.com"
print(my_dict) # Output: {'name': 'John', 'age': 35, 'city': 'New York', 'email': 'j
ohn@example.com'}
Deleting Key-Value Pairs
You can remove a key-value pair using the del statement or the pop() method.
Using del :
del my_dict["city"]
print(my_dict) # Output: {'name': 'John', 'age': 35, 'email': 'john@example.co
m'}
Python Notes 105
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Using pop() :
removed_value = my_dict.pop("email")
print(removed_value) # Output: john@example.com
print(my_dict) # Output: {'name': 'John', 'age': 35}
Using popitem() removes the last inserted key-value pair and returns it:
last_item = my_dict.popitem()
print(last_item) # Output: ('age', 35)
print(my_dict) # Output: {'name': 'John'}
Clearing the Dictionary
You can remove all key-value pairs from the dictionary using the clear() method:
my_dict.clear()
print(my_dict) # Output: {}
3. Dictionary Methods
get() Method
The get() method is used to access the value of a key. If the key does not exist, it
returns None or a default value if specified.
Syntax:
dict_name.get(key, default_value)
Example:
value = my_dict.get("age", "Not Available")
print(value) # Output: "Not Available"
Python Notes 106
c
o
d
e
r
s
n
o
t
e
.
c
o
m
keys() Method
The keys() method returns a view object that displays all the keys in the dictionary.
Example:
keys = my_dict.keys()
print(keys) # Output: dict_keys(['name', 'age'])
values() Method
The values() method returns a view object that displays all the values in the
dictionary.
Example:
values = my_dict.values()
print(values) # Output: dict_values(['John', 30])
items() Method
The items() method returns a view object that displays all the key-value pairs in the
dictionary.
Example:
items = my_dict.items()
print(items) # Output: dict_items([('name', 'John'), ('age', 30)])
update() Method
The update() method updates the dictionary with the key-value pairs from another
dictionary or an iterable of key-value pairs. If a key already exists, its value is
updated.
Example:
my_dict.update({"email": "john@example.com"})
print(my_dict) # Output: {'name': 'John', 'age': 30, 'email': 'john@example.co
Python Notes 107
c
o
d
e
r
s
n
o
t
e
.
c
o
m
m'}
pop() Method
The pop() method removes and returns the value associated with a specified key.
Example:
removed_value = my_dict.pop("age")
print(removed_value) # Output: 30
print(my_dict) # Output: {'name': 'John', 'email': 'john@example.com'}
popitem() Method
The popitem() method removes and returns the last key-value pair from the
dictionary.
Example:
last_item = my_dict.popitem()
print(last_item) # Output: ('email', 'john@example.com')
print(my_dict) # Output: {'name': 'John'}
clear() Method
The clear() method removes all key-value pairs from the dictionary.
Example:
my_dict.clear()
print(my_dict) # Output: {}
fromkeys() Method
The fromkeys() method creates a new dictionary with the specified keys and assigns
a default value to each key.
Syntax:
Python Notes 108
c
o
d
e
r
s
n
o
t
e
.
c
o
m
dict_name = dict.fromkeys(keys, value)
Example:
keys = ['name', 'age', 'city']
new_dict = dict.fromkeys(keys, "Not Available")
print(new_dict) # Output: {'name': 'Not Available', 'age': 'Not Available', 'city':
'Not Available'}
setdefault() Method
The setdefault() method returns the value of the key if it exists. If the key does not
exist, it inserts the key with a specified default value.
Example:
my_dict = {"name": "John", "age": 30}
value = my_dict.setdefault("city", "New York")
print(value) # Output: New York
print(my_dict) # Output: {'name': 'John', 'age': 30, 'city': 'New York'}
Summary of Key Points:
A dictionary is a collection of key-value pairs, where each key is unique.
Dictionaries are mutable, meaning you can add, modify, or remove key-value
pairs.
Common methods include get() , keys() , values() , items() , update() , pop() , and
clear() .
Dictionaries provide efficient access to values through keys and are an
essential data structure in Python.
Dictionaries are widely used for storing structured data, representing objects, and
implementing fast lookups. They are one of the most powerful and versatile data
structures in Python.
Python Notes 109
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Shallow copy vs Deep copy
Using copy and deepcopy from the copy module
Shallow Copy vs. Deep Copy in Python
In Python, when copying objects, there are two types of copies you can make:
shallow copy and deep copy. Understanding the difference is important when
working with complex objects like lists, dictionaries, or any mutable objects that
contain other objects.
1. Shallow Copy
A shallow copy creates a new object, but it does not create copies of the objects
that the original object contains. Instead, it simply copies references to those
objects. This means that changes made to nested objects (objects inside the
original object) will reflect in both the original and the copied object.
In simple terms:
A shallow copy only copies the outermost structure (like the list or dictionary)
but not the inner objects.
The inner objects are shared between the original and the copied object.
Creating a Shallow Copy:
You can create a shallow copy using the copy() method (for lists and
dictionaries) or the copy.copy() method from the copy module.
Example of Shallow Copy:
import copy
# Original object
original_list = [1, 2, [3, 4], 5]
# Create a shallow copy
shallow_copy_list = copy.copy(original_list)
Python Notes 110
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Modify a nested element in the shallow copy
shallow_copy_list[2][0] = 99
# Output the original and copied lists
print("Original List:", original_list) # Output: [1, 2, [99, 4], 5]
print("Shallow Copy List:", shallow_copy_list) # Output: [1, 2, [99, 4], 5]
As you can see, modifying the nested list inside the shallow copy also affects the
original list because both share the same reference to the inner list.
2. Deep Copy
A deep copy, on the other hand, creates a completely new object and recursively
copies all objects found in the original object, including any nested objects. This
means that the copied object and the original object are entirely independent of
each other.
In simple terms:
A deep copy creates a new object and also copies all objects contained within
the original object, including the inner ones.
The original and copied objects do not share any references to the same
objects.
Creating a Deep Copy:
You can create a deep copy using the deepcopy() function from the copy
module.
Example of Deep Copy:
import copy
# Original object
original_list = [1, 2, [3, 4], 5]
# Create a deep copy
deep_copy_list = copy.deepcopy(original_list)
Python Notes 111
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Modify a nested element in the deep copy
deep_copy_list[2][0] = 99
# Output the original and copied lists
print("Original List:", original_list) # Output: [1, 2, [3, 4], 5]
print("Deep Copy List:", deep_copy_list) # Output: [1, 2, [99, 4], 5]
In this case, modifying the nested list inside the deep copy does not affect the
original list, because the nested lists in the deep copy are independent of those in
the original list.
Key Differences Between Shallow Copy and Deep Copy
Aspect Shallow Copy Deep Copy
Definition
Creates a new object, but
doesn't copy nested objects.
Creates a completely independent
copy, recursively copying all objects
inside the original.
Shared
References
Shares references to nested
objects between original and
copied objects.
Does not share references. All
objects are copied, including nested
ones.
Effect of
Modification
Modifying nested objects in the
copied object affects the
original.
Modifying the copied object does
not affect the original.
Performance
Faster, as it only copies
references to the nested
objects.
Slower, as it recursively copies all
objects, including nested ones.
Use Case
Useful when you don't need to
modify nested objects or need
shared references.
Useful when you need completely
independent copies, especially when
modifying nested objects.
When to Use Shallow Copy and Deep Copy
Shallow Copy is useful when:
You only need a new container object (like a list or dictionary) but can
share references to the objects within.
Python Notes 112
c
o
d
e
r
s
n
o
t
e
.
c
o
m
You are working with objects that don’t contain nested mutable objects, or
you don’t intend to modify the nested objects.
Deep Copy is useful when:
You need a completely independent copy of an object, including all nested
objects.
You intend to modify both the original and the copied object, and you don’t
want changes to affect the other.
Code Example with Both Shallow and Deep Copy
import copy
# Original list with nested list
original_list = [1, 2, [3, 4], 5]
# Shallow copy
shallow_copy_list = copy.copy(original_list)
shallow_copy_list[2][0] = 99 # Modify the nested list
print("Shallow Copy Result:")
print("Original List:", original_list) # Output: [1, 2, [99, 4], 5]
print("Shallow Copy List:", shallow_copy_list) # Output: [1, 2, [99, 4], 5]
# Deep copy
deep_copy_list = copy.deepcopy(original_list)
deep_copy_list[2][0] = 999 # Modify the nested list
print("nDeep Copy Result:")
print("Original List:", original_list) # Output: [1, 2, [99, 4], 5]
print("Deep Copy List:", deep_copy_list) # Output: [1, 2, [999, 4], 5]
Conclusion
Shallow copy creates a new object but keeps references to the original
objects within it, making it more efficient for simple use cases.
Python Notes 113
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Deep copy creates a completely independent copy of the original object and
all its contents, which is useful when working with complex, nested structures
that you want to modify independently.
Understanding the difference between shallow and deep copies helps in
managing memory and object references effectively, especially when dealing with
mutable objects like lists, dictionaries, and sets.
Special Operators
Identity operators: is , is not
Membership operators: in , not in
1. Identity Operators
Identity operators are used to compare the memory locations of two objects. They
check whether two objects are the same object in memory, not just if they are
equal.
a) is Operator
Description: The is operator checks if two variables point to the same object
in memory (i.e., if they are the same object).
Syntax: variable1 is variable2
Returns: True if both variables point to the same object, otherwise False .
Example:
x = [1, 2, 3]
y = x # y points to the same object as x
z = [1, 2, 3] # z is a new object with the same value
print(x is y) # Output: True, because x and y refer to the same object
print(x is z) # Output: False, because x and z are different objects in memory
Python Notes 114
c
o
d
e
r
s
n
o
t
e
.
c
o
m
b) is not Operator
Description: The is not operator checks if two variables do not point to the
same object in memory (i.e., if they are different objects).
Syntax: variable1 is not variable2
Returns: True if both variables do not point to the same object, otherwise
False .
Example:
x = [1, 2, 3]
y = [1, 2, 3] # y is a different object with the same value
z = x # z refers to the same object as x
print(x is not y) # Output: True, because x and y are different objects
print(x is not z) # Output: False, because x and z refer to the same object
2. Membership Operators
Membership operators are used to test if a value or variable is present in a
sequence (such as a list, string, tuple, etc.). These operators check whether an
element exists in the sequence.
a) in Operator
Description: The in operator checks if a value is present in a sequence (like a
list, string, tuple, or set).
Syntax: value in sequence
Returns: True if the value is present in the sequence, otherwise False .
Example:
# Using 'in' with a list
fruits = ["apple", "banana", "cherry"]
print("apple" in fruits) # Output: True, because "apple" is in the list
Python Notes 115
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Using 'in' with a string
name = "Harish"
print("a" in name) # Output: True, because "a" is in the string "Harish"
b) not in Operator
Description: The not in operator checks if a value is not present in a sequence
(like a list, string, tuple, or set).
Syntax: value not in sequence
Returns: True if the value is not present in the sequence, otherwise False .
Example:
# Using 'not in' with a list
fruits = ["apple", "banana", "cherry"]
print("orange" not in fruits) # Output: True, because "orange" is not in the list
# Using 'not in' with a string
name = "Harish"
print("z" not in name) # Output: True, because "z" is not in the string "Harish"
Summary of Special Operators
Operator Description Example Output
is
Checks if two variables point to the
same object
x is y True or False
is not
Checks if two variables do not
point to the same object
x is not y True or False
in
Checks if a value is present in a
sequence
"apple" in fruits True or False
not in
Checks if a value is not present in a
sequence
"orange" not in
fruits
True or False
Python Notes 116
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example Program Using Identity and Membership Operators
# Identity operators
a = [1, 2, 3]
b = a # b is the same object as a
c = [1, 2, 3] # c is a different object with the same value
print(a is b) # Output: True, because a and b point to the same object
print(a is c) # Output: False, because a and c are different objects in memory
print(a is not c) # Output: True, because a and c are different objects
# Membership operators
fruits = ["apple", "banana", "cherry"]
print("banana" in fruits) # Output: True, because "banana" is in the list
print("orange" not in fruits) # Output: True, because "orange" is not in the list
Key Takeaways:
Identity operators ( is , is not ) compare if two variables refer to the same
object in memory.
Membership operators ( in , not in ) check if a value exists in a sequence like a
list, tuple, or string.
Use identity operators when checking for object identity and membership
operators when testing membership in sequences.
Module 7: Strings
1. String Basics
Creating strings
Accessing characters using indexing
slicing
Python Notes 117
c
o
d
e
r
s
n
o
t
e
.
c
o
m
String immutability
+ Replication
1. String Basics in Python
Strings are one of the most commonly used data types in Python, and
understanding how to work with them is essential. In Python, strings are
sequences of characters enclosed within single quotes ( ' ) or double quotes
( " ).
1.1 Creating Strings
You can create strings in Python by enclosing characters in single or double
quotes. You can also use triple quotes ( ''' or """ ) for multi-line strings.
Examples:
# Single quote string
string1 = 'Hello, World!'
# Double quote string
string2 = "Python is awesome!"
# Multi-line string
multi_line_string = '''This is a
multi-line string.'''
print(string1)
print(string2)
print(multi_line_string)
1.2 Accessing Characters Using Indexing
Strings in Python are indexed, meaning each character in the string has a
specific position (or index). Indexing starts from 0 for the first character. You
can access a character in a string by referring to its index.
Example:
Python Notes 118
c
o
d
e
r
s
n
o
t
e
.
c
o
m
text = "Python"
# Accessing individual characters using indexing
print(text[0]) # Output: P
print(text[1]) # Output: y
print(text[5]) # Output: n
Positive indexing starts from 0 (left to right).
Negative indexing starts from -1 (right to left).
Example with negative indexing:
text = "Python"
# Negative indexing starts from the last character
print(text[-1]) # Output: n
print(text[-2]) # Output: o
1.3 Slicing
Slicing allows you to extract a portion of a string by specifying a start and end
index. The syntax for slicing is:
string[start:end:step]
start : Index of the first character to include.
end : Index of the character to stop at (but not include).
step : The step size (optional).
Examples:
text = "Python Programming"
# Slicing a string (from index 0 to 5)
print(text[0:6]) # Output: Python
# Slicing with step
Python Notes 119
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(text[0:12:2]) # Output: Pto rg
# Omitting the start and end
print(text[::3]) # Output: Ph oai
1.4 String Immutability
Strings in Python are immutable, meaning you cannot change the content of a
string once it is created. If you try to modify a string directly, it will result in an
error.
Example of attempting to modify a string (will cause an error):
text = "Python"
# Trying to change the first character
text[0] = 'J' # This will cause a TypeError because strings are immutable
However, you can create a new string by concatenating or using string
methods.
Correct way to modify a string (create a new string):
text = "Python"
new_text = 'J' + text[1:]
print(new_text) # Output: Jython
Summary of String Basics
Creating Strings: Strings can be created using single quotes, double
quotes, or triple quotes for multi-line strings.
Indexing: You can access characters in a string by their index. Positive
indices start from 0, and negative indices start from -1.
Slicing: You can extract parts of a string using slicing syntax
( string[start:end:step] ).
Immutability: Strings are immutable in Python, meaning their values
cannot be modified once created. To change a string, you need to create a
Python Notes 120
c
o
d
e
r
s
n
o
t
e
.
c
o
m
new one.
2. String Methods
Modifying strings: upper() , lower() , capitalize() , title() , swapcase() , strip() , lstrip() ,
rstrip()
Searching and replacing: find() , rfind() , index() , rindex() , replace()
Splitting and joining: split() , rsplit() , partition() , rpartition() , join()
Checking content: isalpha() , isdigit() , isalnum() , isspace() , startswith() , endswith()
Strings in Python come with a variety of built-in methods that allow you to
manipulate and interact with them in various ways. Below, we will explore
some common string methods:
2.1 Modifying Strings
upper() : Converts all characters in the string to uppercase.
Example:
text = "python"
print(text.upper()) # Output: PYTHON
lower() : Converts all characters in the string to lowercase.
Example:
text = "Python"
print(text.lower()) # Output: python
capitalize() : Capitalizes the first character of the string and converts all other
characters to lowercase.
Example:
Python Notes 121
c
o
d
e
r
s
n
o
t
e
.
c
o
m
text = "python"
print(text.capitalize()) # Output: Python
title() : Capitalizes the first character of each word in the string.
Example:
text = "hello python world"
print(text.title()) # Output: Hello Python World
swapcase() : Converts all uppercase characters to lowercase and vice versa.
Example:
text = "PyThOn"
print(text.swapcase()) # Output: pYtHoN
strip() : Removes leading and trailing whitespace from the string.
Example:
text = " hello "
print(text.strip()) # Output: hello
lstrip() : Removes leading (left) whitespace.
Example:
text = " hello"
print(text.lstrip()) # Output: hello
rstrip() : Removes trailing (right) whitespace.
Example:
text = "hello "
print(text.rstrip()) # Output: hello
Python Notes 122
c
o
d
e
r
s
n
o
t
e
.
c
o
m
2.2 Searching and Replacing
find() : Returns the lowest index of the substring if found, otherwise returns
1 .
Example:
text = "Python programming"
print(text.find("prog")) # Output: 7
print(text.find("java")) # Output: -1
rfind() : Similar to find() , but returns the highest index of the substring.
Example:
text = "Python programming, Python is great"
print(text.rfind("Python")) # Output: 23
index() : Similar to find() , but raises a ValueError if the substring is not found.
Example:
text = "Python programming"
print(text.index("prog")) # Output: 7
rindex() : Similar to index() , but returns the highest index of the substring.
Example:
text = "Python programming, Python is great"
print(text.rindex("Python")) # Output: 23
replace() : Replaces a specified substring with another substring.
Example:
text = "I love Python"
Python Notes 123
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(text.replace("Python", "Java")) # Output: I love Java
2.3 Splitting and Joining
split() : Splits the string into a list of substrings based on a delimiter (default
is whitespace).
Example:
text = "Python is awesome"
print(text.split()) # Output: ['Python', 'is', 'awesome']
rsplit() : Similar to split() , but splits from the right.
Example:
text = "Python is awesome and fun"
print(text.rsplit(" ", 2)) # Output: ['Python is', 'awesome', 'and fun']
partition() : Splits the string into a 3-part tuple: the part before the separator,
the separator itself, and the part after the separator.
Example:
text = "Python programming is fun"
print(text.partition("programming")) # Output: ('Python ', 'programming', '
is fun')
rpartition() : Similar to partition() , but splits from the right.
Example:
text = "Python programming is fun"
print(text.rpartition("is")) # Output: ('Python programming ', 'is', ' fun')
join() : Joins a sequence of strings into a single string, using the string it’s
called on as the separator.
Python Notes 124
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example:
words = ["Python", "is", "awesome"]
print(" ".join(words)) # Output: Python is awesome
2.4 Checking Content
isalpha() : Returns True if all characters in the string are alphabetic.
Example:
text = "Python"
print(text.isalpha()) # Output: True
text = "Python3"
print(text.isalpha()) # Output: False
isdigit() : Returns True if all characters in the string are digits.
Example:
text = "12345"
print(text.isdigit()) # Output: True
text = "123abc"
print(text.isdigit()) # Output: False
isalnum() : Returns True if all characters in the string are alphanumeric
(letters and digits).
Example:
text = "Python3"
print(text.isalnum()) # Output: True
Python Notes 125
c
o
d
e
r
s
n
o
t
e
.
c
o
m
text = "Python 3"
print(text.isalnum()) # Output: False
isspace() : Returns True if all characters in the string are whitespace.
Example:
text = " "
print(text.isspace()) # Output: True
text = "Python"
print(text.isspace()) # Output: False
startswith() : Returns True if the string starts with the specified substring.
Example:
text = "Python programming"
print(text.startswith("Python")) # Output: True
endswith() : Returns True if the string ends with the specified substring.
Example:
text = "Python programming"
print(text.endswith("programming")) # Output: True
Summary of String Methods
Modifying Strings: Methods like upper() , lower() , capitalize() , and others help
transform string content.
Searching and Replacing: Methods like find() , replace() , and index() allow for
finding and replacing substrings.
Splitting and Joining: Methods like split() , join() , and partition() help break
down or combine strings.
Python Notes 126
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Checking Content: Methods like isalpha() , isdigit() , and isspace() allow you to
check the type of content in a string.
Regular Expressions
re module
Functions: search() , match() , fullmatch() , findall() , finditer() , sub() , split()
re Module
Regular Expressions (regex) are a powerful tool used for searching and
manipulating strings based on patterns. Python provides the re module, which
contains various functions to work with regular expressions.
1. re Module
The re module in Python provides several functions to work with regular
expressions. To use it, you need to import the module:
import re
2. Key Functions in re Module
Here are some common functions in the re module used to perform operations
with regular expressions:
2.1 search()
Description: Searches for the first occurrence of the pattern in the string.
Returns: A match object if the pattern is found, otherwise None .
import re
text = "The quick brown fox."
pattern = r"quick"
Python Notes 127
c
o
d
e
r
s
n
o
t
e
.
c
o
m
result = re.search(pattern, text)
if result:
print("Match found:", result.group())
else:
print("No match found.")
# Output: Match found: quick
2.2 match()
Description: Checks if the pattern matches at the beginning of the string.
Returns: A match object if the pattern matches at the start, otherwise None .
import re
text = "quick brown fox"
pattern = r"quick"
result = re.match(pattern, text)
if result:
print("Match found:", result.group())
else:
print("No match found.")
# Output: Match found: quick
2.3 fullmatch()
Description: Checks if the entire string matches the pattern.
Returns: A match object if the entire string matches the pattern, otherwise
None .
import re
text = "quick brown fox"
Python Notes 128
c
o
d
e
r
s
n
o
t
e
.
c
o
m
pattern = r"quick brown fox"
result = re.fullmatch(pattern, text)
if result:
print("Full match found:", result.group())
else:
print("No full match found.")
# Output: Full match found: quick brown fox
2.4 findall()
Description: Finds all occurrences of the pattern in the string.
Returns: A list of all matches found.
import re
text = "cat bat rat hat"
pattern = r"at"
matches = re.findall(pattern, text)
print("Matches found:", matches)
# Output: Matches found: ['at', 'at', 'at', 'at']
2.5 finditer()
Description: Returns an iterator yielding match objects for all matches in the
string.
Returns: An iterator containing match objects.
import re
text = "cat bat rat hat"
pattern = r"at"
Python Notes 129
c
o
d
e
r
s
n
o
t
e
.
c
o
m
matches = re.finditer(pattern, text)
for match in matches:
print(match.group())
# Output:
# at
# at
# at
# at
2.6 sub()
Description: Replaces occurrences of the pattern with a specified string.
Returns: A new string with the replacements.
import re
text = "cat bat rat hat"
pattern = r"at"
replacement = "on"
result = re.sub(pattern, replacement, text)
print("Replaced text:", result)
# Output: Replaced text: con bon ron hon
2.7 split()
Description: Splits the string by occurrences of the pattern.
Returns: A list of strings split by the pattern.
import re
text = "apple, orange, banana, grape"
pattern = r", "
Python Notes 130
c
o
d
e
r
s
n
o
t
e
.
c
o
m
result = re.split(pattern, text)
print("Split result:", result)
# Output: Split result: ['apple', 'orange', 'banana', 'grape']
3. Regular Expression Syntax
Here are some common regular expression patterns used in the functions above:
. (dot): Matches any character except newline.
d : Matches any digit (equivalent to [0-9] ).
w : Matches any word character (equivalent to [a-zA-Z0-9_] ).
s : Matches any whitespace character (spaces, tabs, newlines).
^ : Matches the beginning of the string.
$ : Matches the end of the string.
: Matches zero or more occurrences of the preceding pattern.
+ : Matches one or more occurrences of the preceding pattern.
? : Matches zero or one occurrence of the preceding pattern.
[] : Matches any single character within the brackets.
| : Acts as an OR operator between patterns.
Example: Matching a phone number
import re
text = "My phone number is 123-456-7890"
pattern = r"d{3}-d{3}-d{4}"
result = re.search(pattern, text)
if result:
print("Phone number found:", result.group())
# Output: Phone number found: 123-456-7890
Python Notes 131
c
o
d
e
r
s
n
o
t
e
.
c
o
m
The re module is a powerful tool for working with text patterns in Python.
Functions like search() , match() , findall() , and others allow you to easily search,
match, and manipulate strings based on regular expressions. Regular expressions
themselves are an essential skill for text processing, data extraction, and
validation tasks in Python.
Module 8: File Handling
1. File Operations
Opening files: open()
Reading files: read() , readline() , readlines()
Writing files: write() , writelines()
Closing files: close()
2. File Modes
Read ( r ), write ( w ), append ( a )
File Operations
In Python, file operations allow us to interact with external files by reading,
writing, and modifying them. Working with files is essential when handling
data storage, logs, and configuration settings.
Opening Files
The open() function is used to open a file in different modes:
file = open("example.txt", "r") # Opens a file in read mode
'r' - Read mode (default)
'w' - Write mode (overwrites existing content)
'a' - Append mode (adds content to the end)
Python Notes 132
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Reading Files
To read the contents of a file, Python provides multiple methods:
file = open("example.txt", "r")
content = file.read() # Reads the entire file
print(content)
file.close()
read() : Reads the whole file as a string.
readline() : Reads one line at a time.
readlines() : Reads all lines into a list.
Writing Files
To write data to a file, we use the write() or writelines() methods:
file = open("example.txt", "w") # Open in write mode
file.write("Hello, World!n") # Writes a string to the file
file.writelines(["Line 1n", "Line 2n"]) # Writes multiple lines
file.close()
write() : Writes a string to the file.
writelines() : Writes multiple lines from a list.
Closing Files
After performing file operations, it is important to close the file to free up
system resources:
file.close()
Alternatively, using the with statement ensures automatic closure:
with open("example.txt", "r") as file:
content = file.read()
Python Notes 133
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(content) # File is closed automatically after this block
This method is preferred as it prevents issues related to forgetting to close the
file.
Module 9: Object-Oriented Programming
1. Classes and Objects
Defining classes using class
Creating objects
Using __init__ (constructor)
self parameter
In Python, classes are used to define the structure and behavior of objects.
Objects are instances of classes, and classes encapsulate data (attributes)
and functions (methods) that operate on the data.
1. Defining a Class Using class
A class is defined using the class keyword followed by the class name
(typically in PascalCase).
class Dog:
pass # Empty class
In this example, Dog is the class name. The pass statement is used as a
placeholder for the class body (though usually, we would add methods and
attributes to it).
2. Creating Objects
Once a class is defined, you can create objects (instances) of that class.
Python Notes 134
c
o
d
e
r
s
n
o
t
e
.
c
o
m
class Dog:
pass
# Creating an object of the Dog class
dog1 = Dog()
Here, dog1 is an instance of the Dog class.
3. Using __init__ (Constructor)
The __init__ method is a special method in Python that is automatically called
when an object is instantiated. It's used to initialize the object's attributes. This
method is commonly known as the constructor.
class Dog:
def __init__(self, name, breed):
self.name = name # Object attribute
self.breed = breed # Object attribute
# Creating an object and passing arguments to the constructor
dog1 = Dog("Buddy", "Golden Retriever")
print(dog1.name) # Output: Buddy
print(dog1.breed) # Output: Golden Retriever
In the above code, __init__ takes the self parameter (referring to the instance)
and the attributes name and breed . The values for these attributes are passed
when creating an object.
4. self Parameter
The self parameter is a reference to the current instance of the class. It allows
you to access the instance’s attributes and methods within the class. It's not
passed when you create an object, but it is used inside the class to refer to the
instance.
Python Notes 135
c
o
d
e
r
s
n
o
t
e
.
c
o
m
class Dog:
def __init__(self, name, breed):
self.name = name # self refers to the current instance
self.breed = breed
def bark(self):
print(f"{self.name} says woof!")
# Creating an object
dog1 = Dog("Buddy", "Golden Retriever")
dog1.bark() # Output: Buddy says woof!
In this example, the bark method uses self.name to access the name attribute of
the object.
Key Points:
1. Class Definition: Classes are created using the class keyword.
2. Creating Objects: You can instantiate objects of a class by calling the
class name followed by parentheses.
3. Constructor ( __init__ ): The __init__ method is used to initialize the object's
attributes. It is automatically called when an object is created.
4. Self: The self parameter refers to the instance of the class and is used to
access its attributes and methods.
Example with Multiple Objects:
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def display_info(self):
Python Notes 136
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(f"{self.year} {self.make} {self.model}")
# Creating multiple objects
car1 = Car("Toyota", "Corolla", 2020)
car2 = Car("Honda", "Civic", 2021)
car1.display_info() # Output: 2020 Toyota Corolla
car2.display_info() # Output: 2021 Honda Civic
In this example, two Car objects ( car1 and car2 ) are created with different
attributes. The display_info() method is used to print information about each car.
class Student:
school = "Tagore"
def data(self,name,gender):
self.name = name
self.gender = gender
print(self.name)
print(self.gender)
print(Student.school)
print(self.__dict__)
def start():
s = Student()
s.data("Harish","M")
s.data("Jeevan","M")
s.data("Preetha","F")
print(s.__dict__)
print(Student.__dict__)
start()
2. Attributes and Methods
Python Notes 137
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Instance variables and methods
Class variables and methods ( @classmethod )
Static methods ( @staticmethod )
In Python, classes can have different types of variables and methods that
function in various ways depending on whether they belong to an instance or
the class itself. Let’s explore the distinctions between instance variables, class
variables, and static methods.
1. Instance Variables and Methods
Instance Variables
Instance variables are variables that are specific to an instance (object) of
the class.
They are defined within the __init__ method and are prefixed with self .
Each object of the class has its own copy of instance variables.
Instance Methods
Instance methods are functions defined inside a class that operate on
instance variables.
They must include self as the first parameter, which refers to the current
object.
class Dog:
def __init__(self, name, breed):
self.name = name # Instance variable
self.breed = breed # Instance variable
def bark(self): # Instance method
print(f"{self.name} says woof!")
# Creating an object
Python Notes 138
c
o
d
e
r
s
n
o
t
e
.
c
o
m
dog1 = Dog("Buddy", "Golden Retriever")
dog1.bark() # Output: Buddy says woof!
In this example, name and breed are instance variables, and bark() is an
instance method.
2. Class Variables and Methods
Class Variables
Class variables are shared among all instances of a class. They are
defined within the class but outside any method.
All instances of the class share the same class variable. If one object
modifies the class variable, it affects all objects.
Class Methods
A class method is a method that takes the class as its first argument, not
the instance ( cls instead of self ).
Class methods are defined using the @classmethod decorator.
They are used when you want to operate on class-level data (class
variables).
class Dog:
species = "Canis familiaris" # Class variable
def __init__(self, name, breed):
self.name = name # Instance variable
self.breed = breed # Instance variable
def bark(self): # Instance method
print(f"{self.name} says woof!")
@classmethod
def change_species(cls, new_species): # Class method
cls.species = new_species
Python Notes 139
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Creating an object
dog1 = Dog("Buddy", "Golden Retriever")
print(dog1.species) # Output: Canis familiaris
# Changing the class variable using class method
Dog.change_species("Canis lupus familiaris")
print(dog1.species) # Output: Canis lupus familiaris
Here:
species is a class variable shared by all instances of the class.
change_species() is a class method that modifies the class variable species .
3. Static Methods
Static Methods
Static methods are methods that don’t modify or rely on the state of the
instance or the class.
They don’t take self or cls as the first parameter.
Static methods are defined using the @staticmethod decorator.
These methods are used when you want a method that belongs to the
class but doesn’t need to access or modify instance or class-level data.
class MathOperations:
@staticmethod
def add(a, b):
return a + b
# Calling the static method without creating an instance
Python Notes 140
c
o
d
e
r
s
n
o
t
e
.
c
o
m
result = MathOperations.add(5, 10)
print("Sum:", result) # Output: Sum: 15
Explanation:
The @staticmethod decorator is used to define a static method.
Static methods belong to the class rather than an instance, meaning they
can be called using the class name without creating an object.
In this example, add(a, b) performs addition and returns the result.
Would you like me to integrate this explanation into your existing notes?
Example Programs
class Student:
def __init__(self, name, gender, school):
self.name = name
self.gender = gender
self.school = school
def display(self):
print("Name:", self.name)
print("Gender:", self.gender)
print("School:", self.school)
# Creating an instance of the Student class
harish = Student("Harish", "M", "Tagore")
jeevan = Student("Jeevan", "M", "Tagore")
preetha = Student("Preetha", "F", "Tagore")
# Calling the display method
harish.display()
jeevan.display()
preetha.display()
Python Notes 141
c
o
d
e
r
s
n
o
t
e
.
c
o
m
class Student:
# Static variable (shared by all instances)
school = "Tagore"
def __init__(self, name, gender):
self.name = name
self.gender = gender
def display(self):
print("Name:", self.name)
print("Gender:", self.gender)
print("School:", Student.school) # Accessing the static variable using th
# Creating instances of the Student class
harish = Student("Harish", "M")
jeevan = Student("Jeevan", "M")
preetha = Student("Preetha", "F")
# Calling the display method
harish.display()
jeevan.display()
preetha.display()
class Student:
# Static variable (shared by all instances)
school = "Tagore"
def __init__(self, name, gender):
self.name = name
self.gender = gender
def display(self):
print("Name:", self.name)
print("Gender:", self.gender)
Python Notes 142
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print("School:", Student.school) # Accessing the static variable using th
# Static method
@staticmethod
def get_school():
print("The school name is:", Student.school)
# Creating instances of the Student class
harish = Student("Harish", "M")
jeevan = Student("Jeevan", "M")
preetha = Student("Preetha", "F")
# Calling the display method
harish.display()
jeevan.display()
preetha.display()
# Calling the static method
Student.get_school()
Key Differences
1. Instance Variables and Methods:
Instance Variables: Unique to each instance of the class. Accessed
with self .
Instance Methods: Operate on instance variables and can access or
modify them. They use self as the first parameter.
2. Class Variables and Methods:
Class Variables: Shared by all instances of the class. Accessed with
cls .
Class Methods: Operate on class-level data (class variables) and use
cls as the first parameter.
Python Notes 143
c
o
d
e
r
s
n
o
t
e
.
c
o
m
3. Static Methods:
Static Methods: Do not rely on instance or class-level data. They don’t
take self or cls as parameters and are used when you want a method
that doesn’t interact with instance or class variables.
Example Combining All Three
class Dog:
species = "Canis familiaris" # Class variable
def __init__(self, name, breed):
self.name = name # Instance variable
self.breed = breed # Instance variable
def bark(self): # Instance method
print(f"{self.name} says woof!")
@classmethod
def change_species(cls, new_species): # Class method
cls.species = new_species
@staticmethod
def bark_sound(): # Static method
print("Woof!")
# Creating objects
dog1 = Dog("Buddy", "Golden Retriever")
dog2 = Dog("Max", "Labrador")
# Instance methods
dog1.bark() # Output: Buddy says woof!
dog2.bark() # Output: Max says woof!
# Class method (changing class variable)
Dog.change_species("Canis lupus familiaris")
Python Notes 144
c
o
d
e
r
s
n
o
t
e
.
c
o
m
print(dog1.species) # Output: Canis lupus familiaris
print(dog2.species) # Output: Canis lupus familiaris
# Static method
Dog.bark_sound() # Output: Woof!
Summary:
Instance variables are unique to each object and accessed with self .
Class variables are shared among all objects and accessed with cls .
Instance methods access instance data, while class methods access
class-level data.
Static methods don’t require access to instance or class data.
Inheritance
Single inheritance
Multiple inheritance
Multilevel inheritance
Hierarchical inheritance
ybrid Inheritance
Overriding methods
Specialization
Inheritance allows a class (child or subclass) to inherit attributes and methods
from another class (parent or superclass). This enables code reuse and helps
create a hierarchy of classes with shared behaviors.
Python supports several types of inheritance, including single, multiple, multilevel,
and hierarchical inheritance.
1. Single Inheritance
Python Notes 145
c
o
d
e
r
s
n
o
t
e
.
c
o
m
In single inheritance, a class (child class) inherits from a single parent class.
Example:
class Animal:
def speak(self):
print("Animal makes a sound")
class Dog(Animal): # Dog is inheriting from Animal
def bark(self):
print("Dog barks")
# Creating an object of Dog class
dog = Dog()
dog.speak() # Inherited method
dog.bark() # Method in Dog class
In this example:
Dog inherits the speak() method from the Animal class.
The Dog class also defines its own bark() method.
2. Multiple Inheritance
In multiple inheritance, a class inherits from more than one parent class. Python
allows a class to inherit from multiple classes.
Example:
class Animal:
def speak(self):
print("Animal makes a sound")
class Mammal:
def has_fur(self):
print("Mammal has fur")
Python Notes 146
c
o
d
e
r
s
n
o
t
e
.
c
o
m
class Dog(Animal, Mammal): # Dog inherits from both Animal and Mammal
def bark(self):
print("Dog barks")
# Creating an object of Dog class
dog = Dog()
dog.speak() # Inherited from Animal
dog.has_fur() # Inherited from Mammal
dog.bark() # Method in Dog class
In this example:
Dog inherits from both Animal and Mammal .
The Dog class has access to methods from both parent classes ( speak() from
Animal and has_fur() from Mammal ).
3. Overriding Methods
Method overriding occurs when a child class provides a specific implementation
of a method that is already defined in its parent class. The method in the child
class overrides the method in the parent class.
Example:
class Animal:
def speak(self):
print("Animal makes a sound")
class Dog(Animal):
def speak(self): # Overriding the speak method
print("Dog barks")
# Creating objects
animal = Animal()
dog = Dog()
Python Notes 147
c
o
d
e
r
s
n
o
t
e
.
c
o
m
animal.speak() # Output: Animal makes a sound
dog.speak() # Output: Dog barks
In this example:
The Dog class overrides the speak() method of the Animal class to provide a
custom implementation.
4. Specialization
Specialization is the process of extending or modifying the behavior of a parent
class in the child class. The child class inherits all the attributes and methods of
the parent class but may also add new features or override existing methods to
make them more specific.
Example:
class Animal:
def speak(self):
print("Animal makes a sound")
class Dog(Animal):
def speak(self): # Overriding the speak method
print("Dog barks")
def fetch(self): # Adding a new method specific to Dog
print("Dog is fetching the ball")
# Creating an object of Dog class
dog = Dog()
dog.speak() # Output: Dog barks
dog.fetch() # Output: Dog is fetching the ball
In this example:
Python Notes 148
c
o
d
e
r
s
n
o
t
e
.
c
o
m
The Dog class specializes the Animal class by overriding speak() and adding the
fetch() method, which is specific to the Dog class.
5. Multilevel Inheritance
In multilevel inheritance, a class inherits from another class, which itself is derived
from another class, forming a chain of inheritance.
Example:
class Animal:
def speak(self):
print("Animal makes a sound")
class Dog(Animal): # Dog inherits from Animal
def bark(self):
print("Dog barks")
class Puppy(Dog): # Puppy inherits from Dog (and implicitly from Animal)
def cute(self):
print("Puppy is cute")
# Creating an object of Puppy class
puppy = Puppy()
puppy.speak() # Inherited from Animal
puppy.bark() # Inherited from Dog
puppy.cute() # Method in Puppy class
In this example:
Puppy inherits from Dog , and Dog inherits from Animal .
The Puppy class can access methods from both Dog and Animal .
6. Hierarchical Inheritance
In hierarchical inheritance, multiple classes inherit from the same parent class.
Each subclass has its own features but shares common methods and properties
Python Notes 149
c
o
d
e
r
s
n
o
t
e
.
c
o
m
from the parent class.
Example:
class Animal:
def speak(self):
print("Animal makes a sound")
class Dog(Animal): # Dog inherits from Animal
def bark(self):
print("Dog barks")
class Cat(Animal): # Cat also inherits from Animal
def meow(self):
print("Cat meows")
# Creating objects of Dog and Cat classes
dog = Dog()
cat = Cat()
dog.speak() # Inherited from Animal
dog.bark() # Method in Dog class
cat.speak() # Inherited from Animal
cat.meow() # Method in Cat class
In this example:
Both Dog and Cat inherit from the Animal class.
The speak() method is inherited by both Dog and Cat , while each has its own
specialized method ( bark() for Dog and meow() for Cat ).
Hybrid Inheritance in Python
Hybrid inheritance is a combination of multiple types of inheritance, such as
single, multiple, multilevel, or hierarchical inheritance. It allows flexibility but can
sometimes lead to complexity and the diamond problem, which Python resolves
using the Method Resolution Order (MRO).
Python Notes 150
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example of Hybrid Inheritance
# Parent class
class A:
def show(self):
print("Class A")
# Child class inheriting from A
class B(A):
def show(self):
print("Class B")
# Another child class inheriting from A
class C(A):
def show(self):
print("Class C")
# Class D inheriting from both B and C (Multiple Inheritance)
class D(B, C):
def show(self):
print("Class D")
# Creating an object of class D
obj = D()
obj.show() # Output: Class D
# Checking Method Resolution Order (MRO)
print(D.mro())
Explanation
1. Class A is the base class.
2. Class B and Class C both inherit from Class A (hierarchical inheritance).
3. Class D inherits from both B and C (multiple inheritance).
Python Notes 151
c
o
d
e
r
s
n
o
t
e
.
c
o
m
4. When obj.show() is called, it follows MRO, which prioritizes D → B → C → A.
Method Resolution Order (MRO)
Python resolves the diamond problem using C3 Linearization (MRO).
Use ClassName.mro() or help(ClassName) to check MRO.
Would you like to add this to your notes?
Summary of Inheritance Types:
Single Inheritance: One class inherits from another class.
Multiple Inheritance: A class inherits from more than one class.
Method Overriding: A child class overrides a method of the parent class to
provide a different implementation.
Specialization: A child class extends or modifies the functionality of the
parent class.
Multilevel Inheritance: A class inherits from another class, which itself is
derived from a third class.
Hierarchical Inheritance: Multiple classes inherit from the same parent class.
Inheritance helps in creating a hierarchy and allows for code reuse, making it
easier to manage and extend functionality.
Polymorphism
Method overloading using default arguments
Method overriding
Polymorphism in Python
Polymorphism is one of the four pillars of Object-Oriented Programming (OOP). It
means "many forms" and allows objects of different classes to be treated as
objects of a common superclass. Polymorphism lets you use a unified interface to
interact with different types of objects.
Python Notes 152
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Base class Zomato, representing a generic food delivery platform
class Zomato:
def menu(self):
print("list Veg & Non Veg foods") # Displays both veg and non-veg options
def order(self):
print("Your Order Placed") # Confirms order placement
def delivery(self):
print("Order Delivered") # Indicates that the order is delivered
# Subclass Veg_Zomato, specialized for vegetarian food
class Veg_Zomato(Zomato):
def menu(self):
print("list Veg foods") # Overrides menu() to show only vegetarian options
# Subclass Non_Veg_Zomato, specialized for non-vegetarian food
class Non_Veg_Zomato(Zomato):
def menu(self):
print("list Non-Veg foods") # Overrides menu() to show only non-veg option
# Subclass Blink_it, specialized for grocery delivery
class Blink_it(Zomato):
def menu(self):
print("list Groceries") # Overrides menu() to list groceries instead of food
def gold_pass(self):
print("You are eligible for free delivery") # Exclusive method for Blink_it cus
# Function to display the behavior of different objects dynamically
def display(ref):
ref.menu() # Calls the menu method of the respective class
ref.order() # Calls the order method from the base class
if type(ref) == Blink_it:
ref.gold_pass() # Calls gold_pass() only if the object belongs to Blink_it class
Python Notes 153
c
o
d
e
r
s
n
o
t
e
.
c
o
m
ref.delivery() # Calls the delivery method from the base class
# Creating instances of different subclasses
v = Veg_Zomato() # Object for vegetarian food ordering
nv = Non_Veg_Zomato() # Object for non-vegetarian food ordering
b = Blink_it() # Object for grocery delivery
# Calling display function to execute respective methods dynamically
display(v) # Displays veg menu and processes order
display(nv) # Displays non-veg menu and processes order
display(b) # Displays grocery menu, applies gold pass (if eligible), and processe
'''
The commented section below shows an alternative approach if we had separate
for each functionality instead of a generic menu() method in the base class:
v.food_list() # Lists vegetarian food
v.food_order() # Places order
v.order_delivered() # Delivers order
nv.food_list() # Lists non-vegetarian food
nv.food_order() # Places order
nv.order_delivered() # Delivers order
b.grocery_list() # Lists groceries
b.food_order() # Places order
b.order_delivered() # Delivers order
'''
Explanation
1. Class Zomato (Base Class): Defines common functionalities like menu() , order() ,
and delivery() .
2. Class Veg_Zomato & Non_Veg_Zomato (Subclasses): Override menu() to display only
veg or non-veg options.
Python Notes 154
c
o
d
e
r
s
n
o
t
e
.
c
o
m
3. Class Blink_it (Subclass): Overrides menu() for groceries and introduces a new
method gold_pass() .
4. Function display() : Uses Polymorphism to call appropriate methods
dynamically. Checks if the object is of type Blink_it before calling gold_pass() .
5. Object Creation: Instances of Veg_Zomato , Non_Veg_Zomato , and Blink_it are created
and passed to display() .
This program demonstrates inheritance, method overriding, and polymorphism
in Python.
Key Points:
Method Overloading in Python is achieved by using default arguments to
allow a method to accept varying numbers of arguments.
Method Overriding happens when a subclass provides its own
implementation of a method that is already defined in the parent class,
allowing the child class to change or extend the behavior of the parent class
method.
Polymorphism helps in writing more flexible and reusable code, as the same
method name can be used to perform different tasks depending on the context or
the object.
Encapsulation
Private and protected members ( _ , __ )
Getter and setter methods
Super()
class Parent:
def __init__(self, name):
self.name = name
print(f"Parent constructor called for {self.name}")
def show(self):
print(f"Hello, I am {self.name} from the Parent class.")
Python Notes 155
c
o
d
e
r
s
n
o
t
e
.
c
o
m
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # Call the parent class constructor
self.age = age
print(f"Child constructor called for {self.name}, Age: {self.age}")
def show(self):
super().show() # Call the parent class method
print(f"I am {self.name}, {self.age} years old, from the Child class.")
# Creating an object of the Child class
c = Child("Alice", 25)
c.show()
Encapsulation in Python
Encapsulation is one of the core principles of Object-Oriented Programming
(OOP). It is the concept of bundling the data (attributes) and methods (functions)
that operate on the data into a single unit or class. Encapsulation helps to protect
the data by restricting direct access to some of the object's components and can
be achieved by making attributes private and providing public getter and setter
methods to access and update those attributes.
1. Private and Protected Members
In Python, we can indicate that an attribute or method is private or protected using
special naming conventions:
Private members: Private members are variables or methods that cannot be
accessed directly outside the class. This is done by prefixing the variable or
method name with double underscores ( __ ).
Protected members: Protected members are intended to be used within the
class and its subclasses but can still be accessed outside. This is done by
prefixing the variable or method name with a single underscore ( _ ).
Python Notes 156
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Example of Private and Protected Members
class BankAccount:
def __init__(self, balance):
self._balance = balance # Protected member (conventionally)
self.__account_number = "12345" # Private member
# Getter method for balance
def get_balance(self):
return self._balance
# Setter method for balance with validation (Encapsulation)
def set_balance(self, amount):
if amount < 0:
print("Balance cannot be negative.")
else:
self._balance = amount
# Creating an instance of BankAccount
account = BankAccount(1000)
# Accessing protected member (not recommended, but possible)
print(account._balance) # Output: 1000
# Accessing private member (raises AttributeError)
# print(account.__account_number) # Uncommenting this line will give an err
or
# Using getter and setter methods
print(account.get_balance()) # Output: 1000
account.set_balance(500) # Updates balance to 500
print(account.get_balance()) # Output: 500
Private members (like __account_number ) cannot be accessed directly from
outside the class.
Python Notes 157
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Protected members (like _balance ) are intended to be used within the class and
its subclasses, but Python does not enforce any strict protection.
class Bankaccount:
def __init__(self, amount):
self.__amount = amount # Private attribute to store account balance
def set_amount(self, amount):
self.__amount = amount # Setter method to update account balance
def get_amount(self):
return self.__amount # Getter method to retrieve account balance
# Creating an object 'b' with an initial balance of 1000
b = Bankaccount(1000)
print(b.get_amount()) # Output: 1000 (Retrieves and prints the account balance)
b.set_amount(500) # Updates account balance to 500
print(b.get_amount()) # Output: 500 (Retrieves and prints the updated balance)
Explanation:
1. Encapsulation:
The class Bankaccount uses a private variable __amount , which cannot be
accessed directly outside the class.
Instead, we use getter ( get_amount() ) and setter ( set_amount() ) methods to
access and modify the balance.
2. __init__ Constructor:
It initializes the account with a given amount when an object is created.
3. Getter ( get_amount() ) Method:
Returns the value of __amount , ensuring controlled access to private data.
4. Setter ( set_amount() ) Method:
Python Notes 158
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Updates the balance with a new value, allowing controlled modification.
5. Object Creation & Method Calls:
An instance b is created with an initial balance of 1000.
get_amount() is called to retrieve the balance.
set_amount(500) modifies the balance.
get_amount() is called again to verify the update.
This implementation ensures data security by restricting direct modification of
__amount and enforcing controlled access through methods.
2. Getter and Setter Methods
Getter and setter methods are used to control the access to private or protected
members. They allow us to add validation or logic while getting or setting the
value of an attribute.
Example: Amazon Prime Auto-Debit Scenario (with condition)
Let's consider an example where an auto-debit feature is implemented for an
account that requires at least a balance of ₹499 to process the debit. The getter
and setter methods can be used to ensure this rule is followed.
class Account:
def __init__(self, balance):
self.__balance = balance # Private balance attribute
# Getter method for balance
def get_balance(self):
return self.__balance
# Setter method for balance with a condition (Encapsulation)
def set_balance(self, amount):
if amount < 0:
print("Balance cannot be negative.")
else:
self.__balance = amount
Python Notes 159
c
o
d
e
r
s
n
o
t
e
.
c
o
m
# Method to simulate auto-debit for services like Amazon Prime
def auto_debit(self, amount):
if self.get_balance() >= 499: # Checking if balance is enough for auto-de
bit
self.set_balance(self.get_balance() - amount)
print(f"₹{amount} debited successfully for Amazon Prime subscriptio
n.")
else:
print("Insufficient balance. Auto-debit failed.")
# Creating an instance of Account with ₹1000 balance
account = Account(1000)
# Simulating the auto-debit process
account.auto_debit(499) # Output: ₹499 debited successfully for Amazon Pri
me subscription.
# Checking balance after auto-debit
print("Remaining balance:", account.get_balance()) # Output: Remaining bala
nce: 501
# Trying to process auto-debit with less than ₹499 balance
account.set_balance(400) # Setting balance to ₹400
account.auto_debit(499) # Output: Insufficient balance. Auto-debit failed.
In this example:
The __balance attribute is private, so it cannot be accessed directly from outside
the class.
The getter method ( get_balance() ) allows us to retrieve the balance.
The setter method ( set_balance() ) allows us to set the balance, but it includes
validation to prevent negative balances.
The auto_debit() method checks if the balance is greater than or equal to ₹499
before proceeding with the debit. If the balance is insufficient, it displays an
Python Notes 160
c
o
d
e
r
s
n
o
t
e
.
c
o
m
error message.
Why Encapsulation?
Encapsulation allows us to:
1. Protect the data: By using private variables and providing controlled access
through getters and setters, we can prevent accidental modification of data
and ensure that the object’s state remains valid.
2. Maintain consistency: By adding logic (like the balance check in the auto_debit
method), we can ensure that invalid operations are prevented.
3. Improve flexibility: Encapsulation allows us to modify the internal workings of
a class without affecting the external code using it. For example, if we wanted
to change how the balance is calculated or stored, we could do so without
affecting how other parts of the program interact with the class.
Abstraction in Python
Abstraction is a fundamental concept in Object-Oriented Programming (OOP) that
hides implementation details and only exposes essential functionalities. Python
provides abstraction through abstract classes and methods, which are defined
using the ABC (Abstract Base Class) module.
Code Breakdown:
from abc import ABC, abstractmethod
ABC (Abstract Base Class): A built-in module that allows defining abstract
classes.
abstractmethod decorator: Used to declare methods that must be implemented
by child classes.
Creating an Abstract Class
Python Notes 161
c
o
d
e
r
s
n
o
t
e
.
c
o
m
class Learn2Code(ABC):
@abstractmethod
def course_list(self):
pass # Abstract method that must be implemented by subclasses
Learn2Code is an abstract class that serves as a blueprint.
The @abstractmethod decorator forces all subclasses to implement the course_list()
method.
The pass keyword is used since abstract methods don’t contain any
implementation.
Defining Subclasses that Inherit the Abstract Class
Subclass for Kids
class Kids(Learn2Code):
def course_list(self):
print("Courses for Kids: Scratch Programming, Math Games, Story Codin
g.")
This class inherits Learn2Code and implements the course_list() method.
Subclass for Non-IT Professionals
class NonIT(Learn2Code):
def course_list(self):
print("Courses for Non-IT: Basic Computer Skills, Digital Marketing, MS O
ffice.")
def mock_ai(self):
print("Mock AI session scheduled for interview preparation.")
This class implements course_list() and adds an extra method mock_ai() , which is
specific to Non-IT students.
Python Notes 162
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Subclass for Professionals
class Professional(Learn2Code):
def course_list(self):
print("Courses for Professionals: Data Science, Cloud Computing, Full St
ack Development.")
Implements course_list() without additional methods.
Displaying Courses Using a Common Function
def display(ref):
ref.course_list()
if isinstance(ref, NonIT): # Check if the instance is of type NonIT
ref.mock_ai()
The function display() takes an object ref and calls the course_list() method.
If ref is an instance of NonIT , it also calls mock_ai() .
Creating Objects and Calling Functions
kids_user = Kids()
non_it_user = NonIT()
professional_user = Professional()
display(kids_user)
display(non_it_user)
display(professional_user)
Objects are created for each subclass.
The display() function is called with each object to show the available courses.
Key Takeaways
Python Notes 163
c
o
d
e
r
s
n
o
t
e
.
c
o
m
1. Abstraction:
The abstract class hides implementation details and forces subclasses to
implement essential methods.
2. Abstract Methods:
Declared using @abstractmethod and must be overridden in subclasses.
3. Code Reusability:
The display() function provides a common interface to display course lists
for different student categories.
This approach ensures better organization, modularity, and flexibility in large
applications.
Module 10: Exception Handling
1. Introduction to Errors and Exceptions
Syntax errors vs. runtime exceptions
Common exceptions in Python ( ValueError , TypeError , IndexError , etc.)
1. Introduction to Errors and Exceptions
Syntax Errors vs. Runtime Exceptions
Errors in Python are broadly categorized into syntax errors and runtime
exceptions.
Syntax Errors
Occur when Python fails to understand the code due to incorrect syntax.
These are detected before the program runs.
Example:
print("Hello World" # Missing closing parenthesis -> SyntaxError
Output:
Python Notes 164
c
o
d
e
r
s
n
o
t
e
.
c
o
m
SyntaxError: unexpected EOF while parsing
Runtime Exceptions
Occur while executing the program, even if the syntax is correct.
Examples include ValueError , TypeError , IndexError , etc.
Common Exceptions in Python
1. ValueError
Occurs when a function receives an argument of the correct type but an
inappropriate value.
Example:
num = int("abc") # Cannot convert string "abc" to an integer
Output:
ValueError: invalid literal for int() with base 10: 'abc'
2. TypeError
Occurs when an operation is performed on an incorrect type.
Example:
result = "5" + 3 # Mixing string and integer
Output:
TypeError: can only concatenate str (not "int") to str
3. IndexError
Python Notes 165
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Occurs when trying to access an index that is out of range.
Example:
lst = [1, 2, 3]
print(lst[5]) # Index out of range
Output:
IndexError: list index out of range
2. Handling Exceptions
Using try , except , else , and finally
Catching specific exceptions
Using except Exception as e
Python provides the try-except block to handle exceptions gracefully.
Using try , except , else , and finally in Python
In Python, exception handling is done using try , except , else , and finally to manage
errors gracefully and ensure smooth program execution.
1. try Block:
The code that may raise an exception is placed inside the try block.
If an error occurs, the program jumps to the except block.
2. except Block:
Catches the exception and allows you to handle the error instead of
terminating the program.
Can specify multiple exception types or a general exception.
3. else Block (Optional):
Runs only if the try block executes successfully (i.e., no exception
occurs).
Python Notes 166
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Useful for executing code only when no errors are encountered.
4. finally Block (Optional):
Runs regardless of whether an exception occurs or not.
Typically used for resource cleanup (e.g., closing files, releasing network
connections).
Example
try:
num = int(input("Enter a number: ")) # May raise ValueError if input is not a
number
result = 10 / num # May raise ZeroDivisionError
except ValueError:
print("Invalid input! Please enter a valid number.")
except ZeroDivisionError:
print("Division by zero is not allowed.")
else:
print(f"Result: {result}") # Runs only if no exception occurs
finally:
print("Execution completed.") # Always executes
Key Takeaways
try : Contains the code that might cause an exception.
except : Handles specific or general exceptions.
else : Runs only if try executes without errors.
finally : Executes no matter what, ensuring cleanup actions.
Using these blocks together ensures robust and error-resilient code execution.
Raising Exceptions
Using raise keyword
Python Notes 167
c
o
d
e
r
s
n
o
t
e
.
c
o
m
Creating user-defined exceptions
Defining custom exception classes
3. Raising Exceptions
Using raise Keyword
Manually raise an exception if a condition is met.
def check_age(age):
if age < 18:
raise ValueError("Age must be 18 or older.")
return "Access granted"
print(check_age(15)) # Raises ValueError
Creating User-Defined Exceptions
Python allows creating custom exceptions by defining a new class.
class InvalidAgeError(Exception):
"""Custom exception for invalid age"""
pass
def check_voter_age(age):
if age < 18:
raise InvalidAgeError("You must be at least 18 to vote.")
return "Eligible to vote"
try:
print(check_voter_age(16))
except InvalidAgeError as e:
print("Custom Exception:", e)
Python Notes 168
c
o
d
e
r
s
n
o
t
e
.
c
o
m

More Related Content

Similar to Free Python Notes PDF - Python Crash Course (20)

PDF
Python Programing Bio computing,basic concepts lab,,
smohana4
 
PPT
Python Programming Language
Dr.YNM
 
PDF
Learnpython 151027174258-lva1-app6892
Neeraj Yadav
 
PDF
web programming UNIT VIII python by Bhavsingh Maloth
Bhavsingh Maloth
 
PPTX
Python_Introduction&DataType.pptx
HaythamBarakeh1
 
PPT
Introduction to python
Ranjith kumar
 
PPTX
Lacture 1- Programming using python.pptx
hello236603
 
PPTX
4_Introduction to Python Programming.pptx
Gnanesh12
 
PPTX
Fundamentals of Python Programming
Kamal Acharya
 
PPT
Py-Slides-1.ppt1234444444444444444444444444444444444444444
divijareddy0502
 
PPT
program on python what is python where it was started by whom started
rajkumarmandal9391
 
PPT
Python slides for the beginners to learn
krishna43511
 
PPT
Python Over View (Python for mobile app Devt)1.ppt
AbdurehmanDawud
 
PPT
Py-Slides-1.pptPy-Slides-1.pptPy-Slides-1.pptPy-Slides-1.ppt
v65176016
 
PPTX
Exploring Data Science Using Python Tools
mohankamalhbec24
 
PPTX
Introduction-to-Python-Programming1.pptx
vijayalakshmi257551
 
PDF
PYTHON PROGRAMMING NOTES RKREDDY.pdf
Ramakrishna Reddy Bijjam
 
PDF
Tutorial on-python-programming
Chetan Giridhar
 
PPTX
Introduction to Python Programing
sameer patil
 
PPT
PythonCourse_01_Intro.ppt Python introduction turorial for beginner.
sakchaisengsui
 
Python Programing Bio computing,basic concepts lab,,
smohana4
 
Python Programming Language
Dr.YNM
 
Learnpython 151027174258-lva1-app6892
Neeraj Yadav
 
web programming UNIT VIII python by Bhavsingh Maloth
Bhavsingh Maloth
 
Python_Introduction&DataType.pptx
HaythamBarakeh1
 
Introduction to python
Ranjith kumar
 
Lacture 1- Programming using python.pptx
hello236603
 
4_Introduction to Python Programming.pptx
Gnanesh12
 
Fundamentals of Python Programming
Kamal Acharya
 
Py-Slides-1.ppt1234444444444444444444444444444444444444444
divijareddy0502
 
program on python what is python where it was started by whom started
rajkumarmandal9391
 
Python slides for the beginners to learn
krishna43511
 
Python Over View (Python for mobile app Devt)1.ppt
AbdurehmanDawud
 
Py-Slides-1.pptPy-Slides-1.pptPy-Slides-1.pptPy-Slides-1.ppt
v65176016
 
Exploring Data Science Using Python Tools
mohankamalhbec24
 
Introduction-to-Python-Programming1.pptx
vijayalakshmi257551
 
PYTHON PROGRAMMING NOTES RKREDDY.pdf
Ramakrishna Reddy Bijjam
 
Tutorial on-python-programming
Chetan Giridhar
 
Introduction to Python Programing
sameer patil
 
PythonCourse_01_Intro.ppt Python introduction turorial for beginner.
sakchaisengsui
 

Recently uploaded (20)

PDF
QNL June Edition hosted by Pragya the official Quiz Club of the University of...
Pragya - UEM Kolkata Quiz Club
 
PPTX
HUMAN RESOURCE MANAGEMENT: RECRUITMENT, SELECTION, PLACEMENT, DEPLOYMENT, TRA...
PRADEEP ABOTHU
 
PPTX
PPT-Q1-WK-3-ENGLISH Revised Matatag Grade 3.pptx
reijhongidayawan02
 
PPTX
QUARTER 1 WEEK 2 PLOT, POV AND CONFLICTS
KynaParas
 
PDF
DIGESTION OF CARBOHYDRATES,PROTEINS,LIPIDS
raviralanaresh2
 
PPTX
Neurodivergent Friendly Schools - Slides from training session
Pooky Knightsmith
 
PDF
The Constitution Review Committee (CRC) has released an updated schedule for ...
nservice241
 
PPTX
care of patient with elimination needs.pptx
Rekhanjali Gupta
 
PDF
Horarios de distribución de agua en julio
pegazohn1978
 
PPTX
How to Set Up Tags in Odoo 18 - Odoo Slides
Celine George
 
PDF
Aprendendo Arquitetura Framework Salesforce - Dia 03
Mauricio Alexandre Silva
 
PDF
The History of Phone Numbers in Stoke Newington by Billy Thomas
History of Stoke Newington
 
PPT
Talk on Critical Theory, Part II, Philosophy of Social Sciences
Soraj Hongladarom
 
PPTX
EDUCATIONAL MEDIA/ TEACHING AUDIO VISUAL AIDS
Sonali Gupta
 
PDF
The Different Types of Non-Experimental Research
Thelma Villaflores
 
PPTX
Stereochemistry-Optical Isomerism in organic compoundsptx
Tarannum Nadaf-Mansuri
 
PPTX
Identifying elements in the story. Arrange the events in the story
geraldineamahido2
 
PPTX
I AM MALALA The Girl Who Stood Up for Education and was Shot by the Taliban...
Beena E S
 
PPTX
Post Dated Cheque(PDC) Management in Odoo 18
Celine George
 
PPTX
STAFF DEVELOPMENT AND WELFARE: MANAGEMENT
PRADEEP ABOTHU
 
QNL June Edition hosted by Pragya the official Quiz Club of the University of...
Pragya - UEM Kolkata Quiz Club
 
HUMAN RESOURCE MANAGEMENT: RECRUITMENT, SELECTION, PLACEMENT, DEPLOYMENT, TRA...
PRADEEP ABOTHU
 
PPT-Q1-WK-3-ENGLISH Revised Matatag Grade 3.pptx
reijhongidayawan02
 
QUARTER 1 WEEK 2 PLOT, POV AND CONFLICTS
KynaParas
 
DIGESTION OF CARBOHYDRATES,PROTEINS,LIPIDS
raviralanaresh2
 
Neurodivergent Friendly Schools - Slides from training session
Pooky Knightsmith
 
The Constitution Review Committee (CRC) has released an updated schedule for ...
nservice241
 
care of patient with elimination needs.pptx
Rekhanjali Gupta
 
Horarios de distribución de agua en julio
pegazohn1978
 
How to Set Up Tags in Odoo 18 - Odoo Slides
Celine George
 
Aprendendo Arquitetura Framework Salesforce - Dia 03
Mauricio Alexandre Silva
 
The History of Phone Numbers in Stoke Newington by Billy Thomas
History of Stoke Newington
 
Talk on Critical Theory, Part II, Philosophy of Social Sciences
Soraj Hongladarom
 
EDUCATIONAL MEDIA/ TEACHING AUDIO VISUAL AIDS
Sonali Gupta
 
The Different Types of Non-Experimental Research
Thelma Villaflores
 
Stereochemistry-Optical Isomerism in organic compoundsptx
Tarannum Nadaf-Mansuri
 
Identifying elements in the story. Arrange the events in the story
geraldineamahido2
 
I AM MALALA The Girl Who Stood Up for Education and was Shot by the Taliban...
Beena E S
 
Post Dated Cheque(PDC) Management in Odoo 18
Celine George
 
STAFF DEVELOPMENT AND WELFARE: MANAGEMENT
PRADEEP ABOTHU
 
Ad

Free Python Notes PDF - Python Crash Course

  • 1. Python Notes Python Programming Notes Disclaimer: These Python notes are exclusively for students who have enrolled in the Amend Ed Tech Python course or have purchased the notes through 📌Udemy or 📌 Tutorialspoint or 📌Gumroad or 📌Topmate. This material is intended for personal learning and reference only. Any unauthorized distribution, resale, reproduction, or sharing of these notes in any form—whether digital or printed—is strictly prohibited. Legal action may be taken against individuals or entities found violating these terms. Master Python with Visual Learning! Struggling to understand how Python works behind the scenes? Our course is designed to give you 100% clarity on program execution, straight from the RAM perspective! Python Notes 1 c o d e r s n o t e . c o m
  • 2. ✅Perfect for Beginners & Non-IT Students ✅Visual Learning Approach – See how code executes in memory! ✅Hands-on Examples & Real-World Scenarios 📌Start your Python journey today! 👉Enroll Now 🎉Struggling with Python? Get 30 Minutes FREE! 🎉 Need help with a Python concept? I’ll explain ANY topic you’re stuck on in a 1-on- 1 online session – in the simplest way possible! ✅First 30 minutes FREE! No risk, just learning! ✅Personalized explanations for your level ✅Visual learning for 100% clarity 📌Book your free session now and start mastering Python! 📩Need Quick Python Help? Chat on WhatsApp! 📩 Stuck on a Python concept? Get instant support and clear your doubts one-on- one via WhatsApp! ✅Quick & Easy Explanations ✅Ask Anytime, Get Answers Fast! 📌Message me now on WhatsApp and start mastering Python! Lets Start! What is Python? Python is a high-level, versatile programming language known for its simplicity and readability. It supports multiple programming paradigms, including object- oriented, procedural, and functional programming. Python is widely used in web development, data science, artificial intelligence, automation, and more, thanks to its extensive libraries and community support. It is also platform-independent and Python Notes 2 c o d e r s n o t e . c o m
  • 3. dynamically typed, making it a popular choice for beginners and professionals alike. Why is Python Popular? Python has become one of the most favored programming languages due to its simple syntax and flexibility. It is widely used in various domains like: Web Development Machine Learning & AI Game Development Data Science Python is open-source, easy to learn, and has a vast collection of libraries that make development faster and more efficient. 2. History of Python Python was created by Guido van Rossum in the early 1990s while working at CWI (Centrum Wiskunde & Informatica) in the Netherlands. How Python was Created: Guido and his team were developing a new operating system using the C language but found it too complex. During his break, he started working on a new language with simpler syntax and more features. Inspired by his favorite TV show, "Monty Python’s Flying Circus", he named the language Python. The Python logo was inspired by a snake, which is commonly associated with the name "Python". 3. Why Do Computers Use Binary (0s and 1s)? Computers process information using only binary values (0 and 1) because of the way their hardware is designed. Python Notes 3 c o d e r s n o t e . c o m
  • 4. Key Components of a Computer: 1. Microprocessor (CPU) 2. RAM (Random Access Memory) 3. HDD (Hard Disk Drive) or SSD (Solid-State Drive) How Computers Process Binary: Microprocessors use billions of transistors that function as switches: High voltage (ON) → Read as 1 Low voltage (OFF) → Read as 0 RAM uses capacitors: Charged capacitor → 1 Uncharged capacitor → 0 HDD uses magnetic storage technology: Magnetic patterns represent 1s and 0s Why Do We Need RAM if We Have HDD? RAM is volatile: Data is lost when power is turned off. HDD is non-volatile: Data is retained even after shutdown. Microprocessors access data from RAM, which is much faster than accessing it from HDD. Example: When you save a program, it is stored on the HDD. But when you run it, a copy is loaded into RAM, allowing the processor to execute it quickly. 4. Machine-Level and High-Level Languages Computers understand only binary (0s and 1s), known as Machine-Level Language (MLL). Evolution of Programming Languages: Before 1950: Programs were written in Machine-Level Language (MLL). Python Notes 4 c o d e r s n o t e . c o m
  • 5. After 1950: Assembly Language was introduced. 1957: IBM scientists developed High-Level Languages (HLL) like C and Java. How Code is Converted: Assembler: Converts Assembly Language into Machine Code. Compiler: Converts High-Level Language (HLL) (e.g., C, Java) into Machine- Level Language (MLL). Interpreter: Python uses an interpreter instead of a compiler (to be discussed in the next session). Python is a High-Level Language (HLL) but differs from compiled languages because it uses an interpreter, which executes code line by line. Compiler Vs Interpreter A compiler and an interpreter are both used to convert high-level programming languages into machine code, but they work differently. Compiler Translates the entire source code into machine code before execution. Generates an executable file that can be run multiple times without re- compilation. Faster execution since the entire program is compiled beforehand. Example languages: C, C++, Java Interpreter Translates code line by line and executes it immediately. Does not generate an executable file, requiring interpretation every time the program runs. Slower execution compared to compiled programs, but easier for debugging. Example languages: Python, JavaScript Python Notes 5 c o d e r s n o t e . c o m
  • 6. Key Differences Feature Compiler Interpreter Execution Entire code at once Line-by-line Speed Faster (pre-compilation) Slower (real-time execution) Debugging Harder (errors shown after compilation) Easier (stops at the first error) Output Generates an executable file No executable file Example Languages C, C++, Java Python, JavaScript Why Does Python Use an Interpreter? Python prioritizes ease of development over execution speed. Allows faster debugging since it executes code line-by-line. More flexible and supports dynamic typing. Installing Python Installing Python on Windows, macOS, and Linux: Download Python Setting up Python environment Installing and using IDEs (Spyder, Notepad++, cmd, online editor) Execute program in online Interpreter: Programiz Online Compiler Installing Spyder IDE: Spyder IDE Python Basics Writing your first Python program: print("Hello world") Python syntax and indentation Single and multi-line comments in Python: Single-line: # This is a comment Multi-line: ''' This is a multi-line comment ''' Python Notes 6 c o d e r s n o t e . c o m
  • 7. 2. Python Execution Modes Interactive Mode: Executes code line by line in the Python shell. Script Mode: Runs an entire Python script from a file. Introduction to RAM Segments - Code, Heap, Stack Note : Once you complete the course, read this RAM segment again for 100 percent clarity. When a Python program runs, the memory is divided into different segments: 1. Code Segment (Text Segment) Stores the compiled program instructions. Contains the machine code that the CPU executes. 2. Heap Segment Stores dynamically allocated memory (objects and variables created at runtime). Memory in this segment is managed by Python’s Garbage Collector. Variables and objects remain in the heap as long as they are referenced. 3. Stack Segment Stores function call frames and local variables. Follows a Last In, First Out (LIFO) structure. Each time a function is called, a new stack frame is pushed onto the stack. When a function returns, its stack frame is removed (popped). Understanding these memory segments helps in writing efficient programs and debugging memory-related issues in Python. Base 2 Format and Two’s Complement Base 2 (Binary) Representation Python Notes 7 c o d e r s n o t e . c o m
  • 8. Numbers in computers are represented using Base 2 (binary), which consists of only 0s and 1s . Example: Decimal 12 in binary: 1100 Decimal -12 needs Two’s Complement Representation. Two’s Complement Representation Two’s complement is a method for representing negative numbers in binary. Steps to find Two’s Complement: 1. Write the binary representation of the positive number. 2. Take the One’s Complement (invert all bits). 3. Add 1 to the result. Example: Finding 12 in two’s complement (using 8-bit representation): 1. 12 in binary (8-bit) → 00001100 2. One’s complement (invert bits) → 11110011 3. Add 1 → 11110100 Thus, -12 in two’s complement (8-bit) is: 11110100 . This method allows simple binary arithmetic operations and is widely used in computer systems. Module 2: Variables, Data Types, and Input/Output 1. Variables 1. Creating and Assigning Variables In Python, variables are created by simply assigning a value to a name using the assignment operator = . You don’t need to declare the type of the variable explicitly; Python will automatically determine it based on the value assigned. Example: Python Notes 8 c o d e r s n o t e . c o m
  • 9. x = 10 # Integer assignment name = "Alice" # String assignment pi = 3.14159 # Float assignment Here, x is assigned the value 10 , name is assigned the string "Alice" , and pi is assigned the floating-point value 3.14159 . 2. Variable Naming Conventions There are several rules and best practices to follow when naming variables in Python: Rules: Variable names must start with a letter (a-z, A-Z) or an underscore (_). The rest of the variable name can include letters, numbers (0-9), and underscores. Variable names are case-sensitive ( name , Name , and NAME are all different). Reserved words (keywords) like if , else , True , False , and class cannot be used as variable names. Best Practices: Use descriptive names that convey the purpose of the variable. Use underscores ( _ ) to separate words in variable names (snake_case). Avoid using single-letter variables except for counters or temporary variables (e.g., i , j ). For constants, use all uppercase letters with underscores between words. Examples: user_age = 25 # Descriptive variable name max_speed = 120 # Descriptive name using snake_case Python Notes 9 c o d e r s n o t e . c o m
  • 10. 3. Constants in Python In Python, constants are typically defined by convention. Although Python does not have built-in support for constants like some other programming languages, constants are usually written in all uppercase letters with underscores to separate words. By convention, you should not modify the value of constants after they are set. Example: PI = 3.14159 # Constant for Pi MAX_USERS = 100 # Constant for max number of users These variables are treated as constants by convention, and you should not change their values within your code. However, Python won't stop you from changing them; it's just a best practice to treat them as immutable. Data Types Numeric types: int , float , complex Boolean type: bool Sequence types: str , list , tuple Mapping type: dict Set types: set 1. Numeric Types: int , float , complex int (Integer): Description: Represents whole numbers (positive, negative, or zero). Example: a = 10 # Positive integer Python Notes 10 c o d e r s n o t e . c o m
  • 11. print(a) x = 10 # Positive integer y = -3 # Negative integer print(type(x)) # <class 'int'> float (Floating-Point Number): Description: Represents real numbers (numbers with a decimal point). Example: x = 10.5 # Positive float y = -3.14 # Negative float print(type(x)) # <class 'float'> complex (Complex Number): Description: Represents complex numbers in the form of a + bj , where a is the real part and b is the imaginary part. Example: x = 3 + 5j # Complex number print(type(x)) # <class 'complex'> 2. Boolean Type: bool bool (Boolean): Description: Represents True or False . Example: Python Notes 11 c o d e r s n o t e . c o m
  • 12. a = True b = False print(type(a)) # <class 'bool'> 3. Sequence Types: str , list , tuple str (String): Description: Represents text data. Example: name = "Alice" print(type(name)) # <class 'str'> list (List): Description: A mutable, ordered collection of items (can be of different types). Example: fruits = ["apple", "banana", "cherry"] print(type(fruits)) # <class 'list'> tuple (Tuple): Description: An immutable, ordered collection of items. Example: point = (2, 3) print(type(point)) # <class 'tuple'> 4. Set Types: set Python Notes 12 c o d e r s n o t e . c o m
  • 13. set (Set): Description: A collection of unique, unordered items. Example: unique_numbers = {1, 2, 3, 4} print(type(unique_numbers)) # <class 'set'> 5. Mapping Type: dict dict (Dictionary): Description: A collection of key-value pairs, where each key is unique. Example: student = {"name": "Alice", "age": 20} print(type(student)) # <class 'dict'> 1. Type Conversion V7 - 3 Implicit and explicit type casting Using functions like int() , float() , str() , list() , tuple() 1. Implicit Type Casting (Automatic Type Conversion) Description: Implicit type casting happens automatically when Python converts one data type to another without the user’s intervention. It occurs when a smaller data type is converted into a larger one, for example, converting an int to a float . Python does this automatically to prevent data loss. Example of Implicit Type Casting: x = 5 # int y = 2.5 # float Python Notes 13 c o d e r s n o t e . c o m
  • 14. result = x + y # Python automatically converts x (int) to a float print(result) # Output: 7.5 print(type(result)) # <class 'float'> Here, x (an integer) is implicitly converted to a float to allow the addition with y (a float). The result is a float . 2. Explicit Type Casting (Manual Type Conversion) Description: Explicit type casting occurs when the user manually converts a data type to another using built-in functions like int() , float() , str() , etc. This is needed when you want to convert data types in a controlled way. Example of Explicit Type Casting: x = 10.5 # float y = int(x) # manually converting float to int print(y) # Output: 10 print(type(y)) # <class 'int'> In this case, the float value of x is explicitly converted to an int using the int() function. This process truncates the decimal part ( .5 ) and gives 10 as the result. 3. Type Conversion Functions Below are some commonly used functions for type conversion in Python: int() : Converts a value to an integer. Description: Used to convert a number or a string representing a number to an integer. Example: # Converting a float to int x = 12.75 Python Notes 14 c o d e r s n o t e . c o m
  • 15. y = int(x) # Conversion from float to int print(y) # Output: 12 # Converting a string to int str_num = "45" num = int(str_num) print(num) # Output: 45 float() : Converts a value to a float. Description: Used to convert an integer, string, or other numeric types to a float. Example: # Converting an integer to float x = 10 y = float(x) # Conversion from int to float print(y) # Output: 10.0 # Converting a string to float str_num = "3.14" num = float(str_num) print(num) # Output: 3.14 str() : Converts a value to a string. Description: Used to convert numbers, lists, tuples, etc., into their string representation. Example: # Converting an integer to string x = 100 str_x = str(x) # Conversion from int to string print(str_x) # Output: "100" print(type(str_x)) # <class 'str'> Python Notes 15 c o d e r s n o t e . c o m
  • 16. # Converting a float to string pi = 3.14159 str_pi = str(pi) print(str_pi) # Output: "3.14159" list() : Converts an iterable (like a tuple or string) to a list. Description: Converts any iterable object (such as a string or tuple) into a list. Example: # Converting a string to a list str_data = "hello" list_data = list(str_data) print(list_data) # Output: ['h', 'e', 'l', 'l', 'o'] # Converting a tuple to a list tuple_data = (1, 2, 3) list_data = list(tuple_data) print(list_data) # Output: [1, 2, 3] tuple() : Converts an iterable (like a list or string) to a tuple. Description: Converts any iterable object (such as a list or string) into a tuple. Example: # Converting a list to a tuple list_data = [1, 2, 3] tuple_data = tuple(list_data) print(tuple_data) # Output: (1, 2, 3) # Converting a string to a tuple str_data = "abc" Python Notes 16 c o d e r s n o t e . c o m
  • 17. tuple_data = tuple(str_data) print(tuple_data) # Output: ('a', 'b', 'c') Example Program: Demonstrating Type Conversion # Implicit and Explicit Type Casting Example # Implicit Type Casting x = 5 # int y = 3.2 # float result = x + y # implicit conversion of x (int) to float print(result) # Output: 8.2 # Explicit Type Casting z = "123" # string num = int(z) # explicit conversion of string to int print(num) # Output: 123 # Converting to float float_num = float(num) # explicit conversion of int to float print(float_num) # Output: 123.0 # Converting to string str_num = str(float_num) # explicit conversion of float to string print(str_num) # Output: "123.0" Output: 8.2 123 123.0 123.0 Python Notes 17 c o d e r s n o t e . c o m
  • 18. Key Takeaways: Implicit Type Casting happens automatically when Python promotes smaller data types to larger ones, such as from int to float . Explicit Type Casting requires the use of functions like int() , float() , str() , etc., to manually convert between data types. Functions like int() , float() , str() , list() , and tuple() are commonly used for converting between different data types, depending on your need. Input and Output input() function print() function Formatting output using str.format() Using f-strings (formatted string literals) 1. input() Function Description: The input() function is used to take user input from the console in Python. The input is always returned as a string, even if the user enters numeric values. Syntax: input(prompt) prompt : An optional string to display to the user as a prompt. Example: # Basic input example name = input("Enter your name: ") print("Hello, " + name + "!") # Taking numeric input Python Notes 18 c o d e r s n o t e . c o m
  • 19. age = input("Enter your age: ") age = int(age) # Converting the input to an integer print("Your age is:", age) Output: Enter your name: Harish Hello, Harish! Enter your age: 27 Your age is: 27 In this example, we used input() to get the user's name and age. The input is taken as a string, and we converted the age input to an integer. 2. print() Function Description: The print() function is used to display output on the screen. Syntax: print(*objects, sep=' ', end='n') objects : The values to print. sep : A string inserted between the objects (default is a space). end : A string appended after the last object (default is a newline). Example: # Basic print example print("Hello, World!") # Output: Hello, World! # Print multiple items with custom separator print("Hello", "World", sep=" - ") # Output: Hello - World Python Notes 19 c o d e r s n o t e . c o m
  • 20. # Print with custom end print("Hello", end=" ") # Output: Hello (without a newline) print("World!") # Output: World! Output: Hello, World! Hello - World Hello World! The print() function can take multiple arguments and print them with a customizable separator and end character. Key Takeaways: input() is used to get input from the user (always returns a string). print() displays output and can accept multiple arguments with custom separators and line endings. String Formatting in Python Note: Video tutorial for format strings and f-strings in the strings topic—watch the tutorial first, or else you won’t be able to understand. Python provides several ways to format strings. Two popular methods for string formatting are str.format() and f-strings (formatted string literals). 1. Using str.format() The str.format() method allows you to embed variables or expressions inside a string by using placeholders (curly braces {} ). You can then pass values to be formatted into the string. Basic Usage name = "Alice" age = 25 Python Notes 20 c o d e r s n o t e . c o m
  • 21. message = "My name is {} and I am {} years old.".format(name, age) print(message) # Output: My name is Alice and I am 25 years old. Positional Arguments You can specify the order of placeholders in the string, and match them with arguments passed to format() . message = "My name is {0} and I am {1} years old. {0} is my first name.".form at(name, age) print(message) # Output: My name is Alice and I am 25 years old. Alice is my first name. Keyword Arguments Instead of using positional arguments, you can use keyword arguments to specify the placeholders. message = "My name is {name} and I am {age} years old.".format(name="Alic e", age=25) print(message) # Output: My name is Alice and I am 25 years old. Reusing Variables You can reuse variables multiple times in the format string. message = "My name is {0} and {0} loves coding.".format(name) print(message) # Output: My name is Alice and Alice loves coding. Formatting Numbers You can format numbers with specific formatting instructions (e.g., rounding, padding). pi = 3.14159 formatted = "Pi to two decimal places: {:.2f}".format(pi) Python Notes 21 c o d e r s n o t e . c o m
  • 22. print(formatted) # Output: Pi to two decimal places: 3.14 2. f-Strings (Formatted String Literals) Introduced in Python 3.6, f-strings provide a concise and more readable way to embed expressions inside string literals. An f-string is prefixed with f before the string, and you can directly embed variables or expressions inside curly braces {} within the string. Basic Usage name = "Alice" age = 25 message = f"My name is {name} and I am {age} years old." print(message) # Output: My name is Alice and I am 25 years old. Expressions Inside f-strings You can use expressions within the curly braces inside an f-string. a = 5 b = 10 message = f"The sum of {a} and {b} is {a + b}." print(message) # Output: The sum of 5 and 10 is 15. Formatting Numbers Just like with str.format() , f-strings also support formatting options. pi = 3.14159 formatted = f"Pi to two decimal places: {pi:.2f}" print(formatted) # Output: Pi to two decimal places: 3.14 Using Expressions for Method Calls or Accessing Attributes You can call methods or access attributes directly within f-strings. Python Notes 22 c o d e r s n o t e . c o m
  • 23. text = "hello world" message = f"The uppercase version of the text is {text.upper()}" print(message) # Output: The uppercase version of the text is HELLO WORLD Comparison: str.format() vs f-strings Feature str.format() f-strings Syntax "{} or {0} , {name} f"{}" Readability More verbose More concise and readable Performance Slightly slower Faster and more efficient (since it is evaluated at runtime) Use of Expressions Expressions are passed as arguments Directly evaluates expressions inside {} Python Version Requirement Works in Python 2.7 and later Works only in Python 3.6 and later Both str.format() and f-strings allow you to embed variables and expressions inside strings. However, f-strings are more concise and efficient, making them the preferred choice in Python 3.6 and later. If you need to support older versions of Python, str.format() is a great alternative. Module 3: Operators and Expressions 1. Arithmetic Operators Addition ( + ), subtraction ( ), multiplication ( ), division ( / ) Floor division ( // ), modulus ( % ), exponentiation ( * ) 1. Arithmetic Operators in Python Python provides several operators to perform arithmetic operations. These include basic operations like addition and multiplication, as well as more advanced operations such as floor division, modulus, and exponentiation. Python Notes 23 c o d e r s n o t e . c o m
  • 24. Basic Arithmetic Operators: Addition ( + ): Adds two numbers. Subtraction ( ): Subtracts one number from another. Multiplication ( ): Multiplies two numbers. Division ( / ): Divides one number by another and returns a floating-point result. Advanced Arithmetic Operators: Floor Division ( // ): Divides one number by another and returns the quotient as an integer (rounded down to the nearest whole number). Modulus ( % ): Returns the remainder after dividing two numbers. 2. Examples of Arithmetic Operations Let’s go over each operator with examples to understand how they work: Addition ( + ): Adds two numbers together. a = 10 b = 5 result = a + b print(result) # Output: 15 Subtraction ( ): Subtracts the second number from the first. a = 10 b = 5 result = a - b print(result) # Output: 5 Python Notes 24 c o d e r s n o t e . c o m
  • 25. Multiplication ( ): Multiplies two numbers. a = 10 b = 5 result = a * b print(result) # Output: 50 Division ( / ): Divides the first number by the second, and the result is always a float. a = 10 b = 3 result = a / b print(result) # Output: 3.3333333333333335 (float) Floor Division ( // ): Divides the first number by the second and returns the quotient rounded down to the nearest integer. a = 10 b = 3 result = a // b print(result) # Output: 3 (rounded down from 3.333) Modulus ( % ): Returns the remainder of the division. a = 10 b = 3 result = a % b print(result) # Output: 1 (because 10 divided by 3 leaves a remainder of 1) Python Notes 25 c o d e r s n o t e . c o m
  • 26. Exponentiation ( * ): Raises the first number to the power of the second. a = 2 b = 3 result = a ** b print(result) # Output: 8 (2 raised to the power of 3) 4. Summary of Arithmetic Operators Operator Description Example + Addition (adds two numbers) 5 + 3 = 8 - Subtraction (subtracts second number from first) 5 - 3 = 2 * Multiplication (multiplies two numbers) 5 * 3 = 15 / Division (returns float result) 5 / 3 = 1.6667 // Floor Division (returns integer quotient) 5 // 3 = 1 % Modulus (returns remainder of division) 5 % 3 = 2 ** Exponentiation (raises the first number to the power of the second) 5 ** 3 = 125 Key Takeaways: Arithmetic operators are fundamental to working with numerical values in Python. Basic operations such as addition, subtraction, multiplication, and division are straightforward. Advanced operations like floor division, modulus, and exponentiation provide useful tools for mathematical calculations. You can combine these operators in complex expressions to perform a wide range of calculations. Comparison Operators Python Notes 26 c o d e r s n o t e . c o m
  • 27. Equal to ( == ), not equal to ( != ), greater than ( > ), less than ( < ), greater than or equal to ( >= ), less than or equal to ( <= ) Comparison Operators in Python Comparison operators are used to compare two values or variables. These operators return a Boolean value ( True or False ), indicating the result of the comparison. 1. Equal to ( == ) Description: Compares if two values are equal. Example: a = 10 b = 10 result = (a == b) # Returns True if a equals b print(result) # Output: True 2. Not equal to ( != ) Description: Compares if two values are not equal. Example: a = 10 b = 5 result = (a != b) # Returns True if a is not equal to b print(result) # Output: True 3. Greater than ( > ) Description: Checks if the value on the left is greater than the value on the right. Example: Python Notes 27 c o d e r s n o t e . c o m
  • 28. a = 10 b = 5 result = (a > b) # Returns True if a is greater than b print(result) # Output: True 4. Less than ( < ) Description: Checks if the value on the left is less than the value on the right. Example: a = 5 b = 10 result = (a < b) # Returns True if a is less than b print(result) # Output: True 5. Greater than or equal to ( >= ) Description: Checks if the value on the left is greater than or equal to the value on the right. Example: a = 10 b = 5 result = (a >= b) # Returns True if a is greater than or equal to b print(result) # Output: True 6. Less than or equal to ( <= ) Description: Checks if the value on the left is less than or equal to the value on the right. Example: Python Notes 28 c o d e r s n o t e . c o m
  • 29. a = 5 b = 10 result = (a <= b) # Returns True if a is less than or equal to b print(result) # Output: True Summary of Comparison Operators Operator Description Example == Equal to (checks if two values are equal) a == b != Not equal to (checks if two values are not equal) a != b > Greater than (checks if left is greater than right) a > b < Less than (checks if left is less than right) a < b >= Greater than or equal to (checks if left is greater than or equal to right) a >= b <= Less than or equal to (checks if left is less than or equal to right) a <= b Key Takeaways: Comparison operators are essential for conditional checks and decision- making. These operators return Boolean values ( True or False ), which are used in control structures like if , while , etc. You can chain comparison operators together to create complex conditions. Logical Operators and , or , not Logical Operators in Python Logical operators are used to perform logical operations on Boolean values (i.e., True or False ). They are commonly used in conditional statements to combine Python Notes 29 c o d e r s n o t e . c o m
  • 30. multiple conditions. 1. and Operator Description: The and operator returns True if both conditions are True . If either or both conditions are False , the result will be False . Syntax: condition1 and condition2 Example: a = 5 b = 10 # Both conditions must be True result = (a > 0) and (b > 0) print(result) # Output: True (both conditions are True) result = (a > 0) and (b < 0) print(result) # Output: False (second condition is False) 2. or Operator Description: The or operator returns True if at least one of the conditions is True . If both conditions are False , the result will be False . Syntax: condition1 or condition2 Example: a = 5 b = -10 # At least one condition must be True result = (a > 0) or (b > 0) print(result) # Output: True (first condition is True) Python Notes 30 c o d e r s n o t e . c o m
  • 31. result = (a < 0) or (b > 0) print(result) # Output: False (both conditions are False) 3. not Operator Description: The not operator is used to invert a Boolean value. It returns True if the condition is False , and False if the condition is True . Syntax: not condition Example: a = 5 b = -10 # Inverts the result of the condition result = not (a > 0) print(result) # Output: False (because a > 0 is True, so not True is False) result = not (b > 0) print(result) # Output: True (because b > 0 is False, so not False is True) Truth Tables for Logical Operators Here’s how the logical operators behave for all possible combinations of True and False : Condition 1 Condition 2 and (Condition1 and Condition2) or (Condition1 or Condition2) not (not Condition1) True True True True False True False False True False False True False True True False False False False True Summary of Logical Operators Python Notes 31 c o d e r s n o t e . c o m
  • 32. Operator Description Example and Returns True if both conditions are True (a > 0) and (b > 0) or Returns True if at least one condition is True (a > 0) or (b > 0) not Inverts the Boolean value of a condition not (a > 0) Key Takeaways: Logical operators are essential for combining multiple conditions in if statements or loops. The and operator ensures all conditions must be true. The or operator requires only one condition to be true. The not operator inverts the result of a condition. Assignment Operators Basic: = , += , = , = , /= , //= , %= , *= 1. Basic Assignment ( = ) Description: The simplest form of assignment. It assigns the value on the right to the variable on the left. Syntax: variable = value Example: a = 5 print(a) # Output: 5 2. Addition Assignment ( += ) Description: Adds the value on the right to the variable on the left and assigns the result back to the variable. Python Notes 32 c o d e r s n o t e . c o m
  • 33. Syntax: variable += value Example: a = 5 a += 3 # equivalent to a = a + 3 print(a) # Output: 8 3. Subtraction Assignment ( = ) Description: Subtracts the value on the right from the variable on the left and assigns the result back to the variable. Syntax: variable -= value Example: a = 10 a -= 4 # equivalent to a = a - 4 print(a) # Output: 6 4. Multiplication Assignment ( = ) Description: Multiplies the variable by the value on the right and assigns the result back to the variable. Syntax: variable *= value Example: a = 6 a *= 2 # equivalent to a = a * 2 print(a) # Output: 12 5. Division Assignment ( /= ) Python Notes 33 c o d e r s n o t e . c o m
  • 34. Description: Divides the variable by the value on the right and assigns the result back to the variable. The result is always a float, even if both operands are integers. Syntax: variable /= value Example: a = 10 a /= 2 # equivalent to a = a / 2 print(a) # Output: 5.0 6. Floor Division Assignment ( //= ) Description: Divides the variable by the value on the right using floor division (returns the integer part of the quotient) and assigns the result back to the variable. Syntax: variable //= value Example: a = 10 a //= 3 # equivalent to a = a // 3 print(a) # Output: 3 7. Modulus Assignment ( %= ) Description: Takes the modulus (remainder) of the variable when divided by the value on the right and assigns the result back to the variable. Syntax: variable %= value Example: a = 10 a %= 3 # equivalent to a = a % 3 Python Notes 34 c o d e r s n o t e . c o m
  • 35. print(a) # Output: 1 8. Exponentiation Assignment ( *= ) Description: Raises the variable to the power of the value on the right and assigns the result back to the variable. Syntax: variable **= value Example: a = 2 a **= 3 # equivalent to a = a ** 3 print(a) # Output: 8 Summary of Assignment Operators Operator Description Example Result = Assigns the value on the right to the variable a = 5 a = 5 += Adds the value on the right to the variable a += 3 (i.e., a = a + 3 ) Adds 3 to a -= Subtracts the value on the right from the variable a -= 2 (i.e., a = a - 2 ) Subtracts 2 from a *= Multiplies the variable by the value on the right a *= 4 (i.e., a = a * 4 ) Multiplies a by 4 /= Divides the variable by the value on the right a /= 2 (i.e., a = a / 2 ) Divides a by 2, result is float //= Performs floor division and assigns the result a //= 2 (i.e., a = a // 2 ) Performs floor division %= Assigns the remainder of the division to the variable a %= 3 (i.e., a = a % 3 ) Stores remainder of a / 3 **= Raises the variable to the power of the value a **= 2 (i.e., a = a ** 2 ) Raises a to the power of 2 Python Notes 35 c o d e r s n o t e . c o m
  • 36. Example Program Using Assignment Operators # Initial value of a a = 10 # Using different assignment operators a += 5 # a = a + 5 print(f"a after += 5: {a}") # Output: 15 a -= 3 # a = a - 3 print(f"a after -= 3: {a}") # Output: 12 a *= 2 # a = a * 2 print(f"a after *= 2: {a}") # Output: 24 a /= 4 # a = a / 4 print(f"a after /= 4: {a}") # Output: 6.0 a //= 2 # a = a // 2 (floor division) print(f"a after //= 2: {a}") # Output: 3.0 a %= 2 # a = a % 2 (remainder) print(f"a after %= 2: {a}") # Output: 1.0 a **= 3 # a = a ** 3 (exponentiation) print(f"a after **= 3: {a}") # Output: 1.0 Key Takeaways: Assignment operators simplify modifying variables in Python, making your code more concise. These operators help to combine assignment and arithmetic or other operations in a single step. Python Notes 36 c o d e r s n o t e . c o m
  • 37. The += , = , = , /= , //= , %= and *= operators are especially useful when working with numbers. Module 4: Control Flow 1. Conditional Statements if statement if-else statement if-elif-else statement Nested if statements Conditional Statements in Python In Python, conditional statements allow you to execute different blocks of code depending on certain conditions. This is how your program can make decisions based on specific inputs or states. 1. if Statement The if statement evaluates a condition (a boolean expression) and executes a block of code if the condition is True . Syntax: if condition: # Code block to execute if condition is True Example: age = 18 if age >= 18: print("You are eligible to vote!") Python Notes 37 c o d e r s n o t e . c o m
  • 38. In this example, the condition age >= 18 is True , so the message "You are eligible to vote!" will be printed. 2. if-else Statement An if-else statement provides an alternative action if the condition is False . It has two code blocks: one that is executed if the condition is True , and the other if the condition is False . Syntax: if condition: # Code block to execute if condition is True else: # Code block to execute if condition is False Example: age = 16 if age >= 18: print("You are eligible to vote!") else: print("You are not eligible to vote yet.") In this case, since the condition age >= 18 is False , the else block will be executed, and the message "You are not eligible to vote yet." will be printed. 3. if-elif-else Statement The if-elif-else statement allows you to check multiple conditions. The program will evaluate the conditions in order and execute the block of code for the first True condition. If none of the conditions are True , the else block will be executed. Syntax: Python Notes 38 c o d e r s n o t e . c o m
  • 39. if condition1: # Code block for condition1 elif condition2: # Code block for condition2 else: # Code block if no conditions are True Example: age = 25 if age >= 60: print("You are a senior citizen.") elif age >= 18: print("You are an adult.") else: print("You are a minor.") Here, since age is 25 , the condition age >= 18 is True , so the program will print "You are an adult." 4. Nested if Statements You can place one if statement inside another to check additional conditions only after the outer condition is True . This is called nesting. Syntax: if condition1: if condition2: # Code block if both conditions are True else: # Code block if condition1 is True and condition2 is False Python Notes 39 c o d e r s n o t e . c o m
  • 40. else: # Code block if condition1 is False Example: # Program to check if a number is positive, and if it's even or odd number = int(input("Enter a number: ")) if number > 0: # Outer if print("The number is positive.") if number % 2 == 0: # Nested if print("It is also an even number.") else: # Nested else print("It is an odd number.") else: # Outer else print("The number is not positive.") In this example: The first if checks if the person is 18 or older. If the person is eligible to vote ( age >= 18 ), it checks if they have a voter ID with a nested if statement. If the person doesn't have a voter ID, the second else block prints a message saying they cannot vote. Summary of Conditional Statements: 1. if Statement: Executes code if the condition is True . 2. if-else Statement: Executes one block of code if the condition is True , otherwise executes another block if False . 3. if-elif-else Statement: Checks multiple conditions in sequence and executes the block for the first True condition. If no conditions are True , the else block is executed. Python Notes 40 c o d e r s n o t e . c o m
  • 41. 4. Nested if Statements: Placing if statements inside other if statements to check additional conditions. Loops for loop Iterating over sequences Using range() function for Loop in Python A for loop in Python is used to iterate over a sequence (like a list, tuple, string, or range) and execute a block of code multiple times. It is commonly used when you want to iterate through each item in a collection. 1. Iterating Over Sequences A sequence can be a list, tuple, string, or any other iterable object. The for loop will iterate over each element of the sequence and execute the block of code for each element. Syntax: for variable in sequence: # Code block to execute for each item in the sequence Example (Iterating over a list): fruits = ["apple", "banana", "cherry"] for fruit in fruits: print(fruit) Output: Python Notes 41 c o d e r s n o t e . c o m
  • 42. apple banana cherry In this example, the loop iterates over each element in the list fruits , and the print(fruit) statement is executed for each element. Example (Iterating over a string): word = "hello" for char in word: print(char) Output: h e l l o In this example, the loop iterates over each character in the string "hello" , printing each character one by one. 2. Using range() Function The range() function is commonly used with for loops to generate a sequence of numbers. It can be used to specify the number of iterations you want the loop to execute. The range() function can take one, two, or three arguments: range(stop) : Generates numbers from 0 to stop - 1 . range(start, stop) : Generates numbers from start to stop - 1 . range(start, stop, step) : Generates numbers from start to stop - 1 , with a step size of step . Python Notes 42 c o d e r s n o t e . c o m
  • 43. Example (Using range() with one argument): for i in range(5): # Will iterate over 0, 1, 2, 3, 4 print(i) Output: 0 1 2 3 4 In this example, range(5) generates the numbers from 0 to 4 , and the loop prints each number. Example (Using range() with two arguments): for i in range(2, 7): # Will iterate over 2, 3, 4, 5, 6 print(i) Output: 2 3 4 5 6 In this example, range(2, 7) generates the numbers from 2 to 6 , and the loop prints each number. Example (Using range() with three arguments): for i in range(1, 10, 2): # Will iterate over 1, 3, 5, 7, 9 Python Notes 43 c o d e r s n o t e . c o m
  • 44. print(i) Output: 1 3 5 7 9 In this example, range(1, 10, 2) generates numbers from 1 to 9 with a step size of 2 , and the loop prints each number. Combining for Loop and range() You can use the range() function inside a for loop to repeat a block of code a specific number of times. This is useful when you want to perform actions a certain number of times without explicitly creating a sequence. Example (Using for loop with range() to repeat actions): for i in range(3): print(f"Iteration {i + 1}") Output: Iteration 1 Iteration 2 Iteration 3 Summary of for Loop Concepts: 1. Iterating Over Sequences: The for loop can be used to iterate over any iterable object (list, string, tuple, etc.). 2. Using range() : Python Notes 44 c o d e r s n o t e . c o m
  • 45. range(stop) generates numbers from 0 to stop - 1 . range(start, stop) generates numbers from start to stop - 1 . range(start, stop, step) generates numbers with a specific step size. 3. Use Cases: Iterating over items in a collection. Repeating a block of code a specific number of times using range() . while loop Loop conditions and infinite loops Loop control statements: break continue pass while Loop in Python A while loop in Python repeatedly executes a block of code as long as a given condition is True . Once the condition becomes False , the loop stops. 1. Loop Conditions in while Loop The while loop continues to execute the code inside it as long as the condition evaluates to True . Once the condition becomes False , the loop stops, and the program proceeds to the next line of code after the loop. Syntax: while condition: # Code block The condition is checked at the start of each iteration. Python Notes 45 c o d e r s n o t e . c o m
  • 46. If the condition evaluates to True , the loop continues. If the condition evaluates to False , the loop ends. Example: count = 0 while count < 3: print(count) count += 1 Output: 0 1 2 In this example, the while loop runs as long as count < 3 . After each iteration, the value of count is incremented, and when it reaches 3 , the condition becomes False , and the loop stops. 2. Infinite Loops An infinite loop occurs when the condition in the while loop is always True , meaning the loop will run forever unless manually stopped. These are often unintended and can cause the program to freeze or crash. Example (Infinite loop): while True: print("This will run forever!") Output (Continuously printing): This will run forever! This will run forever! Python Notes 46 c o d e r s n o t e . c o m
  • 47. This will run forever! ... To stop this infinite loop, you would either manually stop the program (using Ctrl + C ), or the program must have a control structure like break to stop it under certain conditions. Loop Control Statements Loop control statements are used to control the flow of execution in loops. They allow you to skip iterations, break out of the loop, or execute certain code under specific conditions. 1. break Statement The break statement is used to terminate the loop immediately, regardless of the loop's condition. It can be used in both for and while loops. When the break statement is executed, the loop stops, and the program moves on to the next statement after the loop. Example (Using break ): count = 0 while count < 10: if count == 5: break # Exit the loop when count is 5 print(count) count += 1 Output: 0 1 2 3 4 Python Notes 47 c o d e r s n o t e . c o m
  • 48. Prime Number n = 6 for i in range(2,n+1): if n%i==0: break if n==i: print(n , "is prime") else: print(n , "is not prime") In this example, the loop will stop when count becomes 5 because of the break statement. It immediately exits the loop, and the program continues to the next line after the loop. 2. continue Statement The continue statement is used to skip the current iteration and move on to the next iteration of the loop. It does not terminate the loop; instead, it skips over the remaining code in the current iteration and proceeds with the next loop cycle. Example (Using continue ): count = 0 while count < 5: count += 1 if count == 3: continue # Skip printing when count is 3 print(count) Output: Python Notes 48 c o d e r s n o t e . c o m
  • 49. 1 2 4 5 In this example, when count equals 3 , the continue statement is executed, and the print(count) statement is skipped for that iteration. The loop then moves on to the next value of count . 3. pass Statement The pass statement is a null operation. It is used as a placeholder when you need a syntactically valid statement but don’t want to execute any code. It is often used in loops, functions, or classes where the code is yet to be implemented. Example (Using pass ): count = 0 while count < 5: count += 1 if count == 3: pass # Do nothing when count is 3 print(count) Output: 1 2 3 4 5 In this example, when count equals 3 , the pass statement does nothing, and the loop continues as normal. The pass statement is often used as a Python Notes 49 c o d e r s n o t e . c o m
  • 50. placeholder for future code. Summary of Loop Control Statements: 1. break : Terminates the loop immediately, even if the loop condition is still True . Example: if count == 5: break 2. continue : Skips the rest of the code in the current iteration and moves to the next iteration. Example: if count == 3: continue 3. pass : A null operation, used as a placeholder when no action is needed. Example: if count == 3: pass Combining while Loop with Loop Control Statements You can use break , continue , and pass in a while loop to control its flow based on certain conditions. Example (Combining while , break , and continue ): V7-9, V7- 9-1 count = 0 while count < 10: count += 1 if count == 3: continue # Skip printing 3 if count == 8: break # Exit the loop when count is 8 print(count) Output: 1 2 Python Notes 50 c o d e r s n o t e . c o m
  • 51. 4 5 6 7 In this example: The loop skips 3 due to the continue statement. The loop exits when count reaches 8 due to the break statement. String Replication in Python String replication is a technique in Python that allows a string to be repeated multiple times using the * operator. Syntax: string * n Where: string is the original text. n is the number of times the string should be repeated. Example: text = "Hello " print(text * 3) Output: Hello Hello Hello Use Cases of String Replication: Creating text patterns: Python Notes 51 c o d e r s n o t e . c o m
  • 52. print("-" * 30) Formatting output: print("=" * 20 + " TITLE " + "=" * 20) Repeating characters or words efficiently. String replication is a simple and efficient way to generate repeated text without using loops or extra variables. Interview-Focused Star, Number, and Alpha Pattern Programs These types of pattern problems are commonly asked in technical interviews, especially for freshers. Below, I’ll walk through a variety of examples of Star, Number, and Alpha patterns that might appear in interview questions. 1. Star Pattern Programs 1.1 Right-Angled Triangle Star Pattern Example: * ** *** **** ***** Code: n = 5 # number of rows for i in range(1, n+1): print('*' * i) Python Notes 52 c o d e r s n o t e . c o m
  • 53. Explanation: The number of stars increases with each row. The loop runs from 1 to n , and in each iteration, the number of stars printed is equal to the current row number. 1.2 Pyramid Star Pattern Example: * *** ***** ******* ********* Code: n = 5 # number of rows for i in range(1, n+1): print(' ' * (n - i) + '*' * (2*i - 1)) Explanation: In this pattern, we print spaces followed by stars. The spaces decrease as the row number increases, while the stars increase in the odd sequence. 1.3 Inverted Pyramid Star Pattern Example: ********* ******* ***** *** * Python Notes 53 c o d e r s n o t e . c o m
  • 54. Code: n = 5 # number of rows for i in range(n, 0, -1): print(' ' * (n - i) + '*' * (2*i - 1)) Explanation: This pattern is the reverse of the pyramid. Here, the number of stars decreases as the row number increases. 2. Number Pattern Programs 2.1 Number Triangle Pattern Example: 1 12 123 1234 12345 Code: n = 5 # Number of rows for i in range(1, n + 1): # Loop through rows for x in range(1, i + 1): # Loop through numbers in each row print(x, end="") # Print numbers on the same line print() # Move to the next line after each row Explanation: The first row prints 1 , the second prints 12 , and so on, with each row having a sequence of numbers from 1 to the row number. 2.2 Inverted Number Triangle Python Notes 54 c o d e r s n o t e . c o m
  • 55. Example: 12345 1234 123 12 1 Code: n = 5 # Number of rows for i in range(n, 0, -1): for x in range(1, i + 1): # Loop to print numbers in the current row print(x,end=" ") # Print numbers without a newline print() # Print a newline after each row Explanation: This pattern is the reverse of the previous one, starting from the highest number sequence and decreasing the length of the sequence in each row. 11111 22222 33333 44444 55555 n = 5 # Number of rows for i in range(1, n + 1): for j in range(1, n + 1): print(i, end="") print() Python Notes 55 c o d e r s n o t e . c o m
  • 56. 2.3 Diamond Number Pattern Example: 1 22 333 4444 55555 Code: n = 5 # Number of rows for i in range(1, n + 1): for j in range(1, i+1): print(i, end="") print() Explanation: This pattern creates a diamond shape by combining ascending and descending numbers symmetrically. 1 121 12321 1234321 123454321 n = 5 # Number of rows for i in range(1, n + 1): i=2 # Print leading spaces print(" " * (n - i), end="") # Print increasing numbers Python Notes 56 c o d e r s n o t e . c o m
  • 57. for j in range(1, i + 1): j=2 print(j, end="") # Print decreasing numbers for j in range(i - 1, 0, -1): print(j, end="") print() 3. Alpha Pattern Programs 3.1 Alphabet Triangle Pattern Example: A AB ABC ABCD ABCDE Code: n = 5 # number of rows for i in range(1, n+1): print(''.join(chr(65 + j) for j in range(i))) Explanation: The chr(65 + j) function returns characters starting from A (ASCII value 65). The loop prints a sequence of characters from A to the i-th character for each row. n = 5 # Number of rows for i in range(1, n + 1): for j in range(1, n + 1): Python Notes 57 c o d e r s n o t e . c o m
  • 58. print(chr(64+i), end="") print() AAAAA BBBBB CCCCC DDDDD EEEEE 3.2 Reverse Alphabet Triangle Example: ABCDE ABCD ABC AB A Code: n = 5 # number of rows for i in range(n, 0, -1): print(''.join(chr(65 + j) for j in range(i))) Explanation: This pattern reverses the previous one by decreasing the number of characters printed on each row. 3.3 Pyramid of Alphabets Example: Python Notes 58 c o d e r s n o t e . c o m
  • 59. A ABA ABCBA ABCDCBA ABCDEDCBA Code: n = 5 # Number of rows for i in range(1, n + 1): # Outer loop for each row # Print leading spaces print(" " * (n - i), end="") # Print increasing letters for j in range(1, i + 1): print(chr(64 + j), end="") # Convert numbers to letters (A=65 in ASCII) # Print decreasing letters for j in range(i - 1, 0, -1): print(chr(64 + j), end="") # Convert numbers to letters (A=65 in ASCII) # Move to the next line after each row print() Explanation: In this pattern, each row consists of an ascending sequence of letters followed by a descending sequence to form the mirrored shape. Tips for Interview Pattern Programs: 1. Understand the structure: Most patterns can be broken down into a combination of spaces and symbols (like stars, numbers, or letters). 2. Use loops: Use for or while loops to control the number of rows and to print each element in the pattern. Python Notes 59 c o d e r s n o t e . c o m
  • 60. 3. Manage spaces: Often, patterns require precise handling of spaces (like in pyramids), so manage the spaces carefully. 4. Practice logic: If you're stuck, focus on how the pattern changes from one row to the next. Module 5: Functions 1. Defining Functions def keyword User-defined functions (without Input without return, without input with return, with input without return, with input with return) Function parameters and arguments - (Positional, Keyword, Default, Variable Length, Variable Length Keyword) def add(): num1 = int(input("Enter the first number for addition: ")) num2 = int(input("Enter the second number for addition: ")) num3 = num1 + num2 print("Addition result:", num3) # Function to multiply two numbers def multiply(): num1 = int(input("Enter the first number for multiplication: ")) num2 = int(input("Enter the second number for multiplication: ")) num3 = num1 * num2 print("Multiplication result:", num3) # Calling the functions add() multiply() Python Functions Overview Python Notes 60 c o d e r s n o t e . c o m
  • 61. Functions in Python are defined using the def keyword. Functions are a way to group related tasks together, allowing you to execute blocks of code multiple times without repeating yourself. Functions can take inputs (parameters) and can return outputs. There are various types of functions based on input and output, and parameters can be specified in different ways. 1. def Keyword The def keyword is used to define a function in Python. After def , the function name is followed by parentheses () (with optional parameters) and a colon : . The body of the function contains the code block that defines its behavior. Syntax: def function_name(parameters): # code block return value 2. User-defined Functions User-defined functions can have different combinations of input and return values. 2.1 Function without Input and without Return This is the simplest form of a function that neither accepts any arguments nor returns any value. Example: def greet(): print("Hello, welcome to the Python world!") # Calling the function greet() Explanation: The function greet() doesn't take any input or return any output. It simply prints a message when called. Python Notes 61 c o d e r s n o t e . c o m
  • 62. 2.2 Function without Input but with Return A function can perform some operation and return a result without taking any input. Example: def get_greeting(): return "Hello, welcome to Python!" # Calling the function greeting = get_greeting() print(greeting) Explanation: The function get_greeting() doesn't take any parameters but returns a string that can be stored in a variable and printed. 2.3 Function with Input but without Return This function takes input but doesn't return anything. It usually modifies some external state or performs an action using the input. Example: def greet_user(name): print(f"Hello, {name}!") # Calling the function greet_user("Alice") Explanation: The function greet_user() takes name as an argument and prints a greeting message. It doesn't return anything but performs an action (printing). 2.4 Function with Input and Return This is the most common type of function that takes input, processes it, and returns a result. Example: Python Notes 62 c o d e r s n o t e . c o m
  • 63. def add_numbers(a, b): return a + b # Calling the function result = add_numbers(5, 3) print(result) # Output: 8 Explanation: The function add_numbers() takes two arguments ( a and b ), adds them, and returns the result. 3. Function Parameters and Arguments Python allows several types of parameters and arguments. Here’s a breakdown: 3.1 Positional Parameters These parameters are assigned based on the order in which they are passed when calling the function. The first argument is assigned to the first parameter, the second argument to the second parameter, and so on. Example: def subtract(a, b): return a - b result = subtract(10, 3) # 10 is assigned to 'a' and 3 to 'b' print(result) # Output: 7 Explanation: The arguments are assigned to parameters based on their position in the function call. 3.2 Keyword Parameters Keyword parameters are passed to the function by explicitly naming the parameter during the function call. This allows passing arguments in any order. Python Notes 63 c o d e r s n o t e . c o m
  • 64. Example: def display_info(name, age): print(f"Name: {name}, Age: {age}") # Using keyword arguments display_info(age=25, name="John") Explanation: By using keyword arguments, we can pass arguments in any order. The names of the parameters are used to map the values. 3.3 Default Parameters Default parameters are those that have default values assigned in the function definition. These parameters are optional when calling the function. If no value is passed, the default value is used. Example: def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") # Calling the function with and without default parameter greet("Alice") # Uses default greeting "Hello" greet("Bob", "Hi") # Custom greeting Explanation: The function greet() uses "Hello" as the default greeting if no greeting is provided during the function call. 3.4 Variable Length Parameters (Arbitrary Arguments) You can use *args to pass a variable number of positional arguments to a function. args is a tuple that stores all the arguments passed. Example: def sum_numbers(*args): return sum(args) Python Notes 64 c o d e r s n o t e . c o m
  • 65. # Calling the function result = sum_numbers(1, 2, 3, 4, 5) print(result) # Output: 15 Explanation: The function sum_numbers() accepts a variable number of arguments and calculates their sum. 3.5 Variable Length Keyword Parameters (Arbitrary Keyword Arguments) for key, value in kwargs.items(): print(f"{key}: {value}") # Calling the function display_info(name="John", age=30, occupation="Engineer") Explanation: The function display_info() accepts an arbitrary number of keyword arguments (passed as a dictionary). The function then loops through the dictionary to print each key-value pair. 4. Combining Different Types of Parameters You can combine positional, keyword, default, and variable-length arguments in a single function. However, the order of parameters must be maintained as follows: 1. Positional arguments (e.g., a, b ) 2. Default arguments (e.g., greeting="Hello" ) 3. Variable-length positional arguments (e.g., args ) 4. Variable-length keyword arguments (e.g., *kwargs ) Example: def complex_function(a, b=5, *args, **kwargs): print(f"a: {a}, b: {b}") Python Notes 65 c o d e r s n o t e . c o m
  • 66. print("Additional positional arguments:", args) print("Keyword arguments:", kwargs) # Calling the function complex_function(10, 20, 30, 40, name="John", city="New York") Explanation: a is a positional argument. b is a default argument with a default value of 5, but can be overridden. args collects any additional positional arguments (30, 40 in this case). *kwargs collects keyword arguments ( name and city ). 5. Recap and Best Practices for Functions Functions are defined using the def keyword. They can accept input through parameters and can return a value using the return keyword. Function parameters can be positional, keyword, or have default values. You can pass a variable number of positional arguments using args and keyword arguments using *kwargs . Maintain clarity by using descriptive parameter names and comments in your functions. Local Variable, Global Variable, and global Keyword in Python Local Variable A local variable is a variable declared inside a function and is accessible only within that function. Example: Python Notes 66 c o d e r s n o t e . c o m
  • 67. def my_function(): x = 10 # Local variable print("Inside function:", x) my_function() # print(x) # This will cause an error because x is not accessible outside the fu nction. Key Points: Defined inside a function. Cannot be accessed outside the function. Memory is allocated only during function execution. Global Variable A global variable is declared outside of a function and can be accessed by any function in the program. Example: x = 20 # Global variable def my_function(): print("Inside function:", x) my_function() print("Outside function:", x) Key Points: Defined outside a function. Can be accessed inside functions. Exists throughout the program's execution. Python Notes 67 c o d e r s n o t e . c o m
  • 68. global Keyword The global keyword allows modification of a global variable inside a function. Example: x = 30 # Global variable def my_function(): global x x = 50 # Modifying global variable inside function print("Inside function:", x) my_function() print("Outside function:", x) Key Points: Used to modify global variables inside a function. Without global , assigning a value to a global variable inside a function creates a new local variable instead. These concepts are essential for managing variable scope effectively in Python. Types of Functions Built-in functions: len() , sum() , max() , min() , abs() , round() , sorted() Few Built-in Functions in Python 1. len() The len() function is used to get the length (number of items) of an object, such as a string, list, tuple, dictionary, etc. Syntax: len(object) Python Notes 68 c o d e r s n o t e . c o m
  • 69. Example: # Length of a string text = "Hello" print(len(text)) # Output: 5 # Length of a list numbers = [1, 2, 3, 4] print(len(numbers)) # Output: 4 Explanation: len() returns the number of characters in a string or the number of elements in a list, tuple, or dictionary. 2. sum() The sum() function is used to sum all the elements of an iterable, such as a list or tuple. Syntax: sum(iterable, start=0) iterable : Any iterable (e.g., list, tuple) whose elements are numbers. start : Optional. The value that is added to the sum (default is 0). Example: # Sum of a list of numbers numbers = [1, 2, 3, 4] print(sum(numbers)) # Output: 10 # Sum with a starting value print(sum(numbers, 5)) # Output: 15 Explanation: Python Notes 69 c o d e r s n o t e . c o m
  • 70. sum() adds up all the elements in the iterable. The optional start argument can be used to add a value to the sum. 3. max() The max() function returns the largest item in an iterable or the largest of two or more arguments. Syntax: max(iterable, *args, key=None) Example: # Maximum value in a list numbers = [1, 2, 3, 4, 5] print(max(numbers)) # Output: 5 # Maximum of two values print(max(10, 20)) # Output: 20 Explanation: max() returns the highest value in the iterable. If multiple arguments are passed, it returns the largest one. You can also use the key parameter to specify a function to determine the sorting criteria. 4. min() The min() function returns the smallest item in an iterable or the smallest of two or more arguments. Syntax: min(iterable, *args, key=None) Example: Python Notes 70 c o d e r s n o t e . c o m
  • 71. # Minimum value in a list numbers = [1, 2, 3, 4, 5] print(min(numbers)) # Output: 1 # Minimum of two values print(min(10, 20)) # Output: 10 Explanation: min() returns the lowest value in the iterable. If multiple arguments are passed, it returns the smallest one. Like max() , the key parameter can be used to determine the criteria for comparison. 5. abs() The abs() function returns the absolute value of a number, which is the non- negative value of the number. Syntax: abs(x) Example: # Absolute value of a number print(abs(-5)) # Output: 5 print(abs(5)) # Output: 5 Explanation: abs() removes the negative sign from a number, giving you the magnitude (absolute value). 6. round() Python Notes 71 c o d e r s n o t e . c o m
  • 72. The round() function is used to round a floating-point number to a specified number of decimal places. Syntax: round(number, digits=0) number : The number to be rounded. digits : Optional. The number of decimal places to round to (default is 0). Example: # Rounding a number print(round(3.14159, 2)) # Output: 3.14 print(round(5.6789)) # Output: 6 Explanation: round() rounds the given number to the specified number of decimal places. If digits is omitted, it rounds to the nearest whole number. 7. sorted() The sorted() function returns a sorted list of the specified iterable's elements. Syntax: sorted(iterable, key=None, reverse=False) iterable : The iterable to be sorted (list, tuple, string, etc.). key : Optional. A function to execute to decide the order. Default is None . reverse : Optional. If True , the list is sorted in descending order. Default is False . Example: # Sorting a list numbers = [5, 2, 9, 1] print(sorted(numbers)) # Output: [1, 2, 5, 9] Python Notes 72 c o d e r s n o t e . c o m
  • 73. # Sorting a string word = "python" print(sorted(word)) # Output: ['h', 'n', 'o', 'p', 't', 'y'] # Sorting in reverse order print(sorted(numbers, reverse=True)) # Output: [9, 5, 2, 1] Explanation: sorted() returns a new list that is sorted, leaving the original iterable unchanged. You can sort in reverse order or provide a custom sorting function using the key parameter. Summary of Built-in Functions These built-in functions are commonly used for basic operations, such as getting the length of an iterable, summing values, finding the maximum or minimum values, and rounding numbers. Here’s a quick recap: len() : Returns the number of items in an object. sum() : Returns the sum of all elements in an iterable. max() : Returns the maximum value from an iterable or among multiple arguments. min() : Returns the minimum value from an iterable or among multiple arguments. abs() : Returns the absolute value of a number. round() : Rounds a number to a specified number of decimal places. sorted() : Returns a sorted list of elements. Modules and Packages 1. Modules Python Notes 73 c o d e r s n o t e . c o m
  • 74. Importing modules ( import , from ... import , as ) Exploring built-in modules like math , os , random , sys , time , datetime Using dir() to inspect module contents 2. Packages Introduction to Python packages Creating and using packages Importing from packages 1. Modules in Python Modules are files containing Python code that can define functions, classes, and variables, and also include runnable code. A module allows you to organize your code logically. Python provides a rich set of built-in modules that can be used to add extra functionality to your programs without writing everything from scratch. Importing Modules There are several ways to import modules into your Python program: 1.1 Importing an Entire Module You can import an entire module using the import keyword. Syntax: import module_name Example: import math # Using the sqrt function from the math module print(math.sqrt(16)) # Output: 4.0 1.2 Importing Specific Functions or Variables from a Module Python Notes 74 c o d e r s n o t e . c o m
  • 75. You can import specific functions or variables from a module using the from ... import syntax. Syntax: from module_name import function_name Example: from math import pi print(pi) # Output: 3.141592653589793 1.3 Importing a Module with an Alias You can give a module or function an alias using the as keyword to make it easier to refer to within your code. Syntax: import module_name as alias Example: import math as m print(m.sqrt(25)) # Output: 5.0 1.4 Exploring Built-in Modules Python provides many built-in modules for various tasks. Some common ones include: math : Provides mathematical functions (e.g., sqrt() , cos() , sin() , pi ). os : Provides functions to interact with the operating system (e.g., file operations, environment variables). Python Notes 75 c o d e r s n o t e . c o m
  • 76. random : Provides functions for generating random numbers (e.g., randint() , choice() ). sys : Provides access to system-specific parameters and functions (e.g., command-line arguments, exiting the program). time : Provides time-related functions (e.g., sleep() , time() ). datetime : Provides classes for manipulating dates and times (e.g., datetime() , date() ). Example: import os import random # Using os to get current working directory print(os.getcwd()) # Using random to generate a random number print(random.randint(1, 10)) 1.5 Using dir() to Inspect Module Contents The dir() function is used to find all the attributes and methods of an object, including a module. It helps you explore what functions or classes are available within the module. Example: import math # Get a list of all available functions and attributes in the math module print(dir(math)) 2. Packages in Python A package in Python is a collection of modules in a directory. A package allows you to organize related modules into a structured hierarchy. Python Notes 76 c o d e r s n o t e . c o m
  • 77. 2.1 Introduction to Python Packages A Python package is a directory that contains multiple Python files (modules). Packages are often used for large projects to keep related modules together. 2.2 Creating and Using Packages To create a package, you simply create a directory and add Python modules to it. Directory Structure: my_package/ module1.py module2.py 2.3 Example of Creating and Using a Package 1. Create a directory called my_package . 2. Inside my_package , create two modules ( module1.py , module2.py ). module1.py: def greet(name): return f"Hello, {name}!" module2.py: def farewell(name): return f"Goodbye, {name}!" 1. Now, you can import the functions from these modules using the following code: # Importing the package from my_package import module1, module2 # Calling functions from the modules Python Notes 77 c o d e r s n o t e . c o m
  • 78. print(module1.greet("John")) # Output: Hello, John! print(module2.farewell("John")) # Output: Goodbye, John! 2.4 Importing from Packages You can import specific functions from modules in a package or import an entire module. Syntax: from package_name.module_name import function_name Example: from my_package.module1 import greet print(greet("Alice")) # Output: Hello, Alice! Summary Modules: Files containing Python code that define functions, classes, and variables. You can import them using import , from ... import , and as . Built-in Modules: Python provides many useful built-in modules such as math , os , random , sys , time , and datetime . Packages: A collection of modules in a directory. Creating Packages: You can create your own packages by organizing modules into directories. Importing from Packages: You can import modules or specific functions from a package using the import syntax. By using modules and packages, you can organize your code efficiently and reuse functions and classes across different parts of your program. Lambda functions (anonymous functions using lambda keyword) Python Notes 78 c o d e r s n o t e . c o m
  • 79. Lambda Functions in Python In Python, lambda functions are small anonymous functions that are defined using the lambda keyword. These functions can have any number of arguments but only one expression. The expression is evaluated and returned when the function is called. Syntax of Lambda Functions: lambda arguments: expression lambda is the keyword used to define the function. arguments is a comma-separated list of input parameters. expression is the expression that gets evaluated and returned by the function. Key Characteristics of Lambda Functions: They are anonymous, meaning they don’t have a name. They are small, typically used for short, simple operations. They can take any number of arguments, but only one expression. They are generally used when you need a function for a short period and do not want to formally define it with a def statement. Examples of Lambda Functions: 1. Basic Lambda Function # A simple lambda function that adds two numbers add = lambda a, b: a + b print(add(2, 3)) # Output: 5 2. Lambda Function with One Argument Python Notes 79 c o d e r s n o t e . c o m
  • 80. # A lambda function that squares the input number square = lambda x: x ** 2 print(square(5)) # Output: 25 3. Lambda Function in a List V8-4 Lambda functions are often used with higher-order functions like map() , filter() , or sorted() to operate on lists or other iterable objects. from functools import reduce # Function to add two numbers def add(x, y): return x + y # List of numbers numbers = [1, 2, 3, 4] # Use reduce to sum the list result = reduce(add, numbers) # Print the result print("Sum of the list:", result) Example: Using map() to square a list of numbers: numbers = [1, 2, 3, 4, 5] squared = list(map(lambda x: x ** 2, numbers)) print(squared) # Output: [1, 4, 9, 16, 25] Example: Using filter() to get even numbers: numbers = [1, 2, 3, 4, 5, 6, 7, 8] even_numbers = list(filter(lambda x: x % 2 == 0, numbers)) Python Notes 80 c o d e r s n o t e . c o m
  • 81. print(even_numbers) # Output: [2, 4, 6, 8] Aspect map() filter() reduce() (requires functools ) Purpose Transforms each element in an iterable using a function. Filters elements based on a condition (boolean function). Reduces an iterable to a single value by combining elements. Syntax map(function, iterable) filter(function, iterable) reduce(function, iterable[, initializer]) Input Iterable and a function to apply. Iterable and a function that returns True / False . Iterable and a function to combine two elements. Output Transformed iterable ( map object). Filtered iterable ( filter object). A single cumulative value. Function Type Applies the function to all elements. Selects elements where the function returns True . Combines elements iteratively using the function. Use Case When you need to apply a transformation to all elements. When you need to include/exclude elements based on a condition. When you need to aggregate/summarize values. Example map(lambda x: x * 2, [1, 2, 3]) → [2, 4, 6] filter(lambda x: x % 2 == 0, [1, 2, 3]) → [2] reduce(lambda x, y: x + y, [1, 2, 3]) → 6 Returns Iterator ( map object). Iterator ( filter object). Single cumulative value. Module Built-in. Built-in. Requires functools . 4. Lambda Function with Sorting Lambda functions are also useful when sorting lists with custom conditions. Example: Sorting a list of tuples based on the second element: Python Notes 81 c o d e r s n o t e . c o m
  • 82. pairs = [(1, 2), (3, 1), (5, 0)] pairs_sorted = sorted(pairs, key=lambda x: x[1]) print(pairs_sorted) # Output: [(5, 0), (3, 1), (1, 2)] When to Use Lambda Functions Lambda functions are commonly used in situations where: 1. You need a small, simple function temporarily. 2. You don't want to formally define a full function using def . 3. You are passing a function as an argument to higher-order functions like map() , filter() , reduce() , etc. 4. You want to write short, readable code for operations that can be performed in a single line. Advantages of Lambda Functions: Concise: Lambda functions are compact and can be written in a single line. Anonymous: They are often used for short-term, single-use functions. Functional Programming: They are used extensively in functional programming approaches with functions like map() , filter() , and reduce() . Limitations of Lambda Functions: Limited to one expression: Lambda functions can only have one expression. You can't use multiple expressions or statements like you can in regular functions. Not very readable for complex operations: For complex operations, lambda functions can reduce readability and maintainability of the code. Example with Multiple Arguments: Python Notes 82 c o d e r s n o t e . c o m
  • 83. # A lambda function that calculates the area of a rectangle area = lambda length, width: length * width print(area(5, 3)) # Output: 15 In conclusion, lambda functions are an efficient way to define small, one-off functions in Python, especially when working with functional programming features like map() , filter() , and sorted() . Recursive Function? V8-6 A recursive function is a function that calls itself to solve smaller instances of a problem. Recursion continues until it reaches a base case, which stops the recursion. Example: Factorial Calculation Code: # Recursive function to calculate factorial def factorial(n): if n == 1: # Base case return 1 else: return n * factorial(n - 1) # Recursive case # Input from user a = int(input("Enter a number: ")) print(factorial(a)) Example Output: 1. Input: Enter a number: 5 Python Notes 83 c o d e r s n o t e . c o m
  • 84. Output: Factorial of 5 is: 120 2. Input: Enter a number: 0 Output: Factorial of 0 is: 1 Explanation: 1. Base Case ( if n == 0 ): When , the function returns 1 to terminate recursion. n=0n = 0 2. Recursive Case ( n * factorial(n - 1) ): The function calls itself with until it reaches the base case. n−1n-1 3. Step-by-Step Execution for factorial(5) : 5!=5×4!5! = 5 times 4! 4!=4×3!4! = 4 times 3! 3!=3×2!3! = 3 times 2! 2!=2×1!2! = 2 times 1! 1!=1×0!1! = 1 times 0! 0!=10! = 1 (base case) Final Result: 5!=5×4×3×2×1=1205! = 5 times 4 times 3 times 2 times 1 = 120 Python Notes 84 c o d e r s n o t e . c o m
  • 85. Another Example: Sum of Natural Numbers # Recursive function to calculate sum of first n natural numbers def sum_natural(n): if n == 0: # Base case return 0 else: return n + sum_natural(n - 1) # Recursive case # Input from user number = int(input("Enter a number: ")) # Call the recursive function if number >= 0: print(f"Sum of first {number} natural numbers is: {sum_natural(number)}") else: print("Sum is not defined for negative numbers.") Module 6: Data Structures Lists Creating lists Accessing list elements using indexing slicing List methods: append() , extend() , insert() , pop() , remove() , index() , count() , sort() , reverse() , copy() Nested list Concatenation Python Notes 85 c o d e r s n o t e . c o m
  • 86. # Define two lists a = [10, 20, 30] b = [40, 50, 60] # Concatenate the lists c = a + b # Print the result print(c) Lists in Python A list in Python is an ordered collection of items, which can be of any type. Lists are mutable, meaning their elements can be modified after the list is created. They are one of the most versatile data structures in Python, used frequently for a variety of tasks. 1. Creating Lists A list is created by placing items inside square brackets [] , separated by commas. # Creating a list with integers my_list = [1, 2, 3, 4, 5] # Creating a list with different types of elements mixed_list = [1, "hello", 3.14, True] 2. Accessing List Elements Using Indexing List elements are accessed using indexing. Indexing in Python starts at 0 . Negative indexing can be used to access elements from the end of the list. # Accessing elements using positive index my_list = [10, 20, 30, 40, 50] print(my_list[0]) # Output: 10 (first element) Python Notes 86 c o d e r s n o t e . c o m
  • 87. print(my_list[3]) # Output: 40 (fourth element) # Accessing elements using negative index print(my_list[-1]) # Output: 50 (last element) print(my_list[-2]) # Output: 40 (second last element) 3. Slicing Slicing allows you to access a range of elements from a list by specifying a start index, an end index, and an optional step value. # Slicing a list my_list = [1, 2, 3, 4, 5, 6, 7, 8] # Accessing elements from index 2 to 5 (excluding index 5) print(my_list[2:5]) # Output: [3, 4, 5] # Accessing elements from the start to index 4 (excluding index 4) print(my_list[:4]) # Output: [1, 2, 3, 4] # Accessing elements from index 3 to the end print(my_list[3:]) # Output: [4, 5, 6, 7, 8] # Slicing with step value print(my_list[::2]) # Output: [1, 3, 5, 7] 4. List Methods Python provides several built-in methods to manipulate lists. Below are some of the most commonly used list methods: append() : Adds an element at the end of the list. extend() : Adds all elements of an iterable (like another list) to the list. insert() : Inserts an element at a specified position in the list. Python Notes 87 c o d e r s n o t e . c o m
  • 88. pop() : Removes and returns the element at the specified index (default is the last element). remove() : Removes the first occurrence of a specified element. index() : Returns the index of the first occurrence of a specified element. count() : Returns the number of occurrences of a specified element. sort() : Sorts the list in ascending order. reverse() : Reverses the order of elements in the list. copy() : Returns a shallow copy of the list. Examples: # Creating a list my_list = [1, 2, 3, 4] # append() - Adds an element at the end of the list my_list.append(5) print(my_list) # Output: [1, 2, 3, 4, 5] # extend() - Adds elements of another iterable my_list.extend([6, 7]) print(my_list) # Output: [1, 2, 3, 4, 5, 6, 7] # insert() - Inserts an element at the specified position my_list.insert(2, "Hello") print(my_list) # Output: [1, 2, 'Hello', 3, 4, 5, 6, 7] # pop() - Removes and returns the element at the specified index removed_item = my_list.pop(3) print(removed_item) # Output: 3 print(my_list) # Output: [1, 2, 'Hello', 4, 5, 6, 7] # remove() - Removes the first occurrence of a specified element my_list.remove("Hello") Python Notes 88 c o d e r s n o t e . c o m
  • 89. print(my_list) # Output: [1, 2, 4, 5, 6, 7] # index() - Returns the index of the first occurrence of a specified element index = my_list.index(5) print(index) # Output: 3 # count() - Returns the number of occurrences of a specified element count = my_list.count(7) print(count) # Output: 1 # sort() - Sorts the list in ascending order my_list.sort() print(my_list) # Output: [1, 2, 4, 5, 6, 7] # reverse() - Reverses the order of elements in the list my_list.reverse() print(my_list) # Output: [7, 6, 5, 4, 2, 1] # copy() - Returns a shallow copy of the list copied_list = my_list.copy() print(copied_list) # Output: [7, 6, 5, 4, 2, 1] 5. Nested Lists A nested list is a list that contains other lists as its elements. You can access elements in nested lists using multiple indices. # Creating a nested list nested_list = [1, [2, 3], [4, 5, 6], 7] # Accessing elements of the nested list print(nested_list[1]) # Output: [2, 3] (list at index 1) print(nested_list[1][0]) # Output: 2 (first element of the list at index 1) Python Notes 89 c o d e r s n o t e . c o m
  • 90. 6. List Comprehension List comprehension is a concise way to create lists by applying an expression to each element in an iterable. It is often used for transforming or filtering data. Syntax: [expression for item in iterable if condition] expression is the result you want for each item. item is each element of the iterable. iterable can be any iterable like a list, tuple, etc. condition is optional and is used to filter the items. Examples: # Create a list of squares of numbers from 1 to 5 squares = [x ** 2 for x in range(1, 6)] print(squares) # Output: [1, 4, 9, 16, 25] # Create a list of even numbers from 1 to 10 evens = [x for x in range(1, 11) if x % 2 == 0] print(evens) # Output: [2, 4, 6, 8, 10] # Create a list of strings in uppercase words = ["hello", "world", "python"] uppercase_words = [word.upper() for word in words] print(uppercase_words) # Output: ['HELLO', 'WORLD', 'PYTHON'] Conclusion Lists are one of the most commonly used data structures in Python, providing an ordered, mutable collection of items. You can create, access, and manipulate lists using various methods and techniques like indexing, slicing, list methods, and list comprehensions. Python Notes 90 c o d e r s n o t e . c o m
  • 91. Python's list comprehension provides a concise and efficient way to create and modify lists, especially for transforming or filtering data. By understanding lists and their methods, you can efficiently manage collections of data and perform a wide variety of tasks in Python. Mutable and Immutable Data Types 1. Understanding Mutability Definition of mutable and immutable objects Importance of mutability in Python 2. Mutable Data Types Lists Dictionaries Sets 3. Immutable Data Types Strings Tuples Integers, Floats, Booleans, Complex Numbers Examples of immutability Mutable and Immutable Data Types in Python In Python, the concept of mutability refers to whether or not an object can be changed after it is created. This distinction is important because it affects how variables are assigned, how data is shared between variables, and how memory is managed. 1. Understanding Mutability Mutable Objects Python Notes 91 c o d e r s n o t e . c o m
  • 92. A mutable object is an object whose state or content can be changed after it is created. When you modify a mutable object, the change is reflected in the original object, and no new object is created. Examples of mutable data types: Lists Dictionaries Sets Key characteristics of mutable objects: You can change the contents of the object. Modifications to mutable objects affect all references to that object. Immutable Objects An immutable object is an object whose state or content cannot be changed after it is created. When you attempt to modify an immutable object, a new object is created with the new value, and the original object remains unchanged. Examples of immutable data types: Strings Tuples Integers Floats Booleans Key characteristics of immutable objects: You cannot change the contents of the object after it is created. Modifying an immutable object creates a new object rather than changing the original one. 2. Importance of Mutability in Python Python Notes 92 c o d e r s n o t e . c o m
  • 93. Mutability plays a crucial role in how variables and objects behave in Python. Understanding the difference between mutable and immutable types can help avoid bugs and optimize memory usage. Effects of Mutability: Memory Management: Immutable objects can often be optimized by Python’s internal memory management, such as object interning (e.g., for strings). Assignment Behavior: When you assign a mutable object to another variable, both variables refer to the same object. If you modify the object through one variable, the change is reflected in the other variable. # Example of mutable behavior list1 = [1, 2, 3] list2 = list1 list2.append(4) # Modifying list2 also affects list1 print(list1) # Output: [1, 2, 3, 4] print(list2) # Output: [1, 2, 3, 4] Immutable Assignment: When you assign an immutable object to another variable, a copy of the value is made, and changes to one variable do not affect the other. # Example of immutable behavior str1 = "Hello" str2 = str1 str2 = "World" # Modifying str2 does not affect str1 print(str1) # Output: "Hello" print(str2) # Output: "World" Key Takeaways: Mutable objects allow you to modify their content, and multiple variables can reference the same object. This can lead to unexpected side effects if you are not careful. Python Notes 93 c o d e r s n o t e . c o m
  • 94. Immutable objects cannot be changed once created. Modifications result in the creation of new objects, making them safer to use when you don't want shared references to be affected by changes. Examples: Mutable vs Immutable Mutable Example - List # Mutable data type example: List my_list = [1, 2, 3] another_list = my_list # both variables refer to the same list # Modifying the list through one variable another_list.append(4) print(my_list) # Output: [1, 2, 3, 4] print(another_list) # Output: [1, 2, 3, 4] In this example, both my_list and another_list refer to the same list object, so modifying one will affect the other. Immutable Example - String # Immutable data type example: String str1 = "Python" str2 = str1 # both variables refer to the same string # Modifying the string (strings are immutable) str2 = "Java" print(str1) # Output: "Python" print(str2) # Output: "Java" Here, strings are immutable, so when you assign a new value to str2 , Python creates a new string object and updates str2 to reference the new string, leaving str1 unchanged. Python Notes 94 c o d e r s n o t e . c o m
  • 95. 3. Implications of Mutability and Immutability Performance Considerations: Immutable objects are typically faster when used as dictionary keys or set elements because their hash values are constant and do not change. Mutable objects, on the other hand, cannot be used as dictionary keys or set elements since their hash values could change after creation. Avoiding Side Effects: Immutable objects are useful in avoiding unintended side effects when working with multiple references to the same object. Since their state cannot be changed, they are inherently safer in situations where data integrity is important. Conclusion Understanding mutable and immutable data types is essential when working with Python. Mutable objects (like lists, dictionaries, and sets) can be modified after creation. Immutable objects (like strings, tuples, and integers) cannot be modified, and any changes create a new object. This distinction affects how you use these data types in your programs, particularly when it comes to assignment, memory management, and avoiding side effects. Tuples Creating tuples Accessing elements using indexing Tuple immutability Tuple methods: count() , index() Tuples in Python Python Notes 95 c o d e r s n o t e . c o m
  • 96. A tuple is a collection data type in Python that is similar to a list, but unlike lists, tuples are immutable. This means that once a tuple is created, its elements cannot be modified (i.e., you cannot add, remove, or change elements). 1. Creating Tuples You can create a tuple by placing a sequence of elements inside parentheses () . Syntax: tuple_name = (element1, element2, element3, ...) Example: my_tuple = (1, 2, 3, 4) print(my_tuple) # Output: (1, 2, 3, 4) You can also create a tuple with a single element by adding a trailing comma: single_element_tuple = (5,) print(single_element_tuple) # Output: (5,) Without the comma, it will not be considered a tuple: not_a_tuple = (5) print(type(not_a_tuple)) # Output: <class 'int'> Creating an empty tuple: empty_tuple = () print(empty_tuple) # Output: () Tuple with mixed data types: Python Notes 96 c o d e r s n o t e . c o m
  • 97. mixed_tuple = (1, "hello", 3.14, True) print(mixed_tuple) # Output: (1, "hello", 3.14, True) 2. Accessing Elements Using Indexing You can access the elements of a tuple using indexing, similar to lists. Indexing starts from 0. Syntax: tuple_name[index] Example: my_tuple = (1, 2, 3, 4, 5) print(my_tuple[0]) # Output: 1 print(my_tuple[3]) # Output: 4 Negative indexing: You can also use negative indexing to access elements from the end of the tuple. Example: print(my_tuple[-1]) # Output: 5 print(my_tuple[-2]) # Output: 4 Slicing: You can extract a subset of the tuple using slicing. The syntax for slicing is: tuple_name[start_index:end_index] Example: Python Notes 97 c o d e r s n o t e . c o m
  • 98. print(my_tuple[1:4]) # Output: (2, 3, 4) 3. Tuple Immutability One of the most important properties of tuples is that they are immutable. This means that you cannot change, add, or remove elements after the tuple is created. Example (Attempting to modify a tuple): my_tuple = (1, 2, 3) # Trying to modify an element (this will raise an error) # my_tuple[1] = 5 # TypeError: 'tuple' object does not support item assignmen t However, you can concatenate tuples to create a new tuple: tuple1 = (1, 2) tuple2 = (3, 4) new_tuple = tuple1 + tuple2 # Creating a new tuple by concatenation print(new_tuple) # Output: (1, 2, 3, 4) You can also perform operations like repetition using * : my_tuple = (1, 2) new_tuple = my_tuple * 3 # Repeating the tuple 3 times print(new_tuple) # Output: (1, 2, 1, 2, 1, 2) 4. Tuple Methods count() Method The count() method returns the number of occurrences of a specified element in the tuple. Syntax: Python Notes 98 c o d e r s n o t e . c o m
  • 99. tuple_name.count(element) Example: my_tuple = (1, 2, 3, 4, 1, 2, 1) count_of_1 = my_tuple.count(1) print(count_of_1) # Output: 3 index() Method The index() method returns the index of the first occurrence of a specified element in the tuple. If the element is not found, it raises a ValueError . Syntax: tuple_name.index(element) Example: my_tuple = (1, 2, 3, 4, 5) index_of_3 = my_tuple.index(3) print(index_of_3) # Output: 2 If the element is not in the tuple, it will raise an error: # This will raise a ValueError because 6 is not in the tuple # my_tuple.index(6) Summary of Key Points: Tuples are immutable data types in Python. You can create a tuple using parentheses () , and it can contain different data types. Indexing and slicing are used to access tuple elements. Python Notes 99 c o d e r s n o t e . c o m
  • 100. The count() method gives the number of occurrences of a specified element in a tuple. The index() method returns the first index of a specified element in a tuple. Tuples can be concatenated or repeated using + and respectively, but the tuple itself cannot be changed after creation. Sets Creating sets Set methods: add() , update() , remove() , discard() , pop() , clear() , copy() Sets in Python A set in Python is an unordered collection of unique elements. Sets are similar to lists and dictionaries but have no duplicate elements and are unordered, meaning that the items have no index. They are mutable, meaning you can add or remove elements, and they are often used for membership tests, removing duplicates from a collection, and performing mathematical set operations like union, intersection, and difference. 1. Creating Sets A set is created by placing comma-separated values inside curly braces {} or by using the set() constructor. Syntax: set_name = {element1, element2, element3, ...} Alternatively, using the set() constructor: set_name = set([element1, element2, element3, ...]) Example: Python Notes 100 c o d e r s n o t e . c o m
  • 101. my_set = {1, 2, 3, 4} print(my_set) # Output: {1, 2, 3, 4} You can create an empty set using set() , but not using {} as it would create an empty dictionary: empty_set = set() print(empty_set) # Output: set() 3. Set Methods Sets come with several methods that allow you to manipulate the elements of the set. add() Method The add() method adds an element to the set. If the element already exists, it won't be added again (since sets don't allow duplicates). Example: my_set = {1, 2, 3} my_set.add(4) print(my_set) # Output: {1, 2, 3, 4} update() Method The update() method adds multiple elements (from an iterable) to the set. Duplicates will be ignored. Example: my_set = {1, 2, 3} my_set.update([3, 4, 5]) print(my_set) # Output: {1, 2, 3, 4, 5} Python Notes 101 c o d e r s n o t e . c o m
  • 102. remove() Method The remove() method removes a specified element from the set. If the element is not found, it raises a KeyError . Example: my_set = {1, 2, 3, 4} my_set.remove(3) print(my_set) # Output: {1, 2, 4} discard() Method The discard() method removes a specified element from the set. If the element is not found, it does nothing (no error is raised). Example: my_set = {1, 2, 3, 4} my_set.discard(3) print(my_set) # Output: {1, 2, 4} my_set.discard(5) # No error raised, even though 5 is not in the set pop() Method The pop() method removes and returns an arbitrary element from the set. Since sets are unordered, there is no guarantee which element will be removed. Example: my_set = {1, 2, 3, 4} popped_element = my_set.pop() print(popped_element) # Output: 1 (or another element, since the set is unord ered) print(my_set) # Output: {2, 3, 4} clear() Method Python Notes 102 c o d e r s n o t e . c o m
  • 103. The clear() method removes all elements from the set. Example: my_set = {1, 2, 3, 4} my_set.clear() print(my_set) # Output: set() copy() Method The copy() method creates a shallow copy of the set. Example: my_set = {1, 2, 3} new_set = my_set.copy() print(new_set) # Output: {1, 2, 3} Summary of Key Points: A set is an unordered collection of unique elements. Sets support various mathematical operations like union, intersection, and difference. Sets are mutable, meaning elements can be added or removed. Some common set methods include add() , remove() , discard() , pop() , clear() , and update() . Sets are widely used for tasks such as removing duplicates, membership testing, and performing set operations. By understanding these set operations and methods, you can effectively use sets in Python to handle data more efficiently, especially when uniqueness and mathematical set operations are important in your logic. Dictionaries Creating dictionaries Python Notes 103 c o d e r s n o t e . c o m
  • 104. Accessing, modifying, and deleting key-value pairs Dictionary methods: get() , keys() , values() , items() , update() , pop() , popitem() , clear() , fromkeys() , setdefault() Dictionaries in Python A dictionary in Python is a collection of key-value pairs. It is an unordered, mutable, and indexed collection that allows you to store data in the form of a key and an associated value. Dictionaries are highly optimized for retrieving data and can hold a mix of data types, such as strings, integers, and other objects. 1. Creating Dictionaries A dictionary is created by using curly braces {} or the dict() constructor. Each key- value pair is separated by a colon : and the pairs are separated by commas. Syntax: dict_name = {key1: value1, key2: value2, key3: value3, ...} Example: my_dict = {"name": "John", "age": 30, "city": "New York"} print(my_dict) # Output: {'name': 'John', 'age': 30, 'city': 'New York'} Alternatively, you can use the dict() function to create a dictionary: my_dict = dict(name="John", age=30, city="New York") print(my_dict) # Output: {'name': 'John', 'age': 30, 'city': 'New York'} 2. Accessing, Modifying, and Deleting Key-Value Pairs Accessing Values You can access the value associated with a key using the square bracket notation or the get() method. Python Notes 104 c o d e r s n o t e . c o m
  • 105. Using square brackets: print(my_dict["name"]) # Output: John Using get() method: print(my_dict.get("age")) # Output: 30 The get() method is safer than using square brackets because it doesn't raise an error if the key doesn't exist. Instead, it returns None or a default value if provided. Modifying Values You can modify the value associated with a key by assigning a new value to the key. my_dict["age"] = 35 print(my_dict) # Output: {'name': 'John', 'age': 35, 'city': 'New York'} Adding New Key-Value Pairs You can add new key-value pairs to the dictionary simply by assigning a value to a new key. my_dict["email"] = "[email protected]" print(my_dict) # Output: {'name': 'John', 'age': 35, 'city': 'New York', 'email': 'j [email protected]'} Deleting Key-Value Pairs You can remove a key-value pair using the del statement or the pop() method. Using del : del my_dict["city"] print(my_dict) # Output: {'name': 'John', 'age': 35, 'email': '[email protected] m'} Python Notes 105 c o d e r s n o t e . c o m
  • 106. Using pop() : removed_value = my_dict.pop("email") print(removed_value) # Output: [email protected] print(my_dict) # Output: {'name': 'John', 'age': 35} Using popitem() removes the last inserted key-value pair and returns it: last_item = my_dict.popitem() print(last_item) # Output: ('age', 35) print(my_dict) # Output: {'name': 'John'} Clearing the Dictionary You can remove all key-value pairs from the dictionary using the clear() method: my_dict.clear() print(my_dict) # Output: {} 3. Dictionary Methods get() Method The get() method is used to access the value of a key. If the key does not exist, it returns None or a default value if specified. Syntax: dict_name.get(key, default_value) Example: value = my_dict.get("age", "Not Available") print(value) # Output: "Not Available" Python Notes 106 c o d e r s n o t e . c o m
  • 107. keys() Method The keys() method returns a view object that displays all the keys in the dictionary. Example: keys = my_dict.keys() print(keys) # Output: dict_keys(['name', 'age']) values() Method The values() method returns a view object that displays all the values in the dictionary. Example: values = my_dict.values() print(values) # Output: dict_values(['John', 30]) items() Method The items() method returns a view object that displays all the key-value pairs in the dictionary. Example: items = my_dict.items() print(items) # Output: dict_items([('name', 'John'), ('age', 30)]) update() Method The update() method updates the dictionary with the key-value pairs from another dictionary or an iterable of key-value pairs. If a key already exists, its value is updated. Example: my_dict.update({"email": "[email protected]"}) print(my_dict) # Output: {'name': 'John', 'age': 30, 'email': '[email protected] Python Notes 107 c o d e r s n o t e . c o m
  • 108. m'} pop() Method The pop() method removes and returns the value associated with a specified key. Example: removed_value = my_dict.pop("age") print(removed_value) # Output: 30 print(my_dict) # Output: {'name': 'John', 'email': '[email protected]'} popitem() Method The popitem() method removes and returns the last key-value pair from the dictionary. Example: last_item = my_dict.popitem() print(last_item) # Output: ('email', '[email protected]') print(my_dict) # Output: {'name': 'John'} clear() Method The clear() method removes all key-value pairs from the dictionary. Example: my_dict.clear() print(my_dict) # Output: {} fromkeys() Method The fromkeys() method creates a new dictionary with the specified keys and assigns a default value to each key. Syntax: Python Notes 108 c o d e r s n o t e . c o m
  • 109. dict_name = dict.fromkeys(keys, value) Example: keys = ['name', 'age', 'city'] new_dict = dict.fromkeys(keys, "Not Available") print(new_dict) # Output: {'name': 'Not Available', 'age': 'Not Available', 'city': 'Not Available'} setdefault() Method The setdefault() method returns the value of the key if it exists. If the key does not exist, it inserts the key with a specified default value. Example: my_dict = {"name": "John", "age": 30} value = my_dict.setdefault("city", "New York") print(value) # Output: New York print(my_dict) # Output: {'name': 'John', 'age': 30, 'city': 'New York'} Summary of Key Points: A dictionary is a collection of key-value pairs, where each key is unique. Dictionaries are mutable, meaning you can add, modify, or remove key-value pairs. Common methods include get() , keys() , values() , items() , update() , pop() , and clear() . Dictionaries provide efficient access to values through keys and are an essential data structure in Python. Dictionaries are widely used for storing structured data, representing objects, and implementing fast lookups. They are one of the most powerful and versatile data structures in Python. Python Notes 109 c o d e r s n o t e . c o m
  • 110. Shallow copy vs Deep copy Using copy and deepcopy from the copy module Shallow Copy vs. Deep Copy in Python In Python, when copying objects, there are two types of copies you can make: shallow copy and deep copy. Understanding the difference is important when working with complex objects like lists, dictionaries, or any mutable objects that contain other objects. 1. Shallow Copy A shallow copy creates a new object, but it does not create copies of the objects that the original object contains. Instead, it simply copies references to those objects. This means that changes made to nested objects (objects inside the original object) will reflect in both the original and the copied object. In simple terms: A shallow copy only copies the outermost structure (like the list or dictionary) but not the inner objects. The inner objects are shared between the original and the copied object. Creating a Shallow Copy: You can create a shallow copy using the copy() method (for lists and dictionaries) or the copy.copy() method from the copy module. Example of Shallow Copy: import copy # Original object original_list = [1, 2, [3, 4], 5] # Create a shallow copy shallow_copy_list = copy.copy(original_list) Python Notes 110 c o d e r s n o t e . c o m
  • 111. # Modify a nested element in the shallow copy shallow_copy_list[2][0] = 99 # Output the original and copied lists print("Original List:", original_list) # Output: [1, 2, [99, 4], 5] print("Shallow Copy List:", shallow_copy_list) # Output: [1, 2, [99, 4], 5] As you can see, modifying the nested list inside the shallow copy also affects the original list because both share the same reference to the inner list. 2. Deep Copy A deep copy, on the other hand, creates a completely new object and recursively copies all objects found in the original object, including any nested objects. This means that the copied object and the original object are entirely independent of each other. In simple terms: A deep copy creates a new object and also copies all objects contained within the original object, including the inner ones. The original and copied objects do not share any references to the same objects. Creating a Deep Copy: You can create a deep copy using the deepcopy() function from the copy module. Example of Deep Copy: import copy # Original object original_list = [1, 2, [3, 4], 5] # Create a deep copy deep_copy_list = copy.deepcopy(original_list) Python Notes 111 c o d e r s n o t e . c o m
  • 112. # Modify a nested element in the deep copy deep_copy_list[2][0] = 99 # Output the original and copied lists print("Original List:", original_list) # Output: [1, 2, [3, 4], 5] print("Deep Copy List:", deep_copy_list) # Output: [1, 2, [99, 4], 5] In this case, modifying the nested list inside the deep copy does not affect the original list, because the nested lists in the deep copy are independent of those in the original list. Key Differences Between Shallow Copy and Deep Copy Aspect Shallow Copy Deep Copy Definition Creates a new object, but doesn't copy nested objects. Creates a completely independent copy, recursively copying all objects inside the original. Shared References Shares references to nested objects between original and copied objects. Does not share references. All objects are copied, including nested ones. Effect of Modification Modifying nested objects in the copied object affects the original. Modifying the copied object does not affect the original. Performance Faster, as it only copies references to the nested objects. Slower, as it recursively copies all objects, including nested ones. Use Case Useful when you don't need to modify nested objects or need shared references. Useful when you need completely independent copies, especially when modifying nested objects. When to Use Shallow Copy and Deep Copy Shallow Copy is useful when: You only need a new container object (like a list or dictionary) but can share references to the objects within. Python Notes 112 c o d e r s n o t e . c o m
  • 113. You are working with objects that don’t contain nested mutable objects, or you don’t intend to modify the nested objects. Deep Copy is useful when: You need a completely independent copy of an object, including all nested objects. You intend to modify both the original and the copied object, and you don’t want changes to affect the other. Code Example with Both Shallow and Deep Copy import copy # Original list with nested list original_list = [1, 2, [3, 4], 5] # Shallow copy shallow_copy_list = copy.copy(original_list) shallow_copy_list[2][0] = 99 # Modify the nested list print("Shallow Copy Result:") print("Original List:", original_list) # Output: [1, 2, [99, 4], 5] print("Shallow Copy List:", shallow_copy_list) # Output: [1, 2, [99, 4], 5] # Deep copy deep_copy_list = copy.deepcopy(original_list) deep_copy_list[2][0] = 999 # Modify the nested list print("nDeep Copy Result:") print("Original List:", original_list) # Output: [1, 2, [99, 4], 5] print("Deep Copy List:", deep_copy_list) # Output: [1, 2, [999, 4], 5] Conclusion Shallow copy creates a new object but keeps references to the original objects within it, making it more efficient for simple use cases. Python Notes 113 c o d e r s n o t e . c o m
  • 114. Deep copy creates a completely independent copy of the original object and all its contents, which is useful when working with complex, nested structures that you want to modify independently. Understanding the difference between shallow and deep copies helps in managing memory and object references effectively, especially when dealing with mutable objects like lists, dictionaries, and sets. Special Operators Identity operators: is , is not Membership operators: in , not in 1. Identity Operators Identity operators are used to compare the memory locations of two objects. They check whether two objects are the same object in memory, not just if they are equal. a) is Operator Description: The is operator checks if two variables point to the same object in memory (i.e., if they are the same object). Syntax: variable1 is variable2 Returns: True if both variables point to the same object, otherwise False . Example: x = [1, 2, 3] y = x # y points to the same object as x z = [1, 2, 3] # z is a new object with the same value print(x is y) # Output: True, because x and y refer to the same object print(x is z) # Output: False, because x and z are different objects in memory Python Notes 114 c o d e r s n o t e . c o m
  • 115. b) is not Operator Description: The is not operator checks if two variables do not point to the same object in memory (i.e., if they are different objects). Syntax: variable1 is not variable2 Returns: True if both variables do not point to the same object, otherwise False . Example: x = [1, 2, 3] y = [1, 2, 3] # y is a different object with the same value z = x # z refers to the same object as x print(x is not y) # Output: True, because x and y are different objects print(x is not z) # Output: False, because x and z refer to the same object 2. Membership Operators Membership operators are used to test if a value or variable is present in a sequence (such as a list, string, tuple, etc.). These operators check whether an element exists in the sequence. a) in Operator Description: The in operator checks if a value is present in a sequence (like a list, string, tuple, or set). Syntax: value in sequence Returns: True if the value is present in the sequence, otherwise False . Example: # Using 'in' with a list fruits = ["apple", "banana", "cherry"] print("apple" in fruits) # Output: True, because "apple" is in the list Python Notes 115 c o d e r s n o t e . c o m
  • 116. # Using 'in' with a string name = "Harish" print("a" in name) # Output: True, because "a" is in the string "Harish" b) not in Operator Description: The not in operator checks if a value is not present in a sequence (like a list, string, tuple, or set). Syntax: value not in sequence Returns: True if the value is not present in the sequence, otherwise False . Example: # Using 'not in' with a list fruits = ["apple", "banana", "cherry"] print("orange" not in fruits) # Output: True, because "orange" is not in the list # Using 'not in' with a string name = "Harish" print("z" not in name) # Output: True, because "z" is not in the string "Harish" Summary of Special Operators Operator Description Example Output is Checks if two variables point to the same object x is y True or False is not Checks if two variables do not point to the same object x is not y True or False in Checks if a value is present in a sequence "apple" in fruits True or False not in Checks if a value is not present in a sequence "orange" not in fruits True or False Python Notes 116 c o d e r s n o t e . c o m
  • 117. Example Program Using Identity and Membership Operators # Identity operators a = [1, 2, 3] b = a # b is the same object as a c = [1, 2, 3] # c is a different object with the same value print(a is b) # Output: True, because a and b point to the same object print(a is c) # Output: False, because a and c are different objects in memory print(a is not c) # Output: True, because a and c are different objects # Membership operators fruits = ["apple", "banana", "cherry"] print("banana" in fruits) # Output: True, because "banana" is in the list print("orange" not in fruits) # Output: True, because "orange" is not in the list Key Takeaways: Identity operators ( is , is not ) compare if two variables refer to the same object in memory. Membership operators ( in , not in ) check if a value exists in a sequence like a list, tuple, or string. Use identity operators when checking for object identity and membership operators when testing membership in sequences. Module 7: Strings 1. String Basics Creating strings Accessing characters using indexing slicing Python Notes 117 c o d e r s n o t e . c o m
  • 118. String immutability + Replication 1. String Basics in Python Strings are one of the most commonly used data types in Python, and understanding how to work with them is essential. In Python, strings are sequences of characters enclosed within single quotes ( ' ) or double quotes ( " ). 1.1 Creating Strings You can create strings in Python by enclosing characters in single or double quotes. You can also use triple quotes ( ''' or """ ) for multi-line strings. Examples: # Single quote string string1 = 'Hello, World!' # Double quote string string2 = "Python is awesome!" # Multi-line string multi_line_string = '''This is a multi-line string.''' print(string1) print(string2) print(multi_line_string) 1.2 Accessing Characters Using Indexing Strings in Python are indexed, meaning each character in the string has a specific position (or index). Indexing starts from 0 for the first character. You can access a character in a string by referring to its index. Example: Python Notes 118 c o d e r s n o t e . c o m
  • 119. text = "Python" # Accessing individual characters using indexing print(text[0]) # Output: P print(text[1]) # Output: y print(text[5]) # Output: n Positive indexing starts from 0 (left to right). Negative indexing starts from -1 (right to left). Example with negative indexing: text = "Python" # Negative indexing starts from the last character print(text[-1]) # Output: n print(text[-2]) # Output: o 1.3 Slicing Slicing allows you to extract a portion of a string by specifying a start and end index. The syntax for slicing is: string[start:end:step] start : Index of the first character to include. end : Index of the character to stop at (but not include). step : The step size (optional). Examples: text = "Python Programming" # Slicing a string (from index 0 to 5) print(text[0:6]) # Output: Python # Slicing with step Python Notes 119 c o d e r s n o t e . c o m
  • 120. print(text[0:12:2]) # Output: Pto rg # Omitting the start and end print(text[::3]) # Output: Ph oai 1.4 String Immutability Strings in Python are immutable, meaning you cannot change the content of a string once it is created. If you try to modify a string directly, it will result in an error. Example of attempting to modify a string (will cause an error): text = "Python" # Trying to change the first character text[0] = 'J' # This will cause a TypeError because strings are immutable However, you can create a new string by concatenating or using string methods. Correct way to modify a string (create a new string): text = "Python" new_text = 'J' + text[1:] print(new_text) # Output: Jython Summary of String Basics Creating Strings: Strings can be created using single quotes, double quotes, or triple quotes for multi-line strings. Indexing: You can access characters in a string by their index. Positive indices start from 0, and negative indices start from -1. Slicing: You can extract parts of a string using slicing syntax ( string[start:end:step] ). Immutability: Strings are immutable in Python, meaning their values cannot be modified once created. To change a string, you need to create a Python Notes 120 c o d e r s n o t e . c o m
  • 121. new one. 2. String Methods Modifying strings: upper() , lower() , capitalize() , title() , swapcase() , strip() , lstrip() , rstrip() Searching and replacing: find() , rfind() , index() , rindex() , replace() Splitting and joining: split() , rsplit() , partition() , rpartition() , join() Checking content: isalpha() , isdigit() , isalnum() , isspace() , startswith() , endswith() Strings in Python come with a variety of built-in methods that allow you to manipulate and interact with them in various ways. Below, we will explore some common string methods: 2.1 Modifying Strings upper() : Converts all characters in the string to uppercase. Example: text = "python" print(text.upper()) # Output: PYTHON lower() : Converts all characters in the string to lowercase. Example: text = "Python" print(text.lower()) # Output: python capitalize() : Capitalizes the first character of the string and converts all other characters to lowercase. Example: Python Notes 121 c o d e r s n o t e . c o m
  • 122. text = "python" print(text.capitalize()) # Output: Python title() : Capitalizes the first character of each word in the string. Example: text = "hello python world" print(text.title()) # Output: Hello Python World swapcase() : Converts all uppercase characters to lowercase and vice versa. Example: text = "PyThOn" print(text.swapcase()) # Output: pYtHoN strip() : Removes leading and trailing whitespace from the string. Example: text = " hello " print(text.strip()) # Output: hello lstrip() : Removes leading (left) whitespace. Example: text = " hello" print(text.lstrip()) # Output: hello rstrip() : Removes trailing (right) whitespace. Example: text = "hello " print(text.rstrip()) # Output: hello Python Notes 122 c o d e r s n o t e . c o m
  • 123. 2.2 Searching and Replacing find() : Returns the lowest index of the substring if found, otherwise returns 1 . Example: text = "Python programming" print(text.find("prog")) # Output: 7 print(text.find("java")) # Output: -1 rfind() : Similar to find() , but returns the highest index of the substring. Example: text = "Python programming, Python is great" print(text.rfind("Python")) # Output: 23 index() : Similar to find() , but raises a ValueError if the substring is not found. Example: text = "Python programming" print(text.index("prog")) # Output: 7 rindex() : Similar to index() , but returns the highest index of the substring. Example: text = "Python programming, Python is great" print(text.rindex("Python")) # Output: 23 replace() : Replaces a specified substring with another substring. Example: text = "I love Python" Python Notes 123 c o d e r s n o t e . c o m
  • 124. print(text.replace("Python", "Java")) # Output: I love Java 2.3 Splitting and Joining split() : Splits the string into a list of substrings based on a delimiter (default is whitespace). Example: text = "Python is awesome" print(text.split()) # Output: ['Python', 'is', 'awesome'] rsplit() : Similar to split() , but splits from the right. Example: text = "Python is awesome and fun" print(text.rsplit(" ", 2)) # Output: ['Python is', 'awesome', 'and fun'] partition() : Splits the string into a 3-part tuple: the part before the separator, the separator itself, and the part after the separator. Example: text = "Python programming is fun" print(text.partition("programming")) # Output: ('Python ', 'programming', ' is fun') rpartition() : Similar to partition() , but splits from the right. Example: text = "Python programming is fun" print(text.rpartition("is")) # Output: ('Python programming ', 'is', ' fun') join() : Joins a sequence of strings into a single string, using the string it’s called on as the separator. Python Notes 124 c o d e r s n o t e . c o m
  • 125. Example: words = ["Python", "is", "awesome"] print(" ".join(words)) # Output: Python is awesome 2.4 Checking Content isalpha() : Returns True if all characters in the string are alphabetic. Example: text = "Python" print(text.isalpha()) # Output: True text = "Python3" print(text.isalpha()) # Output: False isdigit() : Returns True if all characters in the string are digits. Example: text = "12345" print(text.isdigit()) # Output: True text = "123abc" print(text.isdigit()) # Output: False isalnum() : Returns True if all characters in the string are alphanumeric (letters and digits). Example: text = "Python3" print(text.isalnum()) # Output: True Python Notes 125 c o d e r s n o t e . c o m
  • 126. text = "Python 3" print(text.isalnum()) # Output: False isspace() : Returns True if all characters in the string are whitespace. Example: text = " " print(text.isspace()) # Output: True text = "Python" print(text.isspace()) # Output: False startswith() : Returns True if the string starts with the specified substring. Example: text = "Python programming" print(text.startswith("Python")) # Output: True endswith() : Returns True if the string ends with the specified substring. Example: text = "Python programming" print(text.endswith("programming")) # Output: True Summary of String Methods Modifying Strings: Methods like upper() , lower() , capitalize() , and others help transform string content. Searching and Replacing: Methods like find() , replace() , and index() allow for finding and replacing substrings. Splitting and Joining: Methods like split() , join() , and partition() help break down or combine strings. Python Notes 126 c o d e r s n o t e . c o m
  • 127. Checking Content: Methods like isalpha() , isdigit() , and isspace() allow you to check the type of content in a string. Regular Expressions re module Functions: search() , match() , fullmatch() , findall() , finditer() , sub() , split() re Module Regular Expressions (regex) are a powerful tool used for searching and manipulating strings based on patterns. Python provides the re module, which contains various functions to work with regular expressions. 1. re Module The re module in Python provides several functions to work with regular expressions. To use it, you need to import the module: import re 2. Key Functions in re Module Here are some common functions in the re module used to perform operations with regular expressions: 2.1 search() Description: Searches for the first occurrence of the pattern in the string. Returns: A match object if the pattern is found, otherwise None . import re text = "The quick brown fox." pattern = r"quick" Python Notes 127 c o d e r s n o t e . c o m
  • 128. result = re.search(pattern, text) if result: print("Match found:", result.group()) else: print("No match found.") # Output: Match found: quick 2.2 match() Description: Checks if the pattern matches at the beginning of the string. Returns: A match object if the pattern matches at the start, otherwise None . import re text = "quick brown fox" pattern = r"quick" result = re.match(pattern, text) if result: print("Match found:", result.group()) else: print("No match found.") # Output: Match found: quick 2.3 fullmatch() Description: Checks if the entire string matches the pattern. Returns: A match object if the entire string matches the pattern, otherwise None . import re text = "quick brown fox" Python Notes 128 c o d e r s n o t e . c o m
  • 129. pattern = r"quick brown fox" result = re.fullmatch(pattern, text) if result: print("Full match found:", result.group()) else: print("No full match found.") # Output: Full match found: quick brown fox 2.4 findall() Description: Finds all occurrences of the pattern in the string. Returns: A list of all matches found. import re text = "cat bat rat hat" pattern = r"at" matches = re.findall(pattern, text) print("Matches found:", matches) # Output: Matches found: ['at', 'at', 'at', 'at'] 2.5 finditer() Description: Returns an iterator yielding match objects for all matches in the string. Returns: An iterator containing match objects. import re text = "cat bat rat hat" pattern = r"at" Python Notes 129 c o d e r s n o t e . c o m
  • 130. matches = re.finditer(pattern, text) for match in matches: print(match.group()) # Output: # at # at # at # at 2.6 sub() Description: Replaces occurrences of the pattern with a specified string. Returns: A new string with the replacements. import re text = "cat bat rat hat" pattern = r"at" replacement = "on" result = re.sub(pattern, replacement, text) print("Replaced text:", result) # Output: Replaced text: con bon ron hon 2.7 split() Description: Splits the string by occurrences of the pattern. Returns: A list of strings split by the pattern. import re text = "apple, orange, banana, grape" pattern = r", " Python Notes 130 c o d e r s n o t e . c o m
  • 131. result = re.split(pattern, text) print("Split result:", result) # Output: Split result: ['apple', 'orange', 'banana', 'grape'] 3. Regular Expression Syntax Here are some common regular expression patterns used in the functions above: . (dot): Matches any character except newline. d : Matches any digit (equivalent to [0-9] ). w : Matches any word character (equivalent to [a-zA-Z0-9_] ). s : Matches any whitespace character (spaces, tabs, newlines). ^ : Matches the beginning of the string. $ : Matches the end of the string. : Matches zero or more occurrences of the preceding pattern. + : Matches one or more occurrences of the preceding pattern. ? : Matches zero or one occurrence of the preceding pattern. [] : Matches any single character within the brackets. | : Acts as an OR operator between patterns. Example: Matching a phone number import re text = "My phone number is 123-456-7890" pattern = r"d{3}-d{3}-d{4}" result = re.search(pattern, text) if result: print("Phone number found:", result.group()) # Output: Phone number found: 123-456-7890 Python Notes 131 c o d e r s n o t e . c o m
  • 132. The re module is a powerful tool for working with text patterns in Python. Functions like search() , match() , findall() , and others allow you to easily search, match, and manipulate strings based on regular expressions. Regular expressions themselves are an essential skill for text processing, data extraction, and validation tasks in Python. Module 8: File Handling 1. File Operations Opening files: open() Reading files: read() , readline() , readlines() Writing files: write() , writelines() Closing files: close() 2. File Modes Read ( r ), write ( w ), append ( a ) File Operations In Python, file operations allow us to interact with external files by reading, writing, and modifying them. Working with files is essential when handling data storage, logs, and configuration settings. Opening Files The open() function is used to open a file in different modes: file = open("example.txt", "r") # Opens a file in read mode 'r' - Read mode (default) 'w' - Write mode (overwrites existing content) 'a' - Append mode (adds content to the end) Python Notes 132 c o d e r s n o t e . c o m
  • 133. Reading Files To read the contents of a file, Python provides multiple methods: file = open("example.txt", "r") content = file.read() # Reads the entire file print(content) file.close() read() : Reads the whole file as a string. readline() : Reads one line at a time. readlines() : Reads all lines into a list. Writing Files To write data to a file, we use the write() or writelines() methods: file = open("example.txt", "w") # Open in write mode file.write("Hello, World!n") # Writes a string to the file file.writelines(["Line 1n", "Line 2n"]) # Writes multiple lines file.close() write() : Writes a string to the file. writelines() : Writes multiple lines from a list. Closing Files After performing file operations, it is important to close the file to free up system resources: file.close() Alternatively, using the with statement ensures automatic closure: with open("example.txt", "r") as file: content = file.read() Python Notes 133 c o d e r s n o t e . c o m
  • 134. print(content) # File is closed automatically after this block This method is preferred as it prevents issues related to forgetting to close the file. Module 9: Object-Oriented Programming 1. Classes and Objects Defining classes using class Creating objects Using __init__ (constructor) self parameter In Python, classes are used to define the structure and behavior of objects. Objects are instances of classes, and classes encapsulate data (attributes) and functions (methods) that operate on the data. 1. Defining a Class Using class A class is defined using the class keyword followed by the class name (typically in PascalCase). class Dog: pass # Empty class In this example, Dog is the class name. The pass statement is used as a placeholder for the class body (though usually, we would add methods and attributes to it). 2. Creating Objects Once a class is defined, you can create objects (instances) of that class. Python Notes 134 c o d e r s n o t e . c o m
  • 135. class Dog: pass # Creating an object of the Dog class dog1 = Dog() Here, dog1 is an instance of the Dog class. 3. Using __init__ (Constructor) The __init__ method is a special method in Python that is automatically called when an object is instantiated. It's used to initialize the object's attributes. This method is commonly known as the constructor. class Dog: def __init__(self, name, breed): self.name = name # Object attribute self.breed = breed # Object attribute # Creating an object and passing arguments to the constructor dog1 = Dog("Buddy", "Golden Retriever") print(dog1.name) # Output: Buddy print(dog1.breed) # Output: Golden Retriever In the above code, __init__ takes the self parameter (referring to the instance) and the attributes name and breed . The values for these attributes are passed when creating an object. 4. self Parameter The self parameter is a reference to the current instance of the class. It allows you to access the instance’s attributes and methods within the class. It's not passed when you create an object, but it is used inside the class to refer to the instance. Python Notes 135 c o d e r s n o t e . c o m
  • 136. class Dog: def __init__(self, name, breed): self.name = name # self refers to the current instance self.breed = breed def bark(self): print(f"{self.name} says woof!") # Creating an object dog1 = Dog("Buddy", "Golden Retriever") dog1.bark() # Output: Buddy says woof! In this example, the bark method uses self.name to access the name attribute of the object. Key Points: 1. Class Definition: Classes are created using the class keyword. 2. Creating Objects: You can instantiate objects of a class by calling the class name followed by parentheses. 3. Constructor ( __init__ ): The __init__ method is used to initialize the object's attributes. It is automatically called when an object is created. 4. Self: The self parameter refers to the instance of the class and is used to access its attributes and methods. Example with Multiple Objects: class Car: def __init__(self, make, model, year): self.make = make self.model = model self.year = year def display_info(self): Python Notes 136 c o d e r s n o t e . c o m
  • 137. print(f"{self.year} {self.make} {self.model}") # Creating multiple objects car1 = Car("Toyota", "Corolla", 2020) car2 = Car("Honda", "Civic", 2021) car1.display_info() # Output: 2020 Toyota Corolla car2.display_info() # Output: 2021 Honda Civic In this example, two Car objects ( car1 and car2 ) are created with different attributes. The display_info() method is used to print information about each car. class Student: school = "Tagore" def data(self,name,gender): self.name = name self.gender = gender print(self.name) print(self.gender) print(Student.school) print(self.__dict__) def start(): s = Student() s.data("Harish","M") s.data("Jeevan","M") s.data("Preetha","F") print(s.__dict__) print(Student.__dict__) start() 2. Attributes and Methods Python Notes 137 c o d e r s n o t e . c o m
  • 138. Instance variables and methods Class variables and methods ( @classmethod ) Static methods ( @staticmethod ) In Python, classes can have different types of variables and methods that function in various ways depending on whether they belong to an instance or the class itself. Let’s explore the distinctions between instance variables, class variables, and static methods. 1. Instance Variables and Methods Instance Variables Instance variables are variables that are specific to an instance (object) of the class. They are defined within the __init__ method and are prefixed with self . Each object of the class has its own copy of instance variables. Instance Methods Instance methods are functions defined inside a class that operate on instance variables. They must include self as the first parameter, which refers to the current object. class Dog: def __init__(self, name, breed): self.name = name # Instance variable self.breed = breed # Instance variable def bark(self): # Instance method print(f"{self.name} says woof!") # Creating an object Python Notes 138 c o d e r s n o t e . c o m
  • 139. dog1 = Dog("Buddy", "Golden Retriever") dog1.bark() # Output: Buddy says woof! In this example, name and breed are instance variables, and bark() is an instance method. 2. Class Variables and Methods Class Variables Class variables are shared among all instances of a class. They are defined within the class but outside any method. All instances of the class share the same class variable. If one object modifies the class variable, it affects all objects. Class Methods A class method is a method that takes the class as its first argument, not the instance ( cls instead of self ). Class methods are defined using the @classmethod decorator. They are used when you want to operate on class-level data (class variables). class Dog: species = "Canis familiaris" # Class variable def __init__(self, name, breed): self.name = name # Instance variable self.breed = breed # Instance variable def bark(self): # Instance method print(f"{self.name} says woof!") @classmethod def change_species(cls, new_species): # Class method cls.species = new_species Python Notes 139 c o d e r s n o t e . c o m
  • 140. # Creating an object dog1 = Dog("Buddy", "Golden Retriever") print(dog1.species) # Output: Canis familiaris # Changing the class variable using class method Dog.change_species("Canis lupus familiaris") print(dog1.species) # Output: Canis lupus familiaris Here: species is a class variable shared by all instances of the class. change_species() is a class method that modifies the class variable species . 3. Static Methods Static Methods Static methods are methods that don’t modify or rely on the state of the instance or the class. They don’t take self or cls as the first parameter. Static methods are defined using the @staticmethod decorator. These methods are used when you want a method that belongs to the class but doesn’t need to access or modify instance or class-level data. class MathOperations: @staticmethod def add(a, b): return a + b # Calling the static method without creating an instance Python Notes 140 c o d e r s n o t e . c o m
  • 141. result = MathOperations.add(5, 10) print("Sum:", result) # Output: Sum: 15 Explanation: The @staticmethod decorator is used to define a static method. Static methods belong to the class rather than an instance, meaning they can be called using the class name without creating an object. In this example, add(a, b) performs addition and returns the result. Would you like me to integrate this explanation into your existing notes? Example Programs class Student: def __init__(self, name, gender, school): self.name = name self.gender = gender self.school = school def display(self): print("Name:", self.name) print("Gender:", self.gender) print("School:", self.school) # Creating an instance of the Student class harish = Student("Harish", "M", "Tagore") jeevan = Student("Jeevan", "M", "Tagore") preetha = Student("Preetha", "F", "Tagore") # Calling the display method harish.display() jeevan.display() preetha.display() Python Notes 141 c o d e r s n o t e . c o m
  • 142. class Student: # Static variable (shared by all instances) school = "Tagore" def __init__(self, name, gender): self.name = name self.gender = gender def display(self): print("Name:", self.name) print("Gender:", self.gender) print("School:", Student.school) # Accessing the static variable using th # Creating instances of the Student class harish = Student("Harish", "M") jeevan = Student("Jeevan", "M") preetha = Student("Preetha", "F") # Calling the display method harish.display() jeevan.display() preetha.display() class Student: # Static variable (shared by all instances) school = "Tagore" def __init__(self, name, gender): self.name = name self.gender = gender def display(self): print("Name:", self.name) print("Gender:", self.gender) Python Notes 142 c o d e r s n o t e . c o m
  • 143. print("School:", Student.school) # Accessing the static variable using th # Static method @staticmethod def get_school(): print("The school name is:", Student.school) # Creating instances of the Student class harish = Student("Harish", "M") jeevan = Student("Jeevan", "M") preetha = Student("Preetha", "F") # Calling the display method harish.display() jeevan.display() preetha.display() # Calling the static method Student.get_school() Key Differences 1. Instance Variables and Methods: Instance Variables: Unique to each instance of the class. Accessed with self . Instance Methods: Operate on instance variables and can access or modify them. They use self as the first parameter. 2. Class Variables and Methods: Class Variables: Shared by all instances of the class. Accessed with cls . Class Methods: Operate on class-level data (class variables) and use cls as the first parameter. Python Notes 143 c o d e r s n o t e . c o m
  • 144. 3. Static Methods: Static Methods: Do not rely on instance or class-level data. They don’t take self or cls as parameters and are used when you want a method that doesn’t interact with instance or class variables. Example Combining All Three class Dog: species = "Canis familiaris" # Class variable def __init__(self, name, breed): self.name = name # Instance variable self.breed = breed # Instance variable def bark(self): # Instance method print(f"{self.name} says woof!") @classmethod def change_species(cls, new_species): # Class method cls.species = new_species @staticmethod def bark_sound(): # Static method print("Woof!") # Creating objects dog1 = Dog("Buddy", "Golden Retriever") dog2 = Dog("Max", "Labrador") # Instance methods dog1.bark() # Output: Buddy says woof! dog2.bark() # Output: Max says woof! # Class method (changing class variable) Dog.change_species("Canis lupus familiaris") Python Notes 144 c o d e r s n o t e . c o m
  • 145. print(dog1.species) # Output: Canis lupus familiaris print(dog2.species) # Output: Canis lupus familiaris # Static method Dog.bark_sound() # Output: Woof! Summary: Instance variables are unique to each object and accessed with self . Class variables are shared among all objects and accessed with cls . Instance methods access instance data, while class methods access class-level data. Static methods don’t require access to instance or class data. Inheritance Single inheritance Multiple inheritance Multilevel inheritance Hierarchical inheritance ybrid Inheritance Overriding methods Specialization Inheritance allows a class (child or subclass) to inherit attributes and methods from another class (parent or superclass). This enables code reuse and helps create a hierarchy of classes with shared behaviors. Python supports several types of inheritance, including single, multiple, multilevel, and hierarchical inheritance. 1. Single Inheritance Python Notes 145 c o d e r s n o t e . c o m
  • 146. In single inheritance, a class (child class) inherits from a single parent class. Example: class Animal: def speak(self): print("Animal makes a sound") class Dog(Animal): # Dog is inheriting from Animal def bark(self): print("Dog barks") # Creating an object of Dog class dog = Dog() dog.speak() # Inherited method dog.bark() # Method in Dog class In this example: Dog inherits the speak() method from the Animal class. The Dog class also defines its own bark() method. 2. Multiple Inheritance In multiple inheritance, a class inherits from more than one parent class. Python allows a class to inherit from multiple classes. Example: class Animal: def speak(self): print("Animal makes a sound") class Mammal: def has_fur(self): print("Mammal has fur") Python Notes 146 c o d e r s n o t e . c o m
  • 147. class Dog(Animal, Mammal): # Dog inherits from both Animal and Mammal def bark(self): print("Dog barks") # Creating an object of Dog class dog = Dog() dog.speak() # Inherited from Animal dog.has_fur() # Inherited from Mammal dog.bark() # Method in Dog class In this example: Dog inherits from both Animal and Mammal . The Dog class has access to methods from both parent classes ( speak() from Animal and has_fur() from Mammal ). 3. Overriding Methods Method overriding occurs when a child class provides a specific implementation of a method that is already defined in its parent class. The method in the child class overrides the method in the parent class. Example: class Animal: def speak(self): print("Animal makes a sound") class Dog(Animal): def speak(self): # Overriding the speak method print("Dog barks") # Creating objects animal = Animal() dog = Dog() Python Notes 147 c o d e r s n o t e . c o m
  • 148. animal.speak() # Output: Animal makes a sound dog.speak() # Output: Dog barks In this example: The Dog class overrides the speak() method of the Animal class to provide a custom implementation. 4. Specialization Specialization is the process of extending or modifying the behavior of a parent class in the child class. The child class inherits all the attributes and methods of the parent class but may also add new features or override existing methods to make them more specific. Example: class Animal: def speak(self): print("Animal makes a sound") class Dog(Animal): def speak(self): # Overriding the speak method print("Dog barks") def fetch(self): # Adding a new method specific to Dog print("Dog is fetching the ball") # Creating an object of Dog class dog = Dog() dog.speak() # Output: Dog barks dog.fetch() # Output: Dog is fetching the ball In this example: Python Notes 148 c o d e r s n o t e . c o m
  • 149. The Dog class specializes the Animal class by overriding speak() and adding the fetch() method, which is specific to the Dog class. 5. Multilevel Inheritance In multilevel inheritance, a class inherits from another class, which itself is derived from another class, forming a chain of inheritance. Example: class Animal: def speak(self): print("Animal makes a sound") class Dog(Animal): # Dog inherits from Animal def bark(self): print("Dog barks") class Puppy(Dog): # Puppy inherits from Dog (and implicitly from Animal) def cute(self): print("Puppy is cute") # Creating an object of Puppy class puppy = Puppy() puppy.speak() # Inherited from Animal puppy.bark() # Inherited from Dog puppy.cute() # Method in Puppy class In this example: Puppy inherits from Dog , and Dog inherits from Animal . The Puppy class can access methods from both Dog and Animal . 6. Hierarchical Inheritance In hierarchical inheritance, multiple classes inherit from the same parent class. Each subclass has its own features but shares common methods and properties Python Notes 149 c o d e r s n o t e . c o m
  • 150. from the parent class. Example: class Animal: def speak(self): print("Animal makes a sound") class Dog(Animal): # Dog inherits from Animal def bark(self): print("Dog barks") class Cat(Animal): # Cat also inherits from Animal def meow(self): print("Cat meows") # Creating objects of Dog and Cat classes dog = Dog() cat = Cat() dog.speak() # Inherited from Animal dog.bark() # Method in Dog class cat.speak() # Inherited from Animal cat.meow() # Method in Cat class In this example: Both Dog and Cat inherit from the Animal class. The speak() method is inherited by both Dog and Cat , while each has its own specialized method ( bark() for Dog and meow() for Cat ). Hybrid Inheritance in Python Hybrid inheritance is a combination of multiple types of inheritance, such as single, multiple, multilevel, or hierarchical inheritance. It allows flexibility but can sometimes lead to complexity and the diamond problem, which Python resolves using the Method Resolution Order (MRO). Python Notes 150 c o d e r s n o t e . c o m
  • 151. Example of Hybrid Inheritance # Parent class class A: def show(self): print("Class A") # Child class inheriting from A class B(A): def show(self): print("Class B") # Another child class inheriting from A class C(A): def show(self): print("Class C") # Class D inheriting from both B and C (Multiple Inheritance) class D(B, C): def show(self): print("Class D") # Creating an object of class D obj = D() obj.show() # Output: Class D # Checking Method Resolution Order (MRO) print(D.mro()) Explanation 1. Class A is the base class. 2. Class B and Class C both inherit from Class A (hierarchical inheritance). 3. Class D inherits from both B and C (multiple inheritance). Python Notes 151 c o d e r s n o t e . c o m
  • 152. 4. When obj.show() is called, it follows MRO, which prioritizes D → B → C → A. Method Resolution Order (MRO) Python resolves the diamond problem using C3 Linearization (MRO). Use ClassName.mro() or help(ClassName) to check MRO. Would you like to add this to your notes? Summary of Inheritance Types: Single Inheritance: One class inherits from another class. Multiple Inheritance: A class inherits from more than one class. Method Overriding: A child class overrides a method of the parent class to provide a different implementation. Specialization: A child class extends or modifies the functionality of the parent class. Multilevel Inheritance: A class inherits from another class, which itself is derived from a third class. Hierarchical Inheritance: Multiple classes inherit from the same parent class. Inheritance helps in creating a hierarchy and allows for code reuse, making it easier to manage and extend functionality. Polymorphism Method overloading using default arguments Method overriding Polymorphism in Python Polymorphism is one of the four pillars of Object-Oriented Programming (OOP). It means "many forms" and allows objects of different classes to be treated as objects of a common superclass. Polymorphism lets you use a unified interface to interact with different types of objects. Python Notes 152 c o d e r s n o t e . c o m
  • 153. # Base class Zomato, representing a generic food delivery platform class Zomato: def menu(self): print("list Veg & Non Veg foods") # Displays both veg and non-veg options def order(self): print("Your Order Placed") # Confirms order placement def delivery(self): print("Order Delivered") # Indicates that the order is delivered # Subclass Veg_Zomato, specialized for vegetarian food class Veg_Zomato(Zomato): def menu(self): print("list Veg foods") # Overrides menu() to show only vegetarian options # Subclass Non_Veg_Zomato, specialized for non-vegetarian food class Non_Veg_Zomato(Zomato): def menu(self): print("list Non-Veg foods") # Overrides menu() to show only non-veg option # Subclass Blink_it, specialized for grocery delivery class Blink_it(Zomato): def menu(self): print("list Groceries") # Overrides menu() to list groceries instead of food def gold_pass(self): print("You are eligible for free delivery") # Exclusive method for Blink_it cus # Function to display the behavior of different objects dynamically def display(ref): ref.menu() # Calls the menu method of the respective class ref.order() # Calls the order method from the base class if type(ref) == Blink_it: ref.gold_pass() # Calls gold_pass() only if the object belongs to Blink_it class Python Notes 153 c o d e r s n o t e . c o m
  • 154. ref.delivery() # Calls the delivery method from the base class # Creating instances of different subclasses v = Veg_Zomato() # Object for vegetarian food ordering nv = Non_Veg_Zomato() # Object for non-vegetarian food ordering b = Blink_it() # Object for grocery delivery # Calling display function to execute respective methods dynamically display(v) # Displays veg menu and processes order display(nv) # Displays non-veg menu and processes order display(b) # Displays grocery menu, applies gold pass (if eligible), and processe ''' The commented section below shows an alternative approach if we had separate for each functionality instead of a generic menu() method in the base class: v.food_list() # Lists vegetarian food v.food_order() # Places order v.order_delivered() # Delivers order nv.food_list() # Lists non-vegetarian food nv.food_order() # Places order nv.order_delivered() # Delivers order b.grocery_list() # Lists groceries b.food_order() # Places order b.order_delivered() # Delivers order ''' Explanation 1. Class Zomato (Base Class): Defines common functionalities like menu() , order() , and delivery() . 2. Class Veg_Zomato & Non_Veg_Zomato (Subclasses): Override menu() to display only veg or non-veg options. Python Notes 154 c o d e r s n o t e . c o m
  • 155. 3. Class Blink_it (Subclass): Overrides menu() for groceries and introduces a new method gold_pass() . 4. Function display() : Uses Polymorphism to call appropriate methods dynamically. Checks if the object is of type Blink_it before calling gold_pass() . 5. Object Creation: Instances of Veg_Zomato , Non_Veg_Zomato , and Blink_it are created and passed to display() . This program demonstrates inheritance, method overriding, and polymorphism in Python. Key Points: Method Overloading in Python is achieved by using default arguments to allow a method to accept varying numbers of arguments. Method Overriding happens when a subclass provides its own implementation of a method that is already defined in the parent class, allowing the child class to change or extend the behavior of the parent class method. Polymorphism helps in writing more flexible and reusable code, as the same method name can be used to perform different tasks depending on the context or the object. Encapsulation Private and protected members ( _ , __ ) Getter and setter methods Super() class Parent: def __init__(self, name): self.name = name print(f"Parent constructor called for {self.name}") def show(self): print(f"Hello, I am {self.name} from the Parent class.") Python Notes 155 c o d e r s n o t e . c o m
  • 156. class Child(Parent): def __init__(self, name, age): super().__init__(name) # Call the parent class constructor self.age = age print(f"Child constructor called for {self.name}, Age: {self.age}") def show(self): super().show() # Call the parent class method print(f"I am {self.name}, {self.age} years old, from the Child class.") # Creating an object of the Child class c = Child("Alice", 25) c.show() Encapsulation in Python Encapsulation is one of the core principles of Object-Oriented Programming (OOP). It is the concept of bundling the data (attributes) and methods (functions) that operate on the data into a single unit or class. Encapsulation helps to protect the data by restricting direct access to some of the object's components and can be achieved by making attributes private and providing public getter and setter methods to access and update those attributes. 1. Private and Protected Members In Python, we can indicate that an attribute or method is private or protected using special naming conventions: Private members: Private members are variables or methods that cannot be accessed directly outside the class. This is done by prefixing the variable or method name with double underscores ( __ ). Protected members: Protected members are intended to be used within the class and its subclasses but can still be accessed outside. This is done by prefixing the variable or method name with a single underscore ( _ ). Python Notes 156 c o d e r s n o t e . c o m
  • 157. Example of Private and Protected Members class BankAccount: def __init__(self, balance): self._balance = balance # Protected member (conventionally) self.__account_number = "12345" # Private member # Getter method for balance def get_balance(self): return self._balance # Setter method for balance with validation (Encapsulation) def set_balance(self, amount): if amount < 0: print("Balance cannot be negative.") else: self._balance = amount # Creating an instance of BankAccount account = BankAccount(1000) # Accessing protected member (not recommended, but possible) print(account._balance) # Output: 1000 # Accessing private member (raises AttributeError) # print(account.__account_number) # Uncommenting this line will give an err or # Using getter and setter methods print(account.get_balance()) # Output: 1000 account.set_balance(500) # Updates balance to 500 print(account.get_balance()) # Output: 500 Private members (like __account_number ) cannot be accessed directly from outside the class. Python Notes 157 c o d e r s n o t e . c o m
  • 158. Protected members (like _balance ) are intended to be used within the class and its subclasses, but Python does not enforce any strict protection. class Bankaccount: def __init__(self, amount): self.__amount = amount # Private attribute to store account balance def set_amount(self, amount): self.__amount = amount # Setter method to update account balance def get_amount(self): return self.__amount # Getter method to retrieve account balance # Creating an object 'b' with an initial balance of 1000 b = Bankaccount(1000) print(b.get_amount()) # Output: 1000 (Retrieves and prints the account balance) b.set_amount(500) # Updates account balance to 500 print(b.get_amount()) # Output: 500 (Retrieves and prints the updated balance) Explanation: 1. Encapsulation: The class Bankaccount uses a private variable __amount , which cannot be accessed directly outside the class. Instead, we use getter ( get_amount() ) and setter ( set_amount() ) methods to access and modify the balance. 2. __init__ Constructor: It initializes the account with a given amount when an object is created. 3. Getter ( get_amount() ) Method: Returns the value of __amount , ensuring controlled access to private data. 4. Setter ( set_amount() ) Method: Python Notes 158 c o d e r s n o t e . c o m
  • 159. Updates the balance with a new value, allowing controlled modification. 5. Object Creation & Method Calls: An instance b is created with an initial balance of 1000. get_amount() is called to retrieve the balance. set_amount(500) modifies the balance. get_amount() is called again to verify the update. This implementation ensures data security by restricting direct modification of __amount and enforcing controlled access through methods. 2. Getter and Setter Methods Getter and setter methods are used to control the access to private or protected members. They allow us to add validation or logic while getting or setting the value of an attribute. Example: Amazon Prime Auto-Debit Scenario (with condition) Let's consider an example where an auto-debit feature is implemented for an account that requires at least a balance of ₹499 to process the debit. The getter and setter methods can be used to ensure this rule is followed. class Account: def __init__(self, balance): self.__balance = balance # Private balance attribute # Getter method for balance def get_balance(self): return self.__balance # Setter method for balance with a condition (Encapsulation) def set_balance(self, amount): if amount < 0: print("Balance cannot be negative.") else: self.__balance = amount Python Notes 159 c o d e r s n o t e . c o m
  • 160. # Method to simulate auto-debit for services like Amazon Prime def auto_debit(self, amount): if self.get_balance() >= 499: # Checking if balance is enough for auto-de bit self.set_balance(self.get_balance() - amount) print(f"₹{amount} debited successfully for Amazon Prime subscriptio n.") else: print("Insufficient balance. Auto-debit failed.") # Creating an instance of Account with ₹1000 balance account = Account(1000) # Simulating the auto-debit process account.auto_debit(499) # Output: ₹499 debited successfully for Amazon Pri me subscription. # Checking balance after auto-debit print("Remaining balance:", account.get_balance()) # Output: Remaining bala nce: 501 # Trying to process auto-debit with less than ₹499 balance account.set_balance(400) # Setting balance to ₹400 account.auto_debit(499) # Output: Insufficient balance. Auto-debit failed. In this example: The __balance attribute is private, so it cannot be accessed directly from outside the class. The getter method ( get_balance() ) allows us to retrieve the balance. The setter method ( set_balance() ) allows us to set the balance, but it includes validation to prevent negative balances. The auto_debit() method checks if the balance is greater than or equal to ₹499 before proceeding with the debit. If the balance is insufficient, it displays an Python Notes 160 c o d e r s n o t e . c o m
  • 161. error message. Why Encapsulation? Encapsulation allows us to: 1. Protect the data: By using private variables and providing controlled access through getters and setters, we can prevent accidental modification of data and ensure that the object’s state remains valid. 2. Maintain consistency: By adding logic (like the balance check in the auto_debit method), we can ensure that invalid operations are prevented. 3. Improve flexibility: Encapsulation allows us to modify the internal workings of a class without affecting the external code using it. For example, if we wanted to change how the balance is calculated or stored, we could do so without affecting how other parts of the program interact with the class. Abstraction in Python Abstraction is a fundamental concept in Object-Oriented Programming (OOP) that hides implementation details and only exposes essential functionalities. Python provides abstraction through abstract classes and methods, which are defined using the ABC (Abstract Base Class) module. Code Breakdown: from abc import ABC, abstractmethod ABC (Abstract Base Class): A built-in module that allows defining abstract classes. abstractmethod decorator: Used to declare methods that must be implemented by child classes. Creating an Abstract Class Python Notes 161 c o d e r s n o t e . c o m
  • 162. class Learn2Code(ABC): @abstractmethod def course_list(self): pass # Abstract method that must be implemented by subclasses Learn2Code is an abstract class that serves as a blueprint. The @abstractmethod decorator forces all subclasses to implement the course_list() method. The pass keyword is used since abstract methods don’t contain any implementation. Defining Subclasses that Inherit the Abstract Class Subclass for Kids class Kids(Learn2Code): def course_list(self): print("Courses for Kids: Scratch Programming, Math Games, Story Codin g.") This class inherits Learn2Code and implements the course_list() method. Subclass for Non-IT Professionals class NonIT(Learn2Code): def course_list(self): print("Courses for Non-IT: Basic Computer Skills, Digital Marketing, MS O ffice.") def mock_ai(self): print("Mock AI session scheduled for interview preparation.") This class implements course_list() and adds an extra method mock_ai() , which is specific to Non-IT students. Python Notes 162 c o d e r s n o t e . c o m
  • 163. Subclass for Professionals class Professional(Learn2Code): def course_list(self): print("Courses for Professionals: Data Science, Cloud Computing, Full St ack Development.") Implements course_list() without additional methods. Displaying Courses Using a Common Function def display(ref): ref.course_list() if isinstance(ref, NonIT): # Check if the instance is of type NonIT ref.mock_ai() The function display() takes an object ref and calls the course_list() method. If ref is an instance of NonIT , it also calls mock_ai() . Creating Objects and Calling Functions kids_user = Kids() non_it_user = NonIT() professional_user = Professional() display(kids_user) display(non_it_user) display(professional_user) Objects are created for each subclass. The display() function is called with each object to show the available courses. Key Takeaways Python Notes 163 c o d e r s n o t e . c o m
  • 164. 1. Abstraction: The abstract class hides implementation details and forces subclasses to implement essential methods. 2. Abstract Methods: Declared using @abstractmethod and must be overridden in subclasses. 3. Code Reusability: The display() function provides a common interface to display course lists for different student categories. This approach ensures better organization, modularity, and flexibility in large applications. Module 10: Exception Handling 1. Introduction to Errors and Exceptions Syntax errors vs. runtime exceptions Common exceptions in Python ( ValueError , TypeError , IndexError , etc.) 1. Introduction to Errors and Exceptions Syntax Errors vs. Runtime Exceptions Errors in Python are broadly categorized into syntax errors and runtime exceptions. Syntax Errors Occur when Python fails to understand the code due to incorrect syntax. These are detected before the program runs. Example: print("Hello World" # Missing closing parenthesis -> SyntaxError Output: Python Notes 164 c o d e r s n o t e . c o m
  • 165. SyntaxError: unexpected EOF while parsing Runtime Exceptions Occur while executing the program, even if the syntax is correct. Examples include ValueError , TypeError , IndexError , etc. Common Exceptions in Python 1. ValueError Occurs when a function receives an argument of the correct type but an inappropriate value. Example: num = int("abc") # Cannot convert string "abc" to an integer Output: ValueError: invalid literal for int() with base 10: 'abc' 2. TypeError Occurs when an operation is performed on an incorrect type. Example: result = "5" + 3 # Mixing string and integer Output: TypeError: can only concatenate str (not "int") to str 3. IndexError Python Notes 165 c o d e r s n o t e . c o m
  • 166. Occurs when trying to access an index that is out of range. Example: lst = [1, 2, 3] print(lst[5]) # Index out of range Output: IndexError: list index out of range 2. Handling Exceptions Using try , except , else , and finally Catching specific exceptions Using except Exception as e Python provides the try-except block to handle exceptions gracefully. Using try , except , else , and finally in Python In Python, exception handling is done using try , except , else , and finally to manage errors gracefully and ensure smooth program execution. 1. try Block: The code that may raise an exception is placed inside the try block. If an error occurs, the program jumps to the except block. 2. except Block: Catches the exception and allows you to handle the error instead of terminating the program. Can specify multiple exception types or a general exception. 3. else Block (Optional): Runs only if the try block executes successfully (i.e., no exception occurs). Python Notes 166 c o d e r s n o t e . c o m
  • 167. Useful for executing code only when no errors are encountered. 4. finally Block (Optional): Runs regardless of whether an exception occurs or not. Typically used for resource cleanup (e.g., closing files, releasing network connections). Example try: num = int(input("Enter a number: ")) # May raise ValueError if input is not a number result = 10 / num # May raise ZeroDivisionError except ValueError: print("Invalid input! Please enter a valid number.") except ZeroDivisionError: print("Division by zero is not allowed.") else: print(f"Result: {result}") # Runs only if no exception occurs finally: print("Execution completed.") # Always executes Key Takeaways try : Contains the code that might cause an exception. except : Handles specific or general exceptions. else : Runs only if try executes without errors. finally : Executes no matter what, ensuring cleanup actions. Using these blocks together ensures robust and error-resilient code execution. Raising Exceptions Using raise keyword Python Notes 167 c o d e r s n o t e . c o m
  • 168. Creating user-defined exceptions Defining custom exception classes 3. Raising Exceptions Using raise Keyword Manually raise an exception if a condition is met. def check_age(age): if age < 18: raise ValueError("Age must be 18 or older.") return "Access granted" print(check_age(15)) # Raises ValueError Creating User-Defined Exceptions Python allows creating custom exceptions by defining a new class. class InvalidAgeError(Exception): """Custom exception for invalid age""" pass def check_voter_age(age): if age < 18: raise InvalidAgeError("You must be at least 18 to vote.") return "Eligible to vote" try: print(check_voter_age(16)) except InvalidAgeError as e: print("Custom Exception:", e) Python Notes 168 c o d e r s n o t e . c o m