0% found this document useful (0 votes)
2 views43 pages

Unit2 v2 Notes

This document covers control flow, functions, collections, and modules in Python programming, focusing on conditions, Boolean logic, and decision-making statements. It explains the Boolean data type, relational operators, truthy and falsy values, logical operators, and various decision-making structures such as if, if-else, nested if, and multi-way if-elif-else statements. Practical examples are provided to illustrate the concepts and syntax used in Python for implementing these control flow mechanisms.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views43 pages

Unit2 v2 Notes

This document covers control flow, functions, collections, and modules in Python programming, focusing on conditions, Boolean logic, and decision-making statements. It explains the Boolean data type, relational operators, truthy and falsy values, logical operators, and various decision-making structures such as if, if-else, nested if, and multi-way if-elif-else statements. Practical examples are provided to illustrate the concepts and syntax used in Python for implementing these control flow mechanisms.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

CSE3011 – Python Programming

UNIT 2
Control Flow, Functions, Collections & Modules
2.1 Conditions and Boolean Logic
Every practical program needs to make decisions. Should the student be classified as 'pass' or 'fail'? Is
the entered password correct? Is the temperature above a safe threshold? In Python, decisions are
made by evaluating conditions — expressions that reduce to either True or False. These two special
values belong to Python's Boolean data type (bool), named after the 19th-century British mathematician
George Boole, who showed that logical reasoning could be expressed mathematically using only two
values.
Boolean logic is the foundation of all digital computation. Every transistor in a microprocessor
implements a Boolean function. Every if statement, every while loop, every search algorithm ultimately
depends on the ability to ask a yes-or-no question and act on the answer.

2.1.1 The Boolean Data Type


Python's bool type has exactly two instances: True and False. These are keywords — they must be
capitalised exactly. Lowercase 'true' or 'false' would be treated as undefined variable names, producing
a NameError. Internally, True is stored as the integer 1 and False as 0, which means Booleans can
participate in arithmetic, although this is rarely used in practice.
Boolean Type Demonstration
>>> True
True
>>> False
False
>>> type(True)
<class 'bool'>
>>> type(False)
<class 'bool'>
>>> int(True)
1
>>> int(False)
0
>>> True + True
2 # Boolean arithmetic (rarely used in practice)
Remember: True and False are capitalized Python keywords. The expressions 'true' and 'false'
would raise NameError. Python is case-sensitive: True is not the same as true, TRUE, or tRuE.

2.1.2 Relational (Comparison) Operators


Relational operators compare two values and produce a Boolean result. They are the primary source
of Boolean values in programs and are the building blocks of all conditional logic. There are six
relational operators in Python:
Operator Meaning Example Result Explanation
== Equal to 5 == 5 True Both sides have
the same value
!= Not equal to 5 != 3 True The values differ
> Greater than 10 > 7 True Left side is larger
< Less than 3<8 True Left side is
smaller
Operator Meaning Example Result Explanation
>= Greater than or 5 >= 5 True Left is equal to or
equal larger than right
<= Less than or 4 <= 6 True Left is equal to or
equal smaller than right

Relational Operator Examples


>>> a = 2
>>> b = 2
>>> a == b
True
>>> 4 > 1
True
>>> 4 < 9
True
>>> 4 >= 4
True
>>> 4 <= 3
True
>>> 5 != 4
True
>>> p, q, r = 1, 2, 3
>>> p < q < r # Chained comparison
True
>>> p > q > r
False
Important: Use == (double equals) for comparison and = (single equals) for assignment. Writing 'if x
= 5:' instead of 'if x == 5:' causes a SyntaxError in Python 3. Also remember that comparison is case-
sensitive for strings: 'Apple' == 'apple' is False.

2.1.3 Truthy and Falsy Values


Python's logical operators work not just with True/False but with any data type. When a non-Boolean
value is used in a Boolean context (like an if condition), Python treats it as either 'truthy' (behaves like
True) or 'falsy' (behaves like False). Understanding this is essential for writing Pythonic code.
Value / Type Boolean Interpretation Why
0 (integer) False Zero is falsy for all numeric
types
0.0 (float) False Zero float is falsy
0j (complex) False Zero complex is falsy
'' (empty string) False Empty string is falsy
[] (empty list) False Empty collections are falsy
{} (empty dict) False Empty dictionary is falsy
() (empty tuple) False Empty tuple is falsy
set() (empty set) False Empty set is falsy
None False None always evaluates to False
Value / Type Boolean Interpretation Why
Any non-zero number True Non-zero values are truthy
Any non-empty string True Non-empty strings are truthy
Any non-empty collection True Non-empty collections are
truthy

Truthy / Falsy Examples


>>> not 1 # not True → False
False
>>> not 5 # 5 is truthy, so not truthy → False
False
>>> not 0 # 0 is falsy, so not falsy → True
True
>>> not 0.0
True
>>> not 'hello' # Non-empty string is truthy
False
>>> not '' # Empty string is falsy
True

2.2 Logical Operators (Boolean Operators)


Logical operators combine Boolean expressions to form compound conditions. Python provides three
logical operators: not, and, and or. The precedence order from highest to lowest is: not, then and, then
or. When in doubt, use parentheses to make the intended precedence explicit.

2.2.1 The 'not' Operator


The not operator is a unary operator — it takes only one operand. It negates the Boolean value of its
operand: True becomes False and False becomes True. In numerical terms, it converts all non-zero
values to False and zero/empty values to True.
Operand (X) not X
True False
False True

not Operator Examples


>>> True
True
>>> not True
False
>>> False
False
>>> not False
True
>>> x = 10
>>> not (x > 5) # not True → False
False
>>> not (x < 0) # not False → True
True

2.2.2 The 'and' Operator


The and operator is a binary operator — it requires two operands. It returns True only when BOTH
operands are True. If either operand is False, the result is False. In programming logic, and is used to
check that multiple conditions are all satisfied simultaneously.
X Y X and Y
True True True
True False False
False True False
False False False

and Operator Examples


>>> True and True
True
>>> True and False
False
>>> False and True
False
>>> False and False
False

# Practical example: check both age AND income


age = 25
income = 50000
if age >= 18 and income > 30000:
print('Eligible for loan')

2.2.3 The 'or' Operator


The or operator returns True if AT LEAST ONE of its operands is True. It only returns False when both
operands are False. In programming, or is used when any one of several conditions being true is
sufficient.
X Y X or Y
True True True
True False True
False True True
False False False

or Operator Examples
>>> True or True
True
>>> True or False
True
>>> False or True
True
>>> False or False
False

# Practical example: check if divisible by 5 or 10


num = 45
if num % 5 == 0 or num % 10 == 0:
print(num, 'is divisible by 5 or 10')

2.2.4 Short-Circuit (Conditional) Evaluation


Python's logical operators use short-circuit evaluation (also called lazy evaluation) to improve
performance and avoid unnecessary computation. Python stops evaluating as soon as the final result
is determined:
• Short-circuit AND: If the first operand is False, the overall 'and' expression must be False
regardless of the second operand. Python skips evaluating the second operand entirely.
• Short-circuit OR: If the first operand is True, the overall 'or' expression must be True
regardless of the second operand. Python skips evaluating the second operand entirely.
This property is not just an optimization — it is often used deliberately to prevent runtime errors:
Short-Circuit Safety Example
# Without short-circuit: 100 / x would raise ZeroDivisionError
# With short-circuit: (x != 0) is False, so the right side is never
evaluated
x = 0
result = (x != 0) and (100 / x > 5)
print(result) # False — no ZeroDivisionError!

# Similarly for 'or':


text = 'hello'
# If text is non-empty (truthy), the or expression is True immediately
# Python never evaluates the right side
result = text or 'default'
print(result) # 'hello' (text was truthy, right side skipped)
Short-Circuit AND: Conditional AND operator: If OP1 is False, Python does not evaluate OP2. This
prevents errors like division by zero when the divisor check is placed first.
Short-Circuit OR: Conditional OR operator: If OP1 is True, Python does not evaluate OP2. This is
used for efficient 'or-else-default' patterns.

2.3 Decision Making Statements


Programs that execute statements only in sequence from top to bottom are called monolithic or
sequential programs. While this style works for simple tasks, real-world problems almost always require
the program to choose between different paths of execution based on conditions. Control flow
statements alter the sequential execution order. Python supports the following decision-making
statements: if, if-else, nested if, and multi-way if-elif-else.

2.3.1 The if Statement


The if statement is the simplest form of decision making. It executes a block of code only when a
specified Boolean expression is True. If the expression is False, the block is skipped entirely and
execution resumes after the if block.

Syntax:
if condition:
statement_1 # Executed only if condition is True
statement_2
...
Key rules:
1. The condition is a Boolean expression that evaluates to True or False.
2. A colon (:) is mandatory at the end of the if line.
3. The body (indented block) must be indented consistently — 4 spaces by convention (PEP 8).
4. The body executes if and only if the condition is True. If False, the body is completely ignored.
Program: Check if radius is positive, then compute area
from math import pi
radius = eval(input('Enter Radius of Circle: '))
if radius > 0:
area = radius * radius * pi
print('Area of Circle is =', format(area, '.2f'))
circumference = 2 * pi * radius
print('Circumference =', format(circumference, '.2f'))

Output
Enter Radius of Circle: 5
Area of Circle is = 78.54
Circumference = 31.42
Indentation Rule: All statements in the if block must be indented by the same number of spaces.
Python determines block boundaries purely by indentation — there are no curly braces like in C or
Java. Inconsistent indentation causes IndentationError.

2.3.2 The if-else Statement


The if-else statement provides two alternative paths of execution. If the condition is True, the if block
executes. If False, the else block executes. Exactly one of the two blocks will always run — never both,
never neither. This is also called a two-way decision.

Syntax:
if condition:
if_block_statements # Runs when condition is True
else:
else_block_statements # Runs when condition is False
Program: Find greater of two numbers
num1 = int(input('Enter the First Number: '))
num2 = int(input('Enter the Second Number: '))
if num1 > num2:
print(num1, 'is greater than', num2)
else:
print(num2, 'is greater than', num1)
Output
Enter the First Number: 100
Enter the Second Number: 43
100 is greater than 43
Program: Check if number is divisible by 5 and 10
num = int(input('Enter the number: '))
print('Entered Number is:', num)
if num % 5 == 0 and num % 10 == 0:
print(num, 'is divisible by both 5 and 10')
if num % 5 == 0 or num % 10 == 0:
print(num, 'is divisible by 5 or 10')
else:
print(num, 'is not divisible by 5 or 10')
Points to Remember: The else keyword must line up exactly with the corresponding if statement.
Both blocks must be indented by the same number of spaces. Python determines which else matches
which if purely by indentation.

2.3.3 Nested if Statements


When one if statement is placed inside another if or else block, it creates a nested if structure. Nested
if statements allow decisions that depend on the outcome of previous decisions — a 'decision within a
decision'. Every inner if can have its own else block.

Syntax:
if Boolean-expression1:
if Boolean-expression2:
statement1 # Both expr1 AND expr2 are True
else:
statement2 # expr1 True, expr2 False
else:
statement3 # expr1 False
Program: Compare three numbers using nested if
num1 = int(input('Enter first number: '))
num2 = int(input('Enter second number: '))
num3 = int(input('Enter third number: '))
if num1 > num2:
if num2 > num3:
print(num1, 'is greatest')
else:
print(num1, 'is less than', num2, 'and', num3)
print('End of Nested if')

Output (inputs: 12, 34, 56)


12 is less than 34 and 56
End of Nested if

2.3.4 Multi-way if-elif-else Statements


When a program needs to choose from more than two alternatives, the if-elif-else chain is used. elif is
an abbreviation for 'else if'. Python evaluates conditions from top to bottom, and the first True condition
causes its block to execute. All remaining conditions are skipped, even if they would also be True. If no
condition is True, the else block (if present) executes.
Syntax:
if Boolean-expression1:
statement1
elif Boolean-expression2:
statement2
elif Boolean-expression3:
statement3
# ... as many elif as needed ...
else:
default_statement # Optional: executes if all are False
Program: Grade classification based on marks percentage
per = float(input('Enter percentage: '))
if per >= 90:
print('Distinction')
elif per >= 80:
print('First Class')
elif per >= 70:
print('Second Class')
elif per >= 60:
print('Pass')
else:
print('Fail')

Program: Day of week using elif


day = int(input('Enter day of week (1-7): '))
if day == 1:
print('Its Monday')
elif day == 2:
print('Its Tuesday')
elif day == 3:
print('Its Wednesday')
elif day == 4:
print('Its Thursday')
elif day == 5:
print('Its Friday')
elif day == 6:
print('Its Saturday')
elif day == 7:
print('Its Sunday')
else:
print('Sorry!!! Week contains only 7 days')
Program: Menu-driven calculator
num1 = float(input('Enter the first number: '))
num2 = float(input('Enter the second number: '))
print('1-Addition 2-Subtraction 3-Multiplication 4-Division')
choice = int(input('Please Enter the Choice: '))
if choice == 1:
print('Addition:', num1 + num2)
elif choice == 2:
print('Subtraction:', num1 - num2)
elif choice == 3:
print('Multiplication:', num1 * num2)
elif choice == 4:
print('Division:', num1 / num2)
else:
print('Sorry!!! Invalid Choice')

2.3.5 Conditional (Ternary) Expression


Python provides a compact single-line form for simple two-way decisions. Unlike languages such as
Java and C++, Python does not have a ?: ternary operator. Instead, it uses a conditional expression
with the following syntax:
expression1 if condition else expression2
If the condition is True, expression1 is evaluated and returned. If False, expression2 is evaluated and
returned. This is equivalent to a full if-else block but expressed in a single line. It is most useful for
simple assignments and return values.
Conditional Expression Examples
# Find minimum of two numbers
num1 = int(input('Enter first number: '))
num2 = int(input('Enter second number: '))
min_val = num1 if num1 < num2 else num2
print('Minimum =', min_val)

# Equivalent if-else:
# if num1 < num2:
# min_val = num1
# else:
# min_val = num2

# Square or cube based on even/odd


x = int(input('Enter x: '))
result = x * x if x % 2 == 0 else x * x * x
print('Result:', result)

2.4 Ranges and Loop Control Statements


In programming, many tasks require performing the same operation repeatedly. Without loops, a
programmer would have to write the same statement dozens or hundreds of times. Loops allow a block
of code to execute repeatedly until a condition is met. Python provides two main loop constructs: the
while loop (condition-controlled) and the for loop (count-controlled). Python also provides the range()
function, which is deeply integrated with the for loop.
Loops are one of the most powerful features of any programming language. They allow programs to
process large amounts of data, iterate over sequences, and automate repetitive tasks efficiently.

2.4.1 The range() Function


The range() function is a built-in Python function that generates a sequence of integers on demand. It
does not create a list in memory but generates values one at a time (it is an iterable), making it memory-
efficient even for very large ranges. It is most commonly used with the for loop to control the number of
iterations.

Syntax Forms:
range(stop) # 0 to stop-1
range(start, stop) # start to stop-1
range(start, stop, step) # start to stop-1, incrementing by step
Example Generated Sequence Description
range(5) [0, 1, 2, 3, 4] 0 to 4 (5 elements)
range(1, 5) [1, 2, 3, 4] 1 to 4
range(1, 10, 2) [1, 3, 5, 7, 9] Odd numbers from 1 to 9
range(5, 0, -1) [5, 4, 3, 2, 1] Countdown from 5 to 1
range(5, 0, -2) [5, 3, 1] Countdown, step -2
range(-4, 4) [-4, -3, -2, -1, 0, 1, 2, 3] Negative to positive
range(-4, 4, 2) [-4, -2, 0, 2] Step 2 from -4
range(0, 1) [0] Single element
range(1, 1) [] Empty (start == stop)
range(0) [] Empty (stop == 0)

Note: range() does NOT include the stop value. range(1, 6) generates 1, 2, 3, 4, 5 — NOT 6. To
generate up to and including n, use range(1, n+1).

2.4.2 The while Loop


The while loop is a condition-controlled loop. It repeatedly executes a block of statements as long as a
specified Boolean condition remains True. The condition is tested before each iteration (hence it is a
pre-test loop). When the condition becomes False, the loop terminates and execution continues with
the first statement after the loop body.

Syntax:
while test-condition:
statement_1 # Loop body
statement_2
...
update_expression # Must eventually make condition False
Every while loop must have three essential elements:
5. Initialization: Set up the loop variable before the loop begins.
6. Test Condition: A Boolean expression checked before each iteration.
7. Update: A statement that changes the loop variable so the condition eventually becomes
False.
Infinite Loop Warning: If the update expression is missing or the condition can never become False,
the loop runs forever. An infinite loop is created intentionally with 'while True:' but must always have a
break statement to exit.
Program 1: Print numbers 0 to 5
count = 0 # Initialization
while count <= 5: # Test condition
print('Count =', count)
count = count + 1 # Update (increment)

Output
Count = 0
Count = 1
Count = 2
Count = 3
Count = 4
Count = 5
Program 2: Sum of first 10 numbers
count = 0
sum = 0
while count <= 10:
sum = sum + count
count = count + 1
print('Sum of First 10 Numbers =', sum)

Output
Sum of First 10 Numbers = 55
Program 3: Sum of digits of a number
num = int(input('Please Enter the number: '))
x = num
sum = 0
rem = 0
while num > 0:
rem = num % 10 # Extract last digit
num = num // 10 # Remove last digit
sum = sum + rem # Add digit to sum
print('Sum of digits of', x, 'is =', sum)

Output
Please Enter the number: 12345
Sum of digits of 12345 is = 15
Program 4: Reverse of a number
num = int(input('Please Enter the number: '))
x = num
rev = 0
while num > 0:
rem = num % 10
num = num // 10
rev = rev * 10 + rem
print('Reverse of', x, 'is =', rev)

Output
Please Enter the number: 8759
Reverse of 8759 is = 9578
Program 5: Check Armstrong number
# Armstrong number: sum of cubes of its digits equals the number
# Example: 153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153
num = int(input('Please enter the number: '))
sum = 0
x = num
while num > 0:
d = num % 10
num = num // 10
sum = sum + (d * d * d)
if x == sum:
print('The number', x, 'is Armstrong Number')
else:
print('The number', x, 'is not Armstrong Number')

Output
Please enter the number: 153
The number 153 is Armstrong Number

2.4.3 The for Loop


The for loop is a count-controlled loop. Unlike the while loop, the for loop iterates over a sequence of
objects (such as a range, string, list, tuple, or any iterable). For each element in the sequence, the loop
body executes once. The loop variable automatically takes on the next value in the sequence at each
iteration. Python's for loop is more like a 'for-each' loop in other languages — it does not use a counter
explicitly.

Syntax:
for var in sequence:
statement_1 # Executes for each element in sequence
statement_2
...
The sequence can be a range, a string, a list, a tuple, or any iterable object. On each iteration, the loop
variable 'var' is automatically assigned the next value from the sequence.
Program 1: Print numbers 1 to 5
for i in range(1, 6):
print(i)
print('End of The Program')

Output
1 2 3 4 5
End of The Program
Program 2: Print capital letters A to Z
print('Capital Letters A to Z:')
for i in range(65, 91, 1):
print(chr(i), end=' ')

Output
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Program 3: Print squares of first five numbers
for i in range(1, 6):
square = i * i
print('Square of', i, 'is:', square)

Output
Square of 1 is: 1
Square of 2 is: 4
Square of 3 is: 9
Square of 4 is: 16
Square of 5 is: 25
Program 4: Sum of even numbers from 0 to 10
sum = 0
print('Even numbers from 0 to 10:')
for i in range(0, 11, 1):
if i % 2 == 0:
print(i)
sum = sum + i
print('Sum of Even numbers =', sum)
Program 5: Fibonacci series
First_Number = int(input('Enter First Number: '))
Second_Number = int(input('Enter Second Number: '))
Limit = int(input('Number of Fibonacci Numbers to Print: '))
print(First_Number, end=' ')
print(Second_Number, end=' ')
for i in range(Limit + 1):
sum = First_Number + Second_Number
First_Number = Second_Number
Second_Number = sum
print(sum, end=' ')

2.4.4 Nested Loops


A nested loop is a loop that appears inside another loop. The inner loop executes completely for each
single iteration of the outer loop. If the outer loop runs M times and the inner loop runs N times, the
inner loop body executes M × N times total. Nested loops are essential for processing two-dimensional
data, generating patterns, and matrix operations.
Program: Multiplication table (1 to 5)
print('Multiplication Table from 1 to 5')
for i in range(1, 11, 1): # Outer loop: rows
for j in range(1, 6, 1): # Inner loop: columns
print(format(i * j, '4d'), end=' ')
print() # New line after each row
Program: Triangle star pattern
print('Star Pattern Display')
for i in range(1, 6):
for j in range(1, i + 1):
print('*', end=' ')
print()

Output
*
* *
* * *
* * * *
* * * * *
Program: Number pattern
for i in range(1, 6):
for j in range(1, i + 1):
print(j, end=' ')
print()
Output
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5

2.4.5 Flow Control: break, continue, pass


Python provides three special statements that alter the normal sequential flow of a loop. These are
particularly useful for early termination and skipping iterations based on conditions.

The break Statement


The break statement immediately terminates the enclosing loop when it is executed. Control jumps to
the first statement after the loop body. break is typically used inside an if statement to exit the loop early
when a specific condition is met.
Feature break continue
Effect on loop Exits from loop immediately Skips current iteration only
Loop after execution Loop terminates Loop continues next iteration
Control goes to First statement after loop Beginning of loop (next
iteration)
Terminates loop? Yes No

break Example: Print 1 to 10 only


print('Numbers from 1 to 10:')
for i in range(1, 100, 1): # Loop designed for 100 iterations
if i == 11:
break # Exit when i reaches 11
else:
print(i, end=' ')

Output
1 2 3 4 5 6 7 8 9 10
break Example: Check if number is prime
num = int(input('Enter the Number: '))
x = num
for i in range(2, num):
if num % i == 0:
flag = 0
break # No need to check further
else:
flag = 1
if flag == 1:
print(num, 'is Prime')
else:
print(num, 'is not prime')

The continue Statement


The continue statement skips the remaining code in the current iteration and immediately jumps to the
next iteration of the loop. The loop itself does NOT terminate — it simply proceeds to the next value.
This is exactly opposite to break: break terminates the loop, continue continues it (skipping the rest of
the current iteration).
continue Example: Skip number 5
for i in range(1, 11, 1):
if i == 5:
continue # Skip printing 5
print(i, end=' ')

Output
1 2 3 4 6 7 8 9 10
continue Example: Remove spaces from string
str1 = str(input('Please Enter the String: '))
print('Entered String is:', str1)
print('After Removing Spaces:')
for i in str1:
if i == ' ':
continue # Skip spaces
print(i, end='')

Output
Please Enter the String: Hello World
Entered String is: Hello World
After Removing Spaces: HelloWorld

The pass Statement


The pass statement is a null operation — it does nothing when executed. It is used as a syntactic
placeholder in situations where a statement is required by Python's grammar but the programmer does
not want any code to execute. It is commonly used for empty function bodies, empty class bodies, or
incomplete loop bodies during development.
for i in range(5):
if i == 3:
pass # Do nothing for i=3, just continue
else:
print(i, end=' ')
# Output: 0 1 2 4

2.5 Functions
A function is a self-contained block of one or more statements that performs a specific task when called.
Functions are the fundamental building block of structured, modular programming. They allow large
programs to be broken into smaller, independently manageable and testable units. Each function
should ideally have a single, well-defined purpose.
Without functions, a programmer who needs the same operation performed in three different places in
the code would need to write that code three times. Any bug in that code would need to be fixed in
three places. With functions, the code is written once, and called three times — bugs only need to be
fixed in one place.
Key benefits of functions:
• Reusability: Write once, call many times — eliminates duplicate code.
• Modularity: Breaking a large problem into smaller functions makes it easier to design,
implement, and debug.
• Readability: Named functions with clear names make code self-documenting.
• Abstraction: Users of a function only need to know what it does and how to call it — not the
internal implementation details.
• Maintainability: Changes to functionality only need to be made in one place.

2.5.1 Defining and Calling a Function


Syntax:
def function_name(parameter1, parameter2, ...):
'''Optional docstring describing the function'''
statement_1
statement_2
...
return value # Optional
Key components:
8. def keyword: Tells Python you are defining a function.
9. function_name: A valid identifier. By convention, use lowercase with underscores (e.g.,
calculate_area, print_message).
10. parameters: Input values inside parentheses. Can be empty: def greet(): is valid.
11. Colon (:): Mandatory at the end of the def line.
12. Function body: Indented block of statements that execute when the function is called.
13. return: Sends a value back to the caller. Without return, the function returns None.
Program: Simple function with no parameters
def Display():
print('Welcome to Python Programming')

Display() # Calling the function

Output
Welcome to Python Programming
Program: Function with input
def print_msg():
str1 = input('Please Enter Your Name: ')
print('Dear', str1, 'Welcome to Python Programming')

print_msg() # Call function

Output
Please Enter Your Name: Virat
Dear Virat Welcome to Python Programming
Program: Function reuse — sum of integers in range
def sum_range(x, y):
s = 0
for i in range(x, y + 1):
s = s + i
print('Sum of integers from', x, 'to', y, 'is', s)

sum_range(1, 25)
sum_range(50, 75)
sum_range(90, 100)

Output
Sum of integers from 1 to 25 is 325
Sum of integers from 50 to 75 is 1625
Sum of integers from 90 to 100 is 1045

2.5.2 Parameters and Arguments


Parameters are the variable names listed in a function's definition — they are the formal names used
inside the function body. Arguments are the actual values passed when the function is called. Python
provides three types of argument-passing styles.
Term Definition Example
Parameter Variable in function definition def printMax(num1, num2): —
(formal parameter) num1 and num2 are
parameters
Argument Actual value passed during printMax(10, 20) — 10 and 20
function call are arguments

1. Positional Arguments
Arguments are matched to parameters by position. The first argument maps to the first parameter, the
second to the second, and so on. The number of arguments must exactly match the number of
parameters in the function definition. Passing too few or too many arguments causes a TypeError.
Positional Argument Example
def printMax(num1, num2):
print('num1 =', num1)
print('num2 =', num2)
if num1 > num2:
print('The Number', num1, 'is Greater than', num2)
elif num2 > num1:
print('The Number', num2, 'is Greater than', num1)
else:
print('Both Numbers are equal')

printMax(20, 10) # num1=20, num2=10

Output
num1 = 20
num2 = 10
The Number 20 is Greater than 10

2. Keyword Arguments
A keyword argument passes a value to a specific named parameter, regardless of position. The syntax
is parameter_name=value in the function call. This allows arguments to be passed in any order, which
improves code readability.
Keyword Argument Example
def Display(Name, age):
print('Name =', Name, 'age =', age)

Display(age=25, Name='John') # Order doesn't matter

Output
Name = John age = 25
Precautions for keyword arguments:
14. A positional argument cannot follow a keyword argument in the same call.
15. The same parameter cannot receive a value both positionally and as a keyword argument.
# Valid:
Display(40, age=25) # num1 positional, age keyword

# Invalid (will cause SyntaxError):


Display(age=25, 40) # positional after keyword

3. Default Arguments
A parameter can have a default value specified with = in the function definition. If the caller does not
provide a value for that parameter, the default is used automatically. Default parameters must come
after all non-default parameters in the definition — otherwise Python raises SyntaxError.
Default Argument Example
def greet(name, msg='Welcome to Python!!'):
print('Hello', name, msg)

greet('Sachin') # Uses default msg


greet('Bill Gates', 'How are You?') # Overrides default

Output
Hello Sachin Welcome to Python!!
Hello Bill Gates How are You?
Default Argument Example — Area of circle
def area_circle(pi=3.14, radius=1):
area = pi * radius * radius
print('radius =', radius)
print('The area of Circle =', area)

area_circle() # Both defaults used


area_circle(radius=5) # Only radius overridden

Output
radius = 1
The area of Circle = 3.14
radius = 5
The area of Circle = 78.5

2.5.3 The return Statement


The return statement serves two purposes: it terminates the function's execution, and it optionally sends
a value (or multiple values) back to the caller. A function can have multiple return statements in different
branches, but only one will execute per call. If no return statement is present, or if return is used without
a value, the function automatically returns the special value None.
Program: Return minimum of two numbers
def minimum(a, b):
if a < b:
return a
elif b < a:
return b
else:
return 'Both numbers are equal'

print(minimum(100, 85))

Output
85
Program: Return multiple values
def calc_arith_op(num1, num2):
return num1 + num2, num1 - num2 # Returns a tuple

print(calc_arith_op(10, 20))

Output
(30, -10)
Program: Assign multiple returned values
def compute(num1):
print('Number =', num1)
return num1 * num1, num1 * num1 * num1

square, cube = compute(4)


print('Square =', square, 'Cube =', cube)

Output
Number = 4
Square = 16 Cube = 64
None Return: A return statement without a value (just 'return') is equivalent to 'return None'. If a
function contains no return statement, it also returns None. None is a special Python type representing
the absence of a value.

2.5.4 Local and Global Scope of Variables


The scope of a variable defines the region of the program where that variable is accessible. Python
uses the LEGB rule for name resolution: it searches Local → Enclosing → Global → Built-in scopes in
that order.
Scope Where Defined Accessible From Example
Local Inside a function Only within that def f(): x = 5 — x is
function local to f
Enclosing (E) Outer function of Inner function only def outer(): y=1; def
nested function inner(): print(y)
Scope Where Defined Accessible From Example
Global (G) Outside all functions Entire module x = 100 at top level
(module level)
Built-in (B) Python's standard Anywhere len, print, range, int,
library etc.

Local vs Global Example


p = 20 # Global variable p

def Demo():
q = 10 # Local variable q
print('Local variable q:', q)
print('Global Variable p:', p) # Can READ globals

Demo()
print('Global variable p:', p)

Output
Local variable q: 10
Global Variable p: 20
Global variable p: 20
Accessing local variable outside function — ERROR
def Demo():
q = 10
print('Local variable q:', q)
Demo()
print('q:', q) # NameError: name 'q' is not defined

The global Keyword


By default, when you assign a value inside a function, Python creates a new local variable, even if a
global variable with the same name exists. To modify a global variable from inside a function, explicitly
declare it with the global keyword.
Without global keyword (global variable unchanged)
a = 20
def Display():
a = 30 # Creates LOCAL 'a', does not change global
print('In function:', a)
Display()
print('Outside function:', a)

Output
In function: 30
Outside function: 20 # Global unchanged
With global keyword (global variable modified)
a = 20
def Display():
global a # Declare intent to modify global
a = 30 # Now modifies the global variable
print('In function:', a)
Display()
print('Outside function:', a)

Output
In function: 30
Outside function: 30 # Global was modified

2.5.5 Recursive Functions


A recursive function is a function that calls itself from within its own body. Recursion allows a
programmer to express problems that have a naturally repetitive or nested structure in a concise and
elegant way. Every recursive function must have:
16. A base case: A condition that stops the recursion (the function returns without calling itself
again).
17. A recursive case: The function calls itself with a simpler or smaller version of the problem,
moving toward the base case.
If a base case is missing or unreachable, the recursion continues indefinitely until Python raises a
RecursionError (maximum recursion depth exceeded).
Program: Factorial using recursion
# n! = n * (n-1) * (n-2) * ... * 1
# Base case: 0! = 1
def factorial(n):
if n == 0:
return 1 # Base case
return n * factorial(n - 1) # Recursive case

# Trace: factorial(5)
# = 5 * factorial(4)
# = 5 * 4 * factorial(3)
# = 5 * 4 * 3 * factorial(2)
# = 5 * 4 * 3 * 2 * factorial(1)
# = 5 * 4 * 3 * 2 * 1 * factorial(0)
# = 5 * 4 * 3 * 2 * 1 * 1 = 120
print(factorial(5)) # 120
Program: Fibonacci using recursion
# Fib(0) = 1, Fib(1) = 1
# Fib(n) = Fib(n-1) + Fib(n-2) for n >= 2
def fib(n):
if n == 0:
return 1
if n == 1:
return 1
return fib(n - 1) + fib(n - 2)

print('The Value of 8th Fibonacci number =', fib(8))

Output
The Value of 8th Fibonacci number = 34

2.5.6 Lambda Functions (Anonymous Functions)


Lambda functions are small, unnamed (anonymous) functions defined using the lambda keyword. They
are named after the Greek letter lambda (λ). Unlike regular functions defined with def, lambda functions
have no name, contain only a single expression (not a block of statements), and do not contain a return
statement (the expression's value is automatically returned). They are typically used for short
operations where a full function definition would be unnecessarily verbose.

Syntax:
name = lambda parameter1, parameter2, ... : expression
Lambda Examples
# Calculate cube
cube = lambda x: x * x * x
print(cube(3)) # 27
print(cube(2)) # 8

# Add two numbers


add = lambda a, b: a + b
print(add(5, 3)) # 8

# Compare with regular function:


def func(x): # Traditional function
return x * x * x
print(func(3)) # 27 (same result)

# Lambda with no parameters


greet = lambda: 'Hello World'
print(greet()) # Hello World
Lambda Limitations: Lambda functions can only contain a single expression — not multiple
statements, loops, or assignments. For anything more complex, use a regular def function. Also,
lambda functions do not contain a return statement — the expression is returned automatically.

2.6 Exception Handling


When a Python program encounters an error during execution, it raises an exception — a signal that
an unexpected or erroneous condition has occurred. If the exception is not caught (handled), the
program terminates abruptly with an error message called a traceback. Exception handling allows
programs to detect errors, respond to them gracefully, and continue executing rather than crashing.
Good exception handling is a mark of professional, robust code. It ensures that the program provides
meaningful error messages to users, logs errors for debugging, and recovers gracefully from
unexpected conditions.

2.6.1 Common Built-in Exceptions


Exception When It Occurs Example
ZeroDivisionError Division or modulo by zero 10 / 0 or 10 % 0
ValueError Function receives argument of int('abc')
right type but wrong value
TypeError Operation applied to wrong 'hello' + 5
data type
Exception When It Occurs Example
NameError Name (variable/function) not print(undefined)
defined
IndexError Sequence index out of range [1,2,3][10]
KeyError Dictionary key not found d['missing']
FileNotFoundError File does not exist open('[Link]')
AttributeError Object has no such attribute 'str'.push('x')
ImportError Module cannot be imported import nonexistent_module
RecursionError Max recursion depth exceeded Infinite recursive function
OverflowError Arithmetic result too large [Link](1000)
RuntimeError General runtime error Various runtime situations

2.6.2 The try-except-else-finally Structure


Syntax:
try:
# Block of code that might raise an exception
risky_statement
except ExceptionType1:
# Handles ExceptionType1
except ExceptionType2 as e:
# Handles ExceptionType2, stores exception in 'e'
except (TypeError, ValueError):
# Handles multiple exception types in one clause
except Exception as e:
# Catch-all for any remaining exception
else:
# Executes ONLY if try block completed without exception
finally:
# ALWAYS executes, whether exception occurred or not
Execution flow:
18. Python executes the try block.
19. If an exception occurs, Python stops executing the try block immediately.
20. Python searches the except clauses for one that matches the exception type.
21. The first matching except clause executes.
22. The else block runs only if the try block completed without any exception.
23. The finally block ALWAYS runs, regardless of whether an exception occurred.
Complete Exception Handling Example
try:
num = int(input('Enter a number: '))
result = 100 / num
except ValueError:
print('Error: Please enter a valid integer!')
except ZeroDivisionError:
print('Error: Cannot divide by zero!')
except Exception as e:
print(f'Unexpected error: {e}')
else:
print(f'100 / {num} = {result:.2f}')
finally:
print('Execution complete.')
Program: Safe calculator with exception handling
def safe_divide(a, b):
try:
result = a / b
return result
except ZeroDivisionError:
print('Division by zero is not allowed')
return None

print(safe_divide(10, 2)) # 5.0


print(safe_divide(10, 0)) # Error message + None

2.6.3 Raising Exceptions


Programmers can also deliberately raise exceptions using the raise keyword. This is useful for enforcing
constraints on function input parameters or signaling error conditions in application logic.
raise Example
def set_age(age):
if age < 0 or age > 150:
raise ValueError(f'Invalid age: {age}. Must be 0-150.')
return age

try:
set_age(-5)
except ValueError as e:
print('Caught exception:', e)

2.7 Input, Output, and Modules

2.7.1 I/O Functions Recap


Python's input/output model is simple and consistent. The three fundamental I/O functions — print(),
input(), and eval() — were introduced in Unit 1. In Unit 2, we use them extensively with loops and
functions.
Function Purpose Returns Example
print() Display values to the None print('Hello', x, sep=', ')
console
input(prompt) Read a line from the str (always) x = input('Enter: ')
user
eval(expr) Evaluate a Python The expression's value eval('3 + 4') → 7
expression stored in a
string
Function Purpose Returns Example
int(input(...)) Read an integer from int n = int(input('Enter n:
user '))
float(input(...)) Read a float from user float x = float(input('Enter x:
'))

input() Always Returns String: The input() function ALWAYS returns a string, regardless of what
the user types. If you want a number, you must explicitly convert using int() or float(). Failing to do so
will cause TypeError when you try to use the value arithmetically.

2.7.2 Modules
A module is a file containing Python code — functions, classes, variables, and executable statements.
Modules allow code to be organized into reusable, shareable units. Python comes with an extensive
standard library of modules, and thousands more are available through the Python Package Index
(PyPI).

Ways to Import Modules:


# Method 1: Import entire module
import math
print([Link](16)) # Must use module prefix

# Method 2: Import specific names


from math import sqrt, pi
print(sqrt(25)) # No prefix needed

# Method 3: Import all names (not recommended)


from math import *
print(ceil(4.2))

# Method 4: Import with alias


import numpy as np # Convention: use np as alias
import pandas as pd
Module Key Contents Usage Example
math sqrt, pi, e, sin, cos, log, ceil, [Link](144) → 12.0
floor, factorial, pow
random random(), randint(), choice(), [Link](1, 100)
shuffle(), sample()
os getcwd(), listdir(), mkdir(), [Link]()
rename(), remove(), path
sys argv, exit(), path, version, [Link][0]
platform
datetime datetime, date, time, timedelta [Link]()
string ascii_letters, digits, punctuation, [Link]
whitespace
re match(), search(), findall(), [Link](r'\d+', text)
sub(), compile()
json dumps(), loads(), dump(), load() [Link]({'a': 1})
Module Key Contents Usage Example
csv reader(), writer(), DictReader(), [Link](f)
DictWriter()
statistics mean(), median(), mode(), [Link]([1,2,3])
stdev(), variance()

2.8 Collections
Python provides several built-in collection types that allow multiple values to be stored and managed
together. Choosing the right collection type for a given problem is a critical programming skill that affects
both code clarity and performance.
Collection Ordered? Mutable? Allows Syntax
Duplicates?
list Yes Yes (can modify) Yes [1, 2, 3]
tuple Yes No (immutable) Yes (1, 2, 3)
set No Yes (can No (unique only) {1, 2, 3}
add/remove)
dict Yes (3.7+) Yes Keys: No, Values: {'a': 1, 'b': 2}
Yes

2.8.1 Lists
A list is an ordered, mutable sequence of elements. Lists are the most versatile collection in Python.
They can hold elements of different types, including other lists (nested lists). Elements are enclosed in
square brackets and separated by commas.
Creating and Accessing Lists
empty = []
numbers = [1, 2, 3, 4, 5]
fruits = ['apple', 'banana', 'cherry']
mixed = [10, 'hello', 3.14, True, None]
nested = [[1, 2], [3, 4], [5, 6]]

# Indexing (positive and negative)


lst = ['a', 'b', 'c', 'd', 'e']
print(lst[0]) # 'a' (first element)
print(lst[-1]) # 'e' (last element)
print(lst[-2]) # 'd' (second from last)

# Slicing [start:end:step] — end is exclusive


print(lst[1:4]) # ['b', 'c', 'd']
print(lst[:3]) # ['a', 'b', 'c']
print(lst[2:]) # ['c', 'd', 'e']
print(lst[::2]) # ['a', 'c', 'e'] (every 2nd)
print(lst[::-1]) # ['e', 'd', 'c', 'b', 'a'] (reversed)

List Methods:
Method Description Example
append(x) Add x at end of list [Link]('mango')
insert(i, x) Insert x at position i [Link](1, 'grape')
extend(iter) Add all elements from iter to [Link](['fig', 'plum'])
end
remove(x) Remove first occurrence of x [Link]('banana')
pop() Remove and return last last = [Link]()
element
pop(i) Remove and return element at item = [Link](0)
index i
sort() Sort in ascending order (in- [Link]()
place)
sort(reverse=True) Sort in descending order [Link](reverse=True)
reverse() Reverse the list in-place [Link]()
index(x) Return index of first x [Link]('apple')
count(x) Count occurrences of x [Link](5)
clear() Remove all elements [Link]()
copy() Shallow copy of list lst2 = [Link]()
len(lst) Number of elements len([1, 2, 3]) → 3

List Operations Example


marks = [85, 72, 90, 68, 95, 78]
[Link]()
print('Sorted:', marks)
print('Highest:', marks[-1])
print('Lowest:', marks[0])
print('Average:', sum(marks) / len(marks))

List Comprehension
List comprehension provides a concise, Pythonic way to create a new list by applying an expression to
each element of an iterable, optionally filtered by a condition. It is both more readable and more efficient
than the equivalent for loop.
# Syntax: [expression for item in iterable if condition]

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


# [1, 4, 9, 16, 25]

evens = [x for x in range(20) if x % 2 == 0]


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

upper = [[Link]() for s in ['hello', 'world']]


# ['HELLO', 'WORLD']

2.8.2 Tuples
A tuple is an ordered, immutable sequence of elements. Tuples are similar to lists but cannot be
modified after creation — elements cannot be added, removed, or changed. This immutability makes
tuples faster than lists, suitable for fixed collections, and safe to use as dictionary keys (since they are
hashable).
Creating and Using Tuples
empty = ()
single = (42,) # Trailing comma is REQUIRED for single element
coordinates = (3.5, 4.2)
rgb = (255, 128, 0)
mixed = (1, 'two', 3.0, True)

# Accessing elements (same as lists)


t = (10, 20, 30, 40, 50)
print(t[2]) # 30
print(t[1:4]) # (20, 30, 40)
print(len(t)) # 5
print(30 in t) # True

# Tuple unpacking
x, y = (10, 20)
a, b, c = rgb
print(a, b, c) # 255 128 0

# Swap using tuple


x, y = 10, 20
x, y = y, x
print(x, y) # 20 10
Feature List Tuple
Mutability Mutable (can change) Immutable (cannot change)
Syntax [1, 2, 3] (1, 2, 3)
Performance Slightly slower Slightly faster
Use as dict key? No (not hashable) Yes (hashable)
Memory Uses more memory Uses less memory
When to use Data that changes (shopping Fixed data (coordinates, RGB,
cart, scores) days of week)

2.8.3 Sets
A set is an unordered collection of unique elements. Sets automatically eliminate duplicates — if you
add the same element twice, it only appears once. Sets support efficient membership testing and
mathematical set operations. They are defined with curly braces {} or the set() constructor (for empty
sets, you must use set() since {} creates an empty dictionary).
Creating and Using Sets
empty = set() # NOT {} — that creates empty dict
primes = {2, 3, 5, 7, 11}
vowels = {'a', 'e', 'i', 'o', 'u'}

# Duplicates are removed automatically


s = {1, 2, 3, 2, 1, 3}
print(s) # {1, 2, 3}

# Set operations
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
print(A | B) # Union: {1, 2, 3, 4, 5, 6, 7, 8}
print(A & B) # Intersection: {4, 5}
print(A - B) # Difference: {1, 2, 3}
print(A ^ B) # Symmetric Diff: {1, 2, 3, 6, 7, 8}
Operation Operator Method Description
Union | union() All elements in A or B
(or both)
Intersection & intersection() Elements in both A
and B
Difference - difference() Elements in A but not
in B
Symmetric Difference ^ symmetric_difference() In A or B but not in
both
Subset <= issubset() True if all of A is in B
Superset >= issuperset() True if A contains all of
B

Set Methods
s = {1, 2, 3}
[Link](4) # Add element: {1, 2, 3, 4}
[Link](2) # Remove (no error if missing): {1, 3, 4}
[Link](1) # Remove (KeyError if missing): {3, 4}
print(len(s)) # 2
print(5 in s) # False

2.8.4 Dictionaries
A dictionary (dict) is an ordered (Python 3.7+) collection of key-value pairs. Each key must be unique
and immutable (strings, numbers, or tuples are common keys). Values can be of any type and can be
duplicated. Dictionaries provide O(1) average-case time complexity for lookups, insertions, and
deletions — making them extremely fast for data retrieval by key.
Dictionaries are one of the most frequently used data structures in Python. They model real-world
entities with named attributes (like a student with name, age, marks) and are essential for counting
frequencies, caching computations, and building lookup tables.
Creating Dictionaries
empty = {}
student = {'name': 'Alice', 'age': 20, 'marks': 92.5}
inventory = {'apple': 50, 'banana': 30, 'cherry': 100}
config = dict(host='localhost', port=5432, db='school')
CRUD Operations
d = {'name': 'Bob', 'age': 25, 'city': 'Delhi'}

# Access (Read)
print(d['name']) # 'Bob'
print([Link]('phone', 'N/A')) # 'N/A' — default if key missing

# Create / Update
d['email'] = 'bob@[Link]' # Create new key
d['age'] = 26 # Update existing key

# Delete
del d['city'] # Remove key-value pair
popped = [Link]('age') # Remove and return value

# Check key existence


print('name' in d) # True
print('phone' in d) # False

Dictionary Methods:
Method Description Returns
keys() All keys dict_keys view
values() All values dict_values view
items() All key-value pairs as tuples dict_items view
get(key, default) Value for key, or default if Value or default
missing
pop(key) Remove and return value for Removed value
key
update(d2) Merge d2 into dict None
clear() Remove all items None
copy() Shallow copy New dict

Iterating a Dictionary
student = {'name': 'Alice', 'age': 20, 'marks': 92.5}

# Iterate over keys


for key in student:
print(key, '->', student[key])

# Iterate over key-value pairs (most common)


for key, value in [Link]():
print(f'{key:10} : {value}')

# Get list of all keys/values


print(list([Link]()))
print(list([Link]()))
Nested Dictionary
school = {
'students': {'Alice': 92, 'Bob': 85, 'Carol': 78},
'teachers': {'Math': 'Dr. Smith', 'Science': 'Ms. Jones'}
}
print(school['students']['Alice']) # 92
print(school['teachers']['Math']) # Dr. Smith
Word Frequency Counter using Dictionary
sentence = 'to be or not to be that is the question'
words = [Link]()
freq = {}
for word in words:
freq[word] = [Link](word, 0) + 1
print(freq)

2.9 Regular Expressions


A regular expression (regex) is a sequence of characters that defines a search pattern. Regular
expressions are used to search for, match, extract, replace, or split strings based on complex patterns.
They are an extremely powerful text-processing tool used in data validation (email addresses, phone
numbers), log file analysis, web scraping, and text transformation.
In Python, regular expressions are provided through the built-in re module. Regex patterns are typically
written as raw strings (with an 'r' prefix, like r'\d+') to avoid Python's own interpretation of backslash
escape sequences.

2.9.1 The re Module — Key Functions


Function Description Returns
[Link](pat, str) Match pattern at START of Match object or None
string only
[Link](pat, str) Search for pattern ANYWHERE Match object or None
in string
[Link](pat, str) Find ALL non-overlapping List of matching strings
matches
[Link](pat, str) Like findall, but returns iterator Iterator of match objects
of match objects
[Link](pat, repl, str) Replace all matches with Modified string
replacement string
[Link](pat, str) Split string at each match of List of substrings
pattern
[Link](pat) Compile pattern into reusable Compiled regex object
regex object

Basic re Module Usage


import re

text = 'Python was created in 1991 by Guido van Rossum.'

# findall: Find all sequences of digits


digits = [Link](r'\d+', text)
print(digits) # ['1991']

# search: Find first 4-digit sequence anywhere


m = [Link](r'\d{4}', text)
print([Link]()) # '1991'

# sub: Replace name with abbreviation


result = [Link](r'Guido van Rossum', 'GvR', text)
print(result)

2.9.2 Special Characters (Meta-characters)


Meta-characters are the special characters that give regular expressions their pattern-matching power.
They match not just themselves but entire classes or positions of characters.
Meta-char Meaning Example Pattern Matches
. Any single character a.c 'abc', 'axc', 'a1c'
except newline
^ Start of string ^Hello String must begin with
'Hello'
$ End of string world$ String must end with
'world'
\\d Any digit [0-9] \\d\\d\\d '123', '456', '000'
\\D Any non-digit \\D+ Letters, spaces,
symbols
\\w Word char [a-zA-Z0- \\w+ 'hello', 'var_1', 'abc123'
9_]
\\W Non-word character \\W Spaces, punctuation
\\s Whitespace (space, \\s+ One or more spaces
tab, newline)
\\S Non-whitespace \\S+ Any non-space
character sequence
[abc] Any ONE character [aeiou] Single vowel
from the set
[^abc] Any character NOT in [^aeiou] Non-vowel
the set
[a-z] Character in range a to [a-zA-Z] Any letter
z
[0-9] Any digit (same as \\d) [0-9]+ One or more digits

2.9.3 Quantifiers
Quantifiers specify how many times the preceding pattern element (character, group, or class) must
match. They are among the most powerful features of regular expressions, allowing flexible matching
of repetitions.
Quantifier Meaning Example Matches
* Zero or more times ab* 'a', 'ab', 'abb', 'abbb'...
(greedy)
Quantifier Meaning Example Matches
+ One or more times ab+ 'ab', 'abb', 'abbb' (NOT
(greedy) 'a')
? Zero or one time colou?r 'color' or 'colour'
(optional)
{n} Exactly n times \\d{4} Exactly 4 digits: '2024',
'1999'
{n,} At least n times \\d{3,} 3 or more digits
{n,m} Between n and m \\d{2,4} 2, 3, or 4 digits
times
*? Non-greedy zero or <.*?> Shortest HTML tag
more match
+? Non-greedy one or a.+?b Shortest match
more between a and b

Quantifier Examples
import re

# Match exactly 4 digits (year)


text = 'Python 1991, version 3.12'
years = [Link](r'\d{4}', text)
print(years) # ['1991']

# Validate 10-digit phone number


phone = '9876543210'
if [Link](r'^\d{10}$', phone):
print('Valid phone number')

# Extract email addresses


text2 = 'Contact us at support@[Link] or sales@[Link]'
emails = [Link](r'[\w.-]+@[\w.-]+\.\w{2,}', text2)
print(emails) # ['support@[Link]', 'sales@[Link]']

# Match dates in format YYYY-MM-DD


date_text = 'Events: 2024-01-15 and 2023-12-25'
dates = [Link](r'\d{4}-\d{2}-\d{2}', date_text)
print(dates) # ['2024-01-15', '2023-12-25']

2.9.4 Groups and Capturing


Parentheses () in a regular expression create a group. Groups allow you to extract specific parts of a
match and apply quantifiers to multiple characters at once.
# Extract year, month, day from date
m = [Link](r'(\d{4})-(\d{2})-(\d{2})', '2024-01-15')
print([Link](0)) # '2024-01-15' (entire match)
print([Link](1)) # '2024' (first group)
print([Link](2)) # '01' (second group)
print([Link](3)) # '15' (third group)
# Alternation with |
pattern = r'cat|dog|bird'
animals = [Link](pattern, 'I have a cat, a dog, and a bird')
print(animals) # ['cat', 'dog', 'bird']

2.10 Basic String Operations


Strings in Python are immutable sequences of Unicode characters. Python provides an extensive set
of built-in string methods. Since strings are immutable, all string methods return a new string rather
than modifying the original. String methods are called using dot notation: string.method_name().

2.10.1 String Methods Reference


Method Description Example Result
upper() All characters 'hello'.upper() 'HELLO'
uppercase
lower() All characters 'HELLO'.lower() 'hello'
lowercase
capitalize() First letter upper, rest 'hello world'.capitalize() 'Hello world'
lower
title() First letter of each 'hello world'.title() 'Hello World'
word uppercase
swapcase() Swap case of each 'HeLLo'.swapcase() 'hEllO'
character
strip() Remove ' hi '.strip() 'hi'
leading/trailing
whitespace
lstrip() Remove leading ' hi '.lstrip() 'hi '
whitespace
rstrip() Remove trailing ' hi '.rstrip() ' hi'
whitespace
split(sep) Split into list at 'a,b,c'.split(',') ['a','b','c']
separator
split() Split at whitespace 'a b c'.split() ['a','b','c']
join(iter) Join iterable with ','.join(['a','b']) 'a,b'
separator
find(sub) First index of sub (-1 if 'hello'.find('ll') 2
not found)
rfind(sub) Last index of sub 'hello'.rfind('l') 3
index(sub) Like find() but raises 'hello'.index('ll') 2
ValueError
count(sub) Count occurrences of 'banana'.count('a') 3
sub
Method Description Example Result
replace(old, new) Replace old with new 'hi 'hello hello'
hi'.replace('hi','hello')
startswith(s) True if string starts 'Python'.startswith('Py') True
with s
endswith(s) True if string ends with 'Python'.endswith('on') True
s
isdigit() True if all chars are '123'.isdigit() True
digits
isalpha() True if all chars are 'abc'.isalpha() True
letters
isalnum() True if all 'abc123'.isalnum() True
alphanumeric
islower() True if all lowercase 'hello'.islower() True
isupper() True if all uppercase 'HELLO'.isupper() True
isspace() True if all whitespace ' '.isspace() True
zfill(w) Pad with zeros on left '42'.zfill(6) '000042'
to width w
center(w) Center in field of width 'hi'.center(10) ' hi '
w
ljust(w) Left-align in field of 'hi'.ljust(10) 'hi '
width w
rjust(w) Right-align in field of 'hi'.rjust(10) ' hi'
width w

String Operations Examples


s = ' Hello, Python World! '

print([Link]()) # 'Hello, Python World!'


print([Link]()) # ' hello, python world! '
print([Link]()) # ' HELLO, PYTHON WORLD! '
print([Link]().title()) # 'Hello, Python World!'
print([Link]().replace(',', '')) # 'Hello Python World!'

words = [Link]().split()
print(words)
# ['Hello,', 'Python', 'World!']
print(len(words)) # 3

sentence = ' '.join(words)


print(sentence)
# 'Hello, Python World!'

# Test methods
print('Python'.startswith('Py')) # True
print('Python'.endswith('on')) # True
print('123'.isdigit()) # True
print('abc'.isalpha()) # True
Practical String Processing Program
text = input('Enter a sentence: ')
words = [Link]()
print(f'Original: {text}')
print(f'Uppercase: {[Link]()}')
print(f'Word count: {len(words)}')
print(f'Character count: {len(text)}')
print(f'Is all letters?: {[Link](" ","").isalpha()}')

# Count word frequencies


freq = {}
for word in words:
word = [Link]().strip('.,!?')
freq[word] = [Link](word, 0) + 1

print('Most common word:', max(freq, key=[Link]))

2.11 Comprehensive Worked Programs

Program 1: Generate Prime Numbers (1 to 100)


Code
print('Prime numbers between 1 and 100:')
for num in range(2, 101):
is_prime = True
for i in range(2, int(num**0.5) + 1):
if num % i == 0:
is_prime = False
break
if is_prime:
print(num, end=' ')
Output
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Program 2: Student Marks Report with Grade


Code
def get_grade(marks):
if marks >= 90:
return 'A+'
elif marks >= 80:
return 'A'
elif marks >= 70:
return 'B'
elif marks >= 60:
return 'C'
else:
return 'F'

students = {}
n = int(input('Number of students: '))
for _ in range(n):
name = input('Enter name: ')
marks = float(input('Enter marks (0-100): '))
students[name] = marks

total = sum([Link]())
avg = total / len(students)

print('\n--- Grade Report ---')


print(f'{"Name":<15} {"Marks":>6} {"Grade":>6}')
print('-' * 30)
for name, marks in sorted([Link](), key=lambda x: x[1],
reverse=True):
print(f'{name:<15} {marks:>6.1f} {get_grade(marks):>6}')
print('-' * 30)
print(f'Class Average: {avg:.1f}')

Program 3: Fibonacci Series using Function


Code
def fibonacci(n):
'''Returns list of first n Fibonacci numbers'''
if n <= 0:
return []
a, b = 0, 1
series = []
for _ in range(n):
[Link](a)
a, b = b, a + b
return series

n = int(input('How many Fibonacci numbers? '))


result = fibonacci(n)
print('Fibonacci series:', result)
print('Sum:', sum(result))
Output (n=10)
Fibonacci series: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Sum: 88

Program 4: Matrix Multiplication


Code
def multiply_matrices(A, B):
rows_A, cols_A = len(A), len(A[0])
rows_B, cols_B = len(B), len(B[0])
if cols_A != rows_B:
raise ValueError('Incompatible matrices')
result = [[0] * cols_B for _ in range(rows_A)]
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
result[i][j] += A[i][k] * B[k][j]
return result
A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]
C = multiply_matrices(A, B)
print('A x B:')
for row in C:
print(row)
Output
A x B:
[19, 22]
[43, 50]

Program 5: Word Frequency using Regex and Dictionary


Code
import re

def word_frequency(text):
'''Count frequency of each word in text, ignoring case and
punctuation'''
words = [Link](r'\b[a-zA-Z]+\b', [Link]())
freq = {}
for word in words:
freq[word] = [Link](word, 0) + 1
return freq

text = 'Python is great. Python is easy. I love Python programming.'


freq = word_frequency(text)

# Sort by frequency (descending)


sorted_freq = sorted([Link](), key=lambda x: x[1], reverse=True)
print('Word Frequencies:')
for word, count in sorted_freq:
print(f'{word:15} : {count}')
Output
python : 3
is : 2
great : 1
easy : 1
i : 1
love : 1
programming : 1

2.12 Unit Summary


Topic Key Points
Boolean Type True and False; bool type; case-sensitive; True=1, False=0
Relational Operators ==, !=, >, <, >=, <= produce True/False; chain comparisons (a < b < c)
Logical Operators not (unary, highest priority), and (both must be True), or (at least one
True)
Topic Key Points
Short-Circuit Evaluation and: stops if first is False; or: stops if first is True; prevents errors
Truthy/Falsy Falsy: 0, 0.0, '', [], {}, (), None; everything else is truthy
if Statement Executes block only when condition True; colon and indentation
mandatory
if-else Statement Two-way decision; exactly one block executes
Nested if if inside another if; handles multi-level decisions
if-elif-else Multi-way decision; checks conditions top to bottom; first True wins
Conditional Expression x if condition else y — single-line two-way decision
range() range(stop), range(start,stop), range(start,stop,step); stop excluded
while Loop Condition-controlled; needs init + condition + update; pre-test
for Loop Count-controlled; iterates over sequence; auto-manages iteration
Nested Loops Inner loop runs completely for each outer iteration; use for 2D problems
break Immediately exits loop; control goes to first statement after loop
continue Skips rest of current iteration; loop continues with next iteration
pass Null operation; syntactic placeholder for empty blocks
Functions def name(params): body; promotes reusability and modularity
Positional Arguments Matched by position; order and count must match definition
Keyword Arguments name=value; any order; explicit and readable
Default Arguments param=default; used when caller omits that argument
return Statement Send value back to caller; can return multiple values as tuple
Variable Scope (LEGB) Local → Enclosing → Global → Built-in; global keyword to modify
globals
Recursion Function calls itself; needs base case + recursive case
Lambda lambda params: expr — anonymous, single-expression, no return
statement
Exception Handling try/except/else/finally; catches runtime errors; raise for custom errors
Modules import, from...import; standard library: math, random, os, datetime, re
Lists Ordered, mutable; [], indexing, slicing, methods, list comprehension
Tuples Ordered, immutable; (); indexing, slicing, unpacking; faster than lists
Sets Unordered, unique elements; {}, set(); | & - ^ operations
Dictionaries {key:value}; ordered (3.7+); keys unique; .get(), .keys(), .items()
Regular Expressions import re; match/search/findall/sub; meta-chars; quantifiers * + ? {n,m}
String Methods upper/lower/strip/split/join/find/replace/startswith/endswith/isdigit
2.13 Review Questions

A. Multiple Choice Questions


24. What is the output of: print(not (5 > 3 and 2 < 1)) a) False b) True c) None d) Error
[Answer: b — (5>3 and 2<1) = (True and False) = False; not False = True]
25. What does range(2, 10, 3) produce? a) [2, 5, 8] b) [2, 4, 6, 8] c) [3, 6, 9] d) [2, 5, 8, 11]
[Answer: a]
26. What is the output of: for i in range(1,11): if i==5: break; print(i, end=' ')? a) 1 2 3 4 b) 1 2 3
4 6 7 8 9 10 c) 5 d) Nothing [Answer: a]
27. Which collection does NOT allow duplicate values? a) list b) tuple c) set d) string
[Answer: c]
28. What does the 'finally' block in try-except guarantee? a) Runs only on success b) Runs
only on exception c) Always runs d) Runs only on error [Answer: c]
29. Which of the following is a valid lambda function? a) lambda x,y: x+y b) def lambda(x):
return x c) lambda(x): return x d) function x: x*2 [Answer: a]
30. What is the output of: lst=[1,2,3]; [Link]([4,5]); print(len(lst))? a) 5 b) 4 c) 3 d) 2
[Answer: b — append adds [4,5] as one element]
31. Which statement best describes short-circuit evaluation of 'A and B'? a) Always evaluates
both A and B b) Evaluates B first c) Skips B if A is False d) Skips A if B is True [Answer:
c]
32. What will print(not 0) produce? a) False b) 0 c) True d) Error [Answer: c — 0 is falsy,
not falsy = True]
33. What does [Link](r'\d+', 'I have 3 cats and 12 dogs') return? a) '3' b) ['3', '12'] c) '12' d)
3 [Answer: b]

B. True or False
34. The continue statement immediately terminates the enclosing loop. (False — it skips the
current iteration, loop continues)
35. A function can return multiple values in Python using a tuple. (True)
36. Sets can contain duplicate elements. (False — sets only store unique elements)
37. Global variables can be read inside functions without the global keyword. (True)
38. The pass statement does nothing and is used as a placeholder. (True)
39. In Python 3, 5/2 gives 2. (False — it gives 2.5; use 5//2 for integer floor division)
40. The [Link]() function returns a list of all non-overlapping matches. (True)
41. Dictionary keys must be unique, but values can be duplicated. (True)
42. A positional argument can follow a keyword argument in a function call. (False — SyntaxError)
43. range(5, 0, -1) generates [5, 4, 3, 2, 1]. (True)

C. Short Answer Questions


44. What are the three essential elements of a while loop? Explain with an example.
45. Explain the difference between break and continue with code examples.
46. What is the difference between positional, keyword, and default arguments? Give examples of
each.
47. Explain the LEGB rule for variable scope. What happens if you try to modify a global variable
inside a function without the global keyword?
48. What is a recursive function? What are the two essential components of any recursive
function?
49. What is the difference between a list and a tuple? Under what circumstances would you
choose one over the other?
50. Explain short-circuit evaluation in logical operators. Provide a practical example showing how
it can prevent a runtime error.
51. What is the difference between [Link]() and [Link]()? Provide examples.
52. What does the conditional expression 'a if condition else b' do? Write an equivalent if-else
block.
53. What is the finally block in exception handling? When is it executed and why is it useful?

D. Programming Exercises
54. Write a Python program using a function is_prime() to print all prime numbers between 1 and
100.
55. Write a Python program to find the GCD (Greatest Common Divisor) of two numbers using
Euclid's algorithm in a while loop.
56. Write a function that accepts a list of numbers and returns a tuple containing the (minimum,
maximum, sum, average).
57. Write a program using a dictionary to store 5 students and their marks. Display only those who
scored above the class average.
58. Write a program using regular expressions to extract all phone numbers (format: 10
consecutive digits) from a given text.
59. Write a recursive function to compute the sum of digits of a number. Test it with 12345.
60. Write a program to find the most frequently occurring word in a sentence, ignoring punctuation
and case.
61. Write a Python program to display the following pattern using nested loops: * * * * * *
**** *****
62. Write a program with proper exception handling to read two numbers and perform division,
handling both ValueError (non-numeric input) and ZeroDivisionError.
63. Write a program to create a set of common subjects between two students (stored as sets),
subjects unique to each student, and all subjects combined.

E. Fill in the Blanks


64. The logical operators in decreasing order of precedence are: ______, ______, ______. (not,
and, or)
65. The ______ statement exits a loop, while ______ skips to the next iteration. (break, continue)
66. A function that calls itself is called a ______ function. (recursive)
67. The ______ collection type stores unique, unordered elements. (set)
68. The regular expression quantifier {3,6} means match between ______ and ______ times. (3,
6)
69. The ______ block in exception handling ALWAYS executes regardless of whether an error
occurred. (finally)
70. An anonymous single-expression function is defined using the ______ keyword. (lambda)
71. The range() function generates integers from start up to but ______ including the stop value.
(not)

You might also like