This page shows the source code for Session-2-2-Examples.py with teaching notes, PURPOSE comments, and VS Code instructions.
import sys
sys.stdout.reconfigure(encoding='utf-8')
"""
Session 2: Control Flow & Logic - Code Examples
Introduction to Python Course
"""
# ============================================
# PART 1: Conditional Statements
# ============================================
print("=" * 50)
print("PART 1: Conditional Statements")
print("=" * 50)
# ======================================================
# WHAT THIS SECTION DOES:
# 1) PURPOSE: Conditional statements let your program make
# DECISIONS. Instead of running every line top-to-bottom,
# the program checks a condition (True or False) and
# chooses which block of code to run. This is the core
# of all intelligent program behaviour.
#
# 2) VS CODE: Run each numbered Example block separately -
# select its lines and press Shift+Enter. Change the
# values (age, score, day) between runs to see how the
# output changes based on different conditions.
# ======================================================
# ------------------------------------------------------
# HOW if / elif / else WORKS
# ------------------------------------------------------
#
# STRUCTURE:
# if <condition>: <- checked first
# <code block A> <- runs if condition is True
# elif <condition2>: <- checked only if first was False
# <code block B> <- runs if condition2 is True
# else: <- catches everything remaining
# <code block C> <- runs if ALL above were False
#
# CRITICAL RULE - INDENTATION:
# Python uses spaces (indentation) to know which lines
# belong inside an if block. Every line inside MUST be
# indented by the same amount (usually 4 spaces).
#
# if age >= 18:
# print("Adult") <- indented = INSIDE the if
# print("Done") <- NOT indented = OUTSIDE the if
#
# A condition is any expression that evaluates to True/False:
# age >= 18 True if age is 18 or more
# number % 2 == 0 True if number divides evenly by 2
# name == "Alice" True if name equals "Alice"
#
# LOGICAL OPERATORS combine conditions:
# and -> BOTH sides must be True
# or -> AT LEAST ONE side must be True
# not -> flips True to False and False to True
# ------------------------------------------------------
# Example 1: Simple if statement
print("\n--- Example 1: Age Check ---")
# ======================================================
# WHAT: The simplest form - only runs the indented block
# when the condition is True. If False, nothing happens.
# TRY: Change age to 15 and run again - no output from the if.
# ======================================================
age = 20
if age >= 18:
print(f"Age {age}: You are an adult")
# Example 2: if-else statement
print("\n--- Example 2: Even or Odd ---")
# ======================================================
# WHAT: if-else covers BOTH possibilities - one branch runs
# when True, the other when False. Always one or the other.
# TRY: Change number to 8 - the "even" branch will run.
# The % operator gives the remainder: 7 % 2 = 1 (odd),
# 8 % 2 = 0 (even). If remainder is 0, it divides evenly.
# ======================================================
number = 7
if number % 2 == 0:
print(f"{number} is even")
else:
print(f"{number} is odd")
# Example 3: if-elif-else statement
print("\n--- Example 3: Grade Calculator ---")
# ======================================================
# WHAT: elif (short for "else if") lets you check multiple
# conditions in sequence. Python checks them top-to-bottom
# and runs ONLY the first one that is True, then skips
# all the rest. The else at the bottom is the fallback
# if nothing above matched.
# TRY: Change score to 92, then 65, then 45 to see each
# branch execute in turn.
# ======================================================
score = 85
if score >= 90:
grade = "A"
message = "Excellent!"
elif score >= 80: # only checked if score < 90
grade = "B"
message = "Great job!"
elif score >= 70: # only checked if score < 80
grade = "C"
message = "Good work!"
elif score >= 60: # only checked if score < 70
grade = "D"
message = "Needs improvement"
else: # catches score < 60
grade = "F"
message = "Please study more"
print(f"Score: {score}")
print(f"Grade: {grade}")
print(f"Message: {message}")
# Example 4: Logical operators - and
print("\n--- Example 4: Login Check (and operator) ---")
# ======================================================
# WHAT: 'and' requires BOTH conditions to be True.
# If either username OR password is wrong, the
# whole condition becomes False -> login fails.
# TRY: Change password to "wrong" - login will fail even
# though the username is correct.
# ======================================================
username = "admin"
password = "pass123"
if username == "admin" and password == "pass123":
print("Login successful!")
else:
print("Login failed!")
# Example 5: Logical operators - or
print("\n--- Example 5: Weekend Check (or operator) ---")
# ======================================================
# WHAT: 'or' only needs ONE condition to be True.
# Saturday OR Sunday -> either one triggers the weekend message.
# TRY: Change day to "Sunday" -> still weekend.
# Change to "Monday" -> weekday branch runs.
# ======================================================
day = "Saturday"
if day == "Saturday" or day == "Sunday":
print(f"{day}: It's the weekend!")
else:
print(f"{day}: It's a weekday")
# Example 6: Logical operators - not
print("\n--- Example 6: Weather Check (not operator) ---")
# ======================================================
# WHAT: 'not' flips a Boolean value.
# is_raining = False
# not is_raining -> not False -> True
# So the "Great day for a walk!" branch runs.
# TRY: Change is_raining to True - the 'not' flips it to
# False and the else branch runs instead.
# ======================================================
is_raining = False
if not is_raining: # not False -> True -> runs this block
print("Great day for a walk!")
else:
print("Better stay inside")
# Example 7: Complex conditions
print("\n--- Example 7: Movie Ticket Price ---")
# ======================================================
# WHAT: Combines multiple conditions and logical operators
# to model a real-world pricing rule. Notice how
# 'and' is used inside an elif to check a range:
# age >= 12 and age < 18 means "between 12 and 17".
# TRY: Change age to 10, then 15, then 30 and watch which
# price is selected each time.
# ======================================================
age = 25
is_student = True
if age < 12:
price = 5
elif age >= 12 and age < 18: # range check using and
price = 8
elif is_student: # True/False variable used directly
price = 10
else:
price = 12
print(f"Age: {age}, Student: {is_student}")
print(f"Ticket price: ${price}")
# Example 8: Nested if statements
print("\n--- Example 8: Grade with Bonus ---")
# ======================================================
# WHAT: An if inside another if - called "nested if".
# The inner if only runs when the outer if is True.
# Indentation shows the nesting level:
# if score >= 80: <- outer (4 spaces in)
# if attendance >= 90: <- inner (8 spaces in)
# ... <- inner body (12 spaces in)
# TRY: Change attendance to 75 - the outer if still passes
# (score 88 >= 80) but the inner if fails -> Grade B.
# ======================================================
score = 88
attendance = 95
if score >= 80: # outer if
if attendance >= 90: # inner if (only reached if score >= 80)
print(f"Score: {score}, Attendance: {attendance}%")
print("Grade: A (with perfect attendance bonus!)")
else:
print(f"Score: {score}, Attendance: {attendance}%")
print("Grade: B")
else:
print("Grade: C or below")
# ============================================
# PART 2: Loops - for Loop
# ============================================
print("\n" + "=" * 50)
print("PART 2: For Loops")
print("=" * 50)
# ======================================================
# WHAT THIS SECTION DOES:
# 1) PURPOSE: A for loop repeats a block of code once for
# each item in a sequence (a range of numbers, a list,
# a string, etc.). Instead of copy-pasting the same
# print line 10 times, you write it once inside a loop.
#
# 2) VS CODE: Select each Example block and press Shift+Enter.
# Pay attention to the range() arguments - changing them
# is the most important skill to practice here.
# ======================================================
# ------------------------------------------------------
# HOW for LOOPS AND range() WORK
# ------------------------------------------------------
#
# STRUCTURE:
# for <variable> in <sequence>:
# <code block> <- runs once per item
#
# range() generates a sequence of numbers:
# range(5) -> 0, 1, 2, 3, 4 (start=0, stop=5)
# range(1, 6) -> 1, 2, 3, 4, 5 (start=1, stop=6)
# range(0, 11, 2) -> 0, 2, 4, 6, 8, 10 (start, stop, step)
#
# IMPORTANT: range(stop) STOPS BEFORE the stop value.
# range(5) gives 0-4, NOT 0-5.
# range(1, 6) gives 1-5, NOT 1-6.
#
# The loop variable (i, fruit, letter) takes the value of
# each item one at a time:
# for fruit in ["apple", "banana"]:
# print(fruit) <- prints "apple", then "banana"
#
# INDENTATION applies here too: the indented block runs
# each iteration; the non-indented line after the loop
# runs only once when the loop is finished.
# ------------------------------------------------------
# Example 1: Basic for loop with range
print("\n--- Example 1: Count to 5 ---")
# ======================================================
# WHAT: range(5) produces 0,1,2,3,4 - five numbers.
# The loop runs 5 times; i holds each value in turn.
# TRY: Change range(5) to range(10) to count to 9.
# ======================================================
for i in range(5): # i = 0, then 1, then 2, then 3, then 4
print(f"Count: {i}")
# Example 2: Range with start and end
print("\n--- Example 2: Range 1 to 5 ---")
# ======================================================
# WHAT: range(1, 6) starts at 1 and stops BEFORE 6 -> 1,2,3,4,5.
# end=" " in print() puts a space instead of a newline,
# keeping all numbers on one line.
# The bare print() after the loop adds the final newline.
# ======================================================
for i in range(1, 6):
print(i, end=" ") # end=" " -> prints on same line with space
print() # moves to the next line after the loop
# Example 3: Range with step
print("\n--- Example 3: Even Numbers (step by 2) ---")
# ======================================================
# WHAT: The third argument to range() is the STEP - how much
# to add each time. range(0, 11, 2) -> 0,2,4,6,8,10.
# TRY: Change to range(1, 11, 2) to get odd numbers instead.
# ======================================================
for i in range(0, 11, 2): # step=2 -> skips every other number
print(i, end=" ")
print()
# Example 4: Loop through a list
print("\n--- Example 4: Fruits List ---")
# ======================================================
# WHAT: You can loop over any list directly - no range() needed.
# fruit takes the value of each list item one at a time:
# first "apple", then "banana", then "cherry", then "date".
# TRY: Add "elderberry" to the list and run again.
# ======================================================
fruits = ["apple", "banana", "cherry", "date"]
for fruit in fruits: # fruit = each item in the list
print(f"I like {fruit}")
# Example 5: Loop through a string
print("\n--- Example 5: Loop Through String ---")
# ======================================================
# WHAT: Strings are sequences of characters, so you can loop
# over them just like lists. Each iteration gives one letter.
# TRY: Change word to your own name and run again.
# ======================================================
word = "PYTHON"
for letter in word: # letter = "P", then "Y", then "T", ...
print(letter, end="-")
print()
# Example 6: Multiplication table
print("\n--- Example 6: Multiplication Table (5) ---")
# ======================================================
# WHAT: range(1, 11) gives 1 through 10. Inside the loop,
# the result is calculated fresh each iteration.
# This is the for-loop pattern for building a table.
# TRY: Change 5 * i to 7 * i to get the 7-times table.
# ======================================================
for i in range(1, 11):
result = 5 * i # calculated anew each loop iteration
print(f"5 x {i} = {result}")
# Example 7: Sum of numbers
print("\n--- Example 7: Sum of 1 to 10 ---")
# ======================================================
# WHAT: total starts at 0 OUTSIDE the loop. Each iteration
# adds the current i to it. This is the ACCUMULATOR pattern -
# the most common use of loops in real programs.
# total += i is shorthand for total = total + i
# ======================================================
total = 0 # accumulator - starts at 0
for i in range(1, 11):
total += i # add current i to running total
print(f"Sum of 1 to 10: {total}")
# Example 8: Counting specific items
print("\n--- Example 8: Count Even Numbers ---")
# ======================================================
# WHAT: Combines a loop with an if inside it - the if filters
# which iterations actually do something (the counter).
# This is the FILTER + COUNT pattern.
# TRY: Change the condition to i % 3 == 0 to count
# multiples of 3 between 1 and 20 instead.
# ======================================================
even_count = 0
for i in range(1, 21):
if i % 2 == 0: # filter: only count even numbers
even_count += 1
print(f"Even numbers between 1-20: {even_count}")
# ============================================
# PART 3: While Loops
# ============================================
print("\n" + "=" * 50)
print("PART 3: While Loops")
print("=" * 50)
# ======================================================
# WHAT THIS SECTION DOES:
# 1) PURPOSE: A while loop keeps repeating AS LONG AS its
# condition is True. Use while when you do NOT know in
# advance how many times to loop (e.g. "keep asking until
# the user enters a valid password"). Use for when you DO
# know the count or are iterating over a fixed sequence.
#
# 2) VS CODE: Select each Example block and press Shift+Enter.
# WARNING: if you accidentally create an infinite loop
# (condition never becomes False), press Ctrl+C in the
# terminal to stop it.
# ======================================================
# ------------------------------------------------------
# HOW while LOOPS WORK
# ------------------------------------------------------
#
# STRUCTURE:
# while <condition>:
# <code block> <- repeats as long as condition is True
#
# EXECUTION FLOW:
# 1. Check condition
# 2. If True -> run the block, then go back to step 1
# 3. If False -> exit the loop, continue with next line
#
# CRITICAL: something inside the loop MUST eventually make
# the condition False, otherwise it loops forever!
#
# count = 5
# while count > 0:
# print(count)
# count -= 1 <- THIS makes the condition eventually False
#
# COMMON MISTAKE - infinite loop (missing the update):
# count = 5
# while count > 0:
# print(count) <- count never changes -> loops forever!
# ------------------------------------------------------
# Example 1: Basic while loop
print("\n--- Example 1: Countdown ---")
# ======================================================
# WHAT: count starts at 5. Each iteration prints count,
# then count -= 1 decreases it by 1. When count
# reaches 0, "count > 0" becomes False and the loop ends.
# "Blastoff!" is outside the loop so it prints once after.
# TRY: Change count to 10 for a longer countdown.
# ======================================================
count = 5
while count > 0: # loop runs while this is True
print(f"Countdown: {count}")
count -= 1 # MUST decrease or loop runs forever!
print("Blastoff!") # outside loop - runs once after loop ends
# Example 2: User input with while loop (demo)
print("\n--- Example 2: Password Validator (demo) ---")
# ======================================================
# WHAT: This is the classic "try again" pattern. The loop
# keeps running as long as attempts > 0. When the
# correct password is entered, 'break' exits immediately.
# The 'else' on a while loop runs ONLY if the loop
# finished naturally (condition became False), NOT via break.
# HOW TO TRY: Remove the # from all lines below this comment
# block, select them, and press Shift+Enter.
# Type wrong passwords, then "secret123" to see both paths.
# ======================================================
# attempts = 3
# while attempts > 0:
# password = input(f"Enter password ({attempts} attempts left): ")
# if password == "secret123":
# print("Access granted!")
# break # exits the loop immediately
# attempts -= 1
# print("Wrong password!")
# else:
# print("Account locked!") # runs only if loop ended without break
# Example 3: Sum until negative number
print("\n--- Example 3: Sum Numbers (demo) ---")
# ======================================================
# WHAT: The while loop walks through a list using an index.
# When a negative number is found, 'break' stops the loop
# immediately - the 20 after -1 is never processed.
# index < len(numbers) is the boundary guard that also
# prevents going past the end of the list.
# ======================================================
numbers = [5, 10, 15, -1, 20]
total = 0
index = 0
print("Enter numbers (negative to stop):")
while index < len(numbers): # len(numbers) = 5, so index can be 0-4
num = numbers[index]
print(f"Number entered: {num}")
if num < 0:
break # stop immediately when negative seen
total += num
index += 1
print(f"Total sum: {total}")
# ============================================
# PART 4: Loop Control (break, continue)
# ============================================
print("\n" + "=" * 50)
print("PART 4: Break and Continue")
print("=" * 50)
# ======================================================
# WHAT THIS SECTION DOES:
# 1) PURPOSE: break and continue give you fine-grained control
# INSIDE a loop without changing the loop condition itself.
# break = "stop the loop RIGHT NOW, exit completely"
# continue = "skip the rest of THIS iteration, start the next one"
#
# 2) VS CODE: Run each Example separately. Trace through
# the output and match each printed line to the code
# to understand exactly when break/continue fires.
# ======================================================
# ------------------------------------------------------
# break vs continue - VISUAL SUMMARY
# ------------------------------------------------------
#
# break exits the ENTIRE loop:
# for i in range(5):
# if i == 3:
# break <- loop stops here
# print(i) <- prints 0, 1, 2 then stops
#
# continue skips only the CURRENT iteration:
# for i in range(5):
# if i == 3:
# continue <- skip i=3, keep going
# print(i) <- prints 0, 1, 2, 4 (3 is skipped)
#
# Both work in for loops and while loops.
# ------------------------------------------------------
# Example 1: break statement
print("\n--- Example 1: Finding a Number (break) ---")
# ======================================================
# WHAT: The loop searches for 7. When found, it prints a
# message and immediately exits with 'break'.
# Lines after the break (i=8,9,10) are never reached.
# ======================================================
for i in range(1, 11):
if i == 7:
print(f"Found {i}! Stopping search.")
break # exits loop immediately
print(f"Checking {i}...") # only reached when i != 7
# Example 2: continue statement
print("\n--- Example 2: Skip Multiples of 3 (continue) ---")
# ======================================================
# WHAT: When i is a multiple of 3 (3, 6, 9), 'continue'
# jumps straight to the next iteration - the print
# below it is skipped for those values only.
# Output: 1 2 4 5 7 8 10
# ======================================================
for i in range(1, 11):
if i % 3 == 0:
continue # skip this iteration, go to next i
print(i, end=" ") # only reached when i is NOT a multiple of 3
print()
# Example 3: break in while loop
print("\n--- Example 3: Search in List (break) ---")
# ======================================================
# WHAT: Manual list search using while + break. The 'found'
# flag is set to True before breaking so the code after
# the loop knows whether the search succeeded.
# This is the SEARCH PATTERN - common in real programs.
# ======================================================
fruits = ["apple", "banana", "cherry", "date"]
search = "cherry"
index = 0
found = False
while index < len(fruits):
if fruits[index] == search:
print(f"Found '{search}' at position {index}")
found = True
break # no need to keep searching
index += 1
if not found:
print(f"'{search}' not found")
# ============================================
# PART 5: Nested Loops
# ============================================
print("\n" + "=" * 50)
print("PART 5: Nested Loops")
print("=" * 50)
# ======================================================
# WHAT THIS SECTION DOES:
# 1) PURPOSE: A nested loop is a loop INSIDE another loop.
# The inner loop runs completely for EACH iteration of
# the outer loop. Total iterations = outer count x inner count.
# Common uses: tables, grids, 2D patterns, comparing
# every item in one list against every item in another.
#
# 2) VS CODE: Run each Example separately. Count the output
# lines and verify: outer_range x inner_range = total lines.
# ======================================================
# ------------------------------------------------------
# HOW NESTED LOOPS WORK
# ------------------------------------------------------
#
# for i in range(3): <- outer loop (runs 3 times)
# for j in range(4): <- inner loop (runs 4 times PER outer)
# print(i, j) <- runs 3 x 4 = 12 times total
# print("---") <- runs 3 times (once per outer loop)
#
# Execution order for range(2) x range(3):
# i=0, j=0 -> i=0, j=1 -> i=0, j=2
# i=1, j=0 -> i=1, j=1 -> i=1, j=2
#
# The OUTER loop variable (i) changes SLOWLY.
# The INNER loop variable (j) changes FAST.
# ------------------------------------------------------
# Example 1: Simple nested loop
print("\n--- Example 1: Nested Loop Pattern ---")
# ======================================================
# WHAT: Outer loop i goes 0,1,2. For each i, inner loop
# j goes 0,1,2,3. The print() at the end of the outer
# body (not indented inside j) moves to the next line
# after each inner loop finishes.
# ======================================================
for i in range(3): # outer: 0, 1, 2
for j in range(4): # inner: 0, 1, 2, 3 (resets each outer)
print(f"({i},{j})", end=" ")
print() # newline after each full inner loop
# Example 2: Multiplication table
print("\n--- Example 2: Multiplication Table ---")
# ======================================================
# WHAT: Classic nested loop table. i is the row, j is the
# column. end="\t" uses a tab character to line up columns.
# TRY: Change range(1, 4) to range(1, 6) for a 5x5 table.
# ======================================================
for i in range(1, 4):
for j in range(1, 4):
print(f"{i}x{j}={i*j}", end="\t") # \t = tab for alignment
print()
# Example 3: Pattern printing
print("\n--- Example 3: Star Pattern ---")
# ======================================================
# WHAT: The inner loop runs i times (not a fixed count).
# When i=1 -> 1 star, i=2 -> 2 stars, ..., i=5 -> 5 stars.
# This creates a triangle because the inner range grows
# each time the outer loop increments.
# TRY: Change range(1, 6) to range(5, 0, -1) for
# an upside-down triangle (decreasing stars).
# ======================================================
for i in range(1, 6):
for j in range(i): # inner range grows with i
print("*", end=" ")
print()
# ============================================
# PART 6: Practical Examples
# ============================================
print("\n" + "=" * 50)
print("PART 6: Practical Examples")
print("=" * 50)
# ======================================================
# WHAT THIS SECTION DOES:
# 1) PURPOSE: These three programs combine everything from
# Parts 1-5 into realistic mini-applications. Reading
# and understanding them is excellent practice for seeing
# how if/elif, for, while, break, and continue work
# together in real code.
#
# 2) VS CODE: Run each example, then try changing one value
# at a time (secret_number, number to test, password string)
# and predict the output BEFORE running to test your
# understanding of the control flow.
# ======================================================
# Example 1: Number guessing game (simulated)
print("\n--- Example 1: Number Guessing Game (Demo) ---")
# ======================================================
# WHAT: for loop with break + elif chain. The 'else' on
# the for loop only runs if the loop finished WITHOUT
# a break (i.e. all guesses were wrong). This is
# Python's unique "for...else" pattern.
# TRY: Change guesses = [5, 8, 7] to [1, 2, 3] to trigger
# the "Game over!" else branch.
# ======================================================
secret_number = 7
guesses = [5, 8, 7]
max_attempts = 3
for attempt in range(1, max_attempts + 1):
guess = guesses[attempt - 1]
print(f"Attempt {attempt}: You guessed {guess}")
if guess == secret_number:
print(f"Correct! You won in {attempt} attempts!")
break # exit loop on correct guess
elif guess < secret_number:
print("Too low!")
else:
print("Too high!")
else:
# 'else' on for loop: runs ONLY if loop ended without break
print(f"Game over! The number was {secret_number}")
# Example 2: Prime number checker
print("\n--- Example 2: Prime Number Checker ---")
# ======================================================
# WHAT: A prime has no divisors except 1 and itself.
# We only need to check up to the square root of number
# (int(number ** 0.5) + 1) - a math shortcut that avoids
# unnecessary checks. If ANY divisor is found, we set
# is_prime = False and break immediately.
# TRY: Change number to 15 (not prime) then 19 (prime).
# ======================================================
number = 17
is_prime = True
if number < 2:
is_prime = False
else:
for i in range(2, int(number ** 0.5) + 1): # only check up to sqrt
if number % i == 0:
is_prime = False
break # no need to check further
if is_prime:
print(f"{number} is a prime number")
else:
print(f"{number} is not a prime number")
# Example 3: Password strength checker
print("\n--- Example 3: Password Strength Checker ---")
# ======================================================
# WHAT: Loops over each character in the password string
# and uses built-in string methods to classify it:
# char.isdigit() -> True if character is 0-9
# char.isupper() -> True if character is A-Z
# char.islower() -> True if character is a-z
# Three boolean flags are set to True as soon as their
# character type is found. Then the strength is determined
# by combining the flags with 'and'/'or' logic.
# TRY: Change password to "hello" (weak), "Hello1" (medium),
# "SecurePass99" (strong) to test all three branches.
# ======================================================
password = "MyPass123"
has_digit = False
has_upper = False
has_lower = False
for char in password: # check each character one by one
if char.isdigit():
has_digit = True # found at least one digit
elif char.isupper():
has_upper = True # found at least one uppercase letter
elif char.islower():
has_lower = True # found at least one lowercase letter
strength = "Weak"
if len(password) >= 8 and has_digit and has_upper and has_lower:
strength = "Strong"
elif len(password) >= 6 and (has_digit or has_upper):
strength = "Medium"
print(f"Password: {password}")
print(f"Length: {len(password)}")
print(f"Strength: {strength}")
print("\nSession 2 completed successfully!")
print("Practice these control flow concepts!")