1. FACTORIAL FUNCTION USING RECURSION
The Code:
def factorial(n): if n == 0 or n == 1: return 1 else: return n * factorial(n - 1) print(factorial(5))
Line-by-Line Explanation:
Line 1: def factorial(n):
def- Keyword to DEFINE a new functionfactorial- Name of the function (describes what it does)(n)- Parameter - the function expects one input value calledn:- Colon indicates the function body starts on next linePurpose: Creates a reusable block of code that calculates factorials
What is a Factorial?
Factorial of a number (written as
n!) is the product of all positive integers less than or equal to nExamples:
5! = 5 Γ 4 Γ 3 Γ 2 Γ 1 = 1204! = 4 Γ 3 Γ 2 Γ 1 = 243! = 3 Γ 2 Γ 1 = 62! = 2 Γ 1 = 21! = 10! = 1(by definition)
Line 2: if n == 0 or n == 1:
Checks if
nis equal to 0 OR equal to 1oroperator - if either condition is True, the whole condition is TrueThis is called the BASE CASE - the condition that stops the recursion
Line 3: return 1
Returns the value 1 when n is 0 or 1
This ends the recursive calls for these values
Line 4: else:
If n is NOT 0 or 1 (meaning n >= 2), execute this block
Line 5: return n * factorial(n - 1)
This is the RECURSIVE CASE
Returns
nmultiplied by the factorial of(n-1)The function calls ITSELF with a smaller number
Line 6: print(factorial(5))
Calls the factorial function with argument 5
Prints the result (120)
How Recursion Works - Step by Step Execution:
When we call factorial(5), here's what happens:
Step 1: factorial(5) is called
β
5 == 0 or 5 == 1? NO
β
return 5 * factorial(4) β WAITS for factorial(4) to complete
Step 2: factorial(4) is called
β
4 == 0 or 4 == 1? NO
β
return 4 * factorial(3) β WAITS for factorial(3) to complete
Step 3: factorial(3) is called
β
3 == 0 or 3 == 1? NO
β
return 3 * factorial(2) β WAITS for factorial(2) to complete
Step 4: factorial(2) is called
β
2 == 0 or 2 == 1? NO
β
return 2 * factorial(1) β WAITS for factorial(1) to complete
Step 5: factorial(1) is called
β
1 == 0 or 1 == 1? YES (1 == 1 is True)
β
return 1 β BASE CASE REACHED! Now we unwind...
Step 6: Back to factorial(2): 2 * factorial(1) = 2 * 1 = 2
β returns 2
Step 7: Back to factorial(3): 3 * factorial(2) = 3 * 2 = 6
β returns 6
Step 8: Back to factorial(4): 4 * factorial(3) = 4 * 6 = 24
β returns 24
Step 9: Back to factorial(5): 5 * factorial(4) = 5 * 24 = 120
β returns 120
Final result: 120Visual Representation of Recursion:
factorial(5) = 5 Γ factorial(4)
β
factorial(4) = 4 Γ factorial(3)
β
factorial(3) = 3 Γ factorial(2)
β
factorial(2) = 2 Γ factorial(1)
β
factorial(1) = 1
β
= 2 Γ 1 = 2
= 3 Γ 2 = 6
= 4 Γ 6 = 24
= 5 Γ 24 = 120The Stack (How Python Remembers):
Python uses a "call stack" to keep track of recursive calls:
| Stack Level | Function Call | Waiting For | Returns |
|---|---|---|---|
| 1 | factorial(5) | factorial(4) | 120 |
| 2 | factorial(4) | factorial(3) | 24 |
| 3 | factorial(3) | factorial(2) | 6 |
| 4 | factorial(2) | factorial(1) | 2 |
| 5 | factorial(1) | (base case) | 1 |
Alternative: Iterative Factorial (Non-Recursive)
def factorial_iterative(n): result = 1 for i in range(1, n + 1): result *= i # Same as: result = result * i return result print(factorial_iterative(5)) # Also prints 120
Comparison: Recursion vs Iteration
| Aspect | Recursion | Iteration (Loop) |
|---|---|---|
| Code Length | Shorter, cleaner | Slightly longer |
| Readability | Very readable for mathematical definitions | Easy to understand |
| Memory Usage | Uses more (call stack) | Uses less |
| Speed | Slower (function call overhead) | Faster |
| Risk | Stack overflow for large n | No stack issues |
Testing Different Values:
print(factorial(0)) # 1 (by definition) print(factorial(1)) # 1 print(factorial(2)) # 2 print(factorial(3)) # 6 print(factorial(4)) # 24 print(factorial(5)) # 120 print(factorial(6)) # 720 print(factorial(7)) # 5040
2. LAMBDA FUNCTION TO FILTER EVEN NUMBERS
The Code:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] even_numbers = list(filter(lambda x: x % 2 == 0, numbers)) print(even_numbers)
Line-by-Line Explanation:
Line 1: numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Creates a list variable called
numbersContains integers from 1 to 10
Lists are ordered, changeable collections using square brackets
[]
Line 2: even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
Let's break this complex line into parts:
Part A: lambda x: x % 2 == 0
lambda- Creates an anonymous (unnamed) functionx- Parameter (input to the function):- Separates parameters from the expressionx % 2 == 0- The function body (returns True if x is even)This is EQUIVALENT to:
def is_even(x): return x % 2 == 0
Part B: filter(lambda x: x % 2 == 0, numbers)
filter()- Built-in function that filters a sequenceTakes two arguments:
A function that returns True/False (the lambda)
An iterable to filter (the numbers list)
filter()returns ONLY items where the function returns TrueReturns a filter object (not a list yet)
Part C: list(filter(...))
list()- Converts the filter object to a listWithout this, you'd see something like
<filter object at 0x...>
Line 3: print(even_numbers)
Displays the filtered list
How Filter Works - Step by Step:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Check each number: 1 β 1 % 2 == 0? 1 % 2 = 1 β False β NOT included 2 β 2 % 2 == 0? 2 % 2 = 0 β True β included β 3 β 3 % 2 == 0? 3 % 2 = 1 β False β NOT included 4 β 4 % 2 == 0? 4 % 2 = 0 β True β included β 5 β 5 % 2 == 0? 5 % 2 = 1 β False β NOT included 6 β 6 % 2 == 0? 6 % 2 = 0 β True β included β 7 β 7 % 2 == 0? 7 % 2 = 1 β False β NOT included 8 β 8 % 2 == 0? 8 % 2 = 0 β True β included β 9 β 9 % 2 == 0? 9 % 2 = 1 β False β NOT included 10 β 10 % 2 == 0? 10 % 2 = 0 β True β included β Result: [2, 4, 6, 8, 10]
Output:
[2, 4, 6, 8, 10]
What is Lambda? Detailed Explanation:
Lambda functions are small, anonymous functions that:
Can have any number of parameters, but only ONE expression
Cannot contain statements or multiple lines
Automatically return the expression result
Syntax: lambda parameters: expression
Examples:
# Regular function def square(x): return x ** 2 # Lambda equivalent square_lambda = lambda x: x ** 2 print(square(5)) # 25 print(square_lambda(5)) # 25
More Lambda Examples:
# Add two numbers add = lambda a, b: a + b print(add(5, 3)) # 8 # Check if number is positive is_positive = lambda x: x > 0 print(is_positive(5)) # True print(is_positive(-2)) # False # Get length of string get_length = lambda s: len(s) print(get_length("hello")) # 5 # Multiple operations (but only one expression) # This works but is hard to read: complex_lambda = lambda x: x * 2 if x > 10 else x + 5
Alternative Ways to Filter Even Numbers:
# Method 1: List comprehension (most Pythonic) even_numbers = [x for x in numbers if x % 2 == 0] print(even_numbers) # [2, 4, 6, 8, 10] # Method 2: Regular function with filter def is_even(x): return x % 2 == 0 even_numbers = list(filter(is_even, numbers)) print(even_numbers) # [2, 4, 6, 8, 10] # Method 3: For loop even_numbers = [] for x in numbers: if x % 2 == 0: even_numbers.append(x) print(even_numbers) # [2, 4, 6, 8, 10]
Filter with Other Conditions:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # Filter numbers greater than 5 greater_than_5 = list(filter(lambda x: x > 5, numbers)) print(greater_than_5) # [6, 7, 8, 9, 10] # Filter numbers divisible by 3 divisible_by_3 = list(filter(lambda x: x % 3 == 0, numbers)) print(divisible_by_3) # [3, 6, 9] # Filter numbers between 3 and 7 between_3_and_7 = list(filter(lambda x: 3 <= x <= 7, numbers)) print(between_3_and_7) # [3, 4, 5, 6, 7]
3. BASIC CALCULATOR WITH ADD/SUB/MUL FUNCTIONS
The Code:
def add(x, y): return x + y def sub(x, y): return x - y def mul(x, y): return x * y print(add(5, 3)) print(sub(5, 3)) print(mul(5, 3))
Line-by-Line Explanation:
Lines 1-2: def add(x, y): return x + y
Defines a function named
addTakes two parameters:
xandyreturn x + y- Adds the two numbers and returns the resultThis is a one-line function (no indentation needed if on same line)
Lines 4-5: def sub(x, y): return x - y
Defines a function named
subSubtracts
yfromxand returns the result
Lines 7-8: def mul(x, y): return x * y
Defines a function named
mulMultiplies
xandyand returns the result
Lines 10-12: The function calls
print(add(5, 3))- Calls add with 5 and 3, prints resultprint(sub(5, 3))- Calls sub with 5 and 3, prints resultprint(mul(5, 3))- Calls mul with 5 and 3, prints result
Output:
8 2 15
How Each Function Works:
# ADD function add(5, 3) β x = 5, y = 3 β return 5 + 3 β return 8 β print(8) # Output: 8 # SUBTRACT function sub(5, 3) β x = 5, y = 3 β return 5 - 3 β return 2 β print(2) # Output: 2 # MULTIPLY function mul(5, 3) β x = 5, y = 3 β return 5 * 3 β return 15 β print(15) # Output: 15
Expanded Calculator with More Features:
# Complete Calculator with all operations def add(x, y): """Returns the sum of x and y""" return x + y def subtract(x, y): """Returns the difference of x and y""" return x - y def multiply(x, y): """Returns the product of x and y""" return x * y def divide(x, y): """Returns the quotient of x divided by y""" if y == 0: return "Error: Cannot divide by zero!" return x / y def power(x, y): """Returns x raised to the power y""" return x ** y def modulus(x, y): """Returns the remainder when x is divided by y""" return x % y # Using the calculator print("Calculator Demo:") print(f"5 + 3 = {add(5, 3)}") print(f"5 - 3 = {subtract(5, 3)}") print(f"5 Γ 3 = {multiply(5, 3)}") print(f"5 Γ· 3 = {divide(5, 3):.2f}") print(f"5Β² = {power(5, 2)}") print(f"5 % 3 = {modulus(5, 3)}")
Interactive Calculator Version:
def calculator(): print("=" * 40) print(" SIMPLE CALCULATOR") print("=" * 40) print("Operations:") print("1. Add (+)") print("2. Subtract (-)") print("3. Multiply (Γ)") print("4. Divide (Γ·)") print("5. Power (^)") try: # Get user input choice = input("\nChoose operation (1-5): ") num1 = float(input("Enter first number: ")) num2 = float(input("Enter second number: ")) # Perform calculation based on choice if choice == '1': result = num1 + num2 operation = "+" elif choice == '2': result = num1 - num2 operation = "-" elif choice == '3': result = num1 * num2 operation = "Γ" elif choice == '4': if num2 == 0: print("Error: Cannot divide by zero!") return result = num1 / num2 operation = "Γ·" elif choice == '5': result = num1 ** num2 operation = "^" else: print("Invalid choice!") return print(f"\n{num1} {operation} {num2} = {result}") except ValueError: print("Error: Please enter valid numbers!") # Run the interactive calculator calculator()
Function Reusability Demonstration:
# Once defined, functions can be used many times print(add(10, 20)) # 30 print(add(100, 200)) # 300 print(add(5, 7)) # 12 print(sub(100, 30)) # 70 print(sub(50, 15)) # 35 print(mul(6, 7)) # 42 print(mul(10, 10)) # 100 # You can also store results in variables result = add(15, 25) print(f"Stored result: {result}") # Stored result: 40 # Use results in other calculations total = add(10, multiply(5, 3)) # 10 + (5 Γ 3) = 10 + 15 = 25 print(total) # 25
Why Use Functions? Benefits Explained:
| Benefit | Explanation | Example |
|---|---|---|
| Reusability | Write once, use many times | add(5,3) can be called anywhere |
| Modularity | Break complex problems into smaller pieces | Calculator has separate functions for each operation |
| Readability | Code is easier to understand | calculate_total() is clearer than long math formulas |
| Testing | Can test each function independently | Test add() separately from multiply() |
| Maintenance | Fix bugs in one place | Update divide() function once to fix all division |
COMPARISON TABLE: ALL THREE PROGRAMS
| Feature | Factorial Function | Lambda Filter | Calculator Functions |
|---|---|---|---|
| Purpose | Calculate n! | Filter even numbers | Perform math operations |
| Key Concept | Recursion | Lambda & Filter | Function definition |
| Input | Single number (n) | List of numbers | Two numbers (x, y) |
| Output | Single number | List of evens | Single number |
| Complexity | O(n) recursive | O(n) linear | O(1) constant |
| Best For | Learning recursion | Learning functional programming | Learning modular design |
COMMON MISTAKES AND SOLUTIONS
Factorial Function:
# MISTAKE 1: No base case (infinite recursion) def factorial(n): return n * factorial(n - 1) # Never stops! Causes RecursionError # MISTAKE 2: Wrong base case condition def factorial(n): if n == 0: return 0 # Wrong! Should return 1 return n * factorial(n - 1) # MISTAKE 3: Forgetting to convert input to int n = input("Enter number: ") # This is a string! print(factorial(n)) # Error: can't multiply string by int
Lambda/Filter:
# MISTAKE 1: Forgetting to convert filter object to list even = filter(lambda x: x % 2 == 0, numbers) print(even) # Prints <filter object at 0x...> not the list! # FIX: even = list(filter(lambda x: x % 2 == 0, numbers)) # MISTAKE 2: Using statements in lambda (not allowed) lambda x: if x > 0: return x # Syntax error! # FIX: Use regular function or conditional expression lambda x: x if x > 0 else 0
Calculator Functions:
# MISTAKE 1: No return statement def add(x, y): x + y # Nothing returned! Returns None # FIX: Add return def add(x, y): return x + y # MISTAKE 2: Wrong parameter order def subtract(x, y): return x - y result = subtract(3, 5) # Returns -2, not 2!
PRACTICE EXERCISES
Try these modifications on your own:
For Factorial:
Create a function that calculates factorial using a loop instead of recursion
Add error handling for negative numbers
Calculate factorial of numbers from 1 to 10 using a loop
For Lambda/Filter:
Filter numbers that are odd
Filter numbers greater than 5
Use filter with a list of strings to find words longer than 3 characters
For Calculator:
Add division function
Create a function that does all operations and returns results in a dictionary
Build a menu-driven calculator that keeps running until user chooses to exit
QUICK REFERENCE CARD
# RECURSION PATTERN def recursive_function(parameter): if base_condition: # When to stop return base_value else: return operation(parameter, recursive_function(parameter - 1)) # LAMBDA PATTERN lambda parameters: expression # FILTER PATTERN filtered_list = list(filter(lambda x: condition, original_list)) # FUNCTION PATTERN def function_name(param1, param2): """Optional docstring""" # Function body return result # FUNCTION CALL PATTERN result = function_name(argument1, argument2)
This comprehensive explanation covers all three of your programs in detail. Each concept builds on the previous ones, helping you understand both the individual pieces and how they work together in Python programming!View previous lecture
Discussion (0)