Programming with PythonUnit 49 min read
Functions, Modules, Recursion & Scope in Python
Unit 4 of Programming with Python covers how to define, call, and reuse functions; organize code into modules; handle scope rules; and implement recursion. Learn parameter passing, lambda functions, and Python’s import system with real-world examples from Nepalese apps like eSewa and Daraz.
TAKEAWAYS
- Functions let you group reusable code with parameters and return values, reducing redundancy.
- Scope rules (LEGB) determine where variables are accessible: Local → Enclosing → Global → Built-in.
- Modules help organize code into files (
.py) and avoid naming conflicts viaimportstatements. - Recursion solves problems by breaking them into smaller subproblems (e.g., factorial, Fibonacci).
- Lambda functions create anonymous functions for short, one-time operations (e.g., sorting keys).
- Parameter passing in Python is pass-by-object-reference: mutable objects (lists) can be modified inside functions.
1. Functions: Definition, Calling, and Scope
1.1 What is a Function?
A function is a reusable block of code that performs a specific task. It:
- Takes inputs (parameters/arguments).
- Executes statements.
- Returns an output (optional).
def greet(name): # 'name' is a parameter
return f"Hello, {name}!"
print(greet("Rohan")) # 'Rohan' is an argument
Output:
Hello, Rohan!
1.2 Types of Functions
| Type | Example | Key Feature |
|---|---|---|
| Built-in | len(), print(), max() |
Predefined in Python |
| User-defined | def add(a, b): return a + b |
Created by the programmer |
| Lambda (Anonymous) | lambda x: x**2 |
Short, one-line functions |
1.3 Scope Rules (LEGB)
Variables are accessed in this order:
- Local (inside the function)
- Enclosing (in nested functions)
- Global (module-level)
- Built-in (Python’s default, e.g.,
print)
x = 10 # Global
def outer():
x = 20 # Enclosing
def inner():
x = 30 # Local
print(x) # 30 (Local)
inner()
print(x) # 20 (Enclosing)
outer()
print(x) # 10 (Global)
Output:
30
20
10
1.4 Parameter Passing
Python uses pass-by-object-reference:
- Immutable objects (e.g.,
int,str,tuple) → copied (changes inside function don’t affect original). - Mutable objects (e.g.,
list,dict) → reference passed (changes persist).
def modify_list(lst):
lst.append(4) # Modifies the original list
my_list = [1, 2, 3]
modify_list(my_list)
print(my_list) # Output: [1, 2, 3, 4]
2. Modules: Organizing Code
2.1 Why Use Modules?
- Reusability: Share code across programs.
- Avoid naming conflicts: Use
import module_name. - Modularity: Split large programs into manageable files.
2.2 Importing Modules
# Import entire module
import math
print(math.sqrt(16)) # 4.0
# Import specific functions
from math import pi, sin
print(sin(pi/2)) # 1.0
# Import with alias
import numpy as np
print(np.array([1, 2, 3]))
2.3 Creating Your Own Module
- Save code in a file (e.g.,
mymath.py):def add(a, b): return a + b - Import it:
import mymath print(mymath.add(5, 3)) # 8
2.4 __name__ and if __name__ == "__main__":
__name__is"__main__"when the script runs directly.- Useful for conditional execution (e.g., run tests only when the file is executed, not imported).
def hello():
print("Hello!")
if __name__ == "__main__":
hello() # Runs only when executed directly
3. Recursion
flowchart TD
A["factorial(4)"] --> B["4 × factorial(3)"]
B --> C["factorial(3)"] --> D["3 × factorial(2)"]
D --> E["factorial(2)"] --> F["2 × factorial(1)"]
F --> G["factorial(1)"] --> H["1 × factorial(0)"]
H --> I["factorial(0)"] --> J["1 (base case)"]Call stack for factorial(4) (3.2)
3.1 What is Recursion?
A function calls itself to solve smaller instances of the same problem. Base case: Stops recursion (prevents infinite loops). Recursive case: Breaks the problem into smaller subproblems.
3.2 Example: Factorial
def factorial(n):
if n == 0: # Base case
return 1
else:
return n * factorial(n - 1) # Recursive case
print(factorial(4)) # 24
Trace:
| Call Stack | n |
Return Value |
|---|---|---|
factorial(4) |
4 | 4 × factorial(3) |
factorial(3) |
3 | 3 × factorial(2) |
factorial(2) |
2 | 2 × factorial(1) |
factorial(1) |
1 | 1 × factorial(0) |
factorial(0) |
0 | 1 (base case) |
Output: 4 × 3 × 2 × 1 × 1 = 24
3.3 Real-World Example: Fibonacci Sequence
Problem: Calculate the 6th Fibonacci number (0, 1, 1, 2, 3, 5, 8, ...). Solution:
def fib(n):
if n <= 1:
return n
else:
return fib(n - 1) + fib(n - 2)
print(fib(6)) # 8
Trace:
fib(6) → fib(5) + fib(4)
fib(5) → fib(4) + fib(3)
fib(4) → fib(3) + fib(2)
fib(3) → fib(2) + fib(1)
fib(2) → fib(1) + fib(0) → 1 + 0 = 1
fib(1) → 1
fib(0) → 0
Output: 8
4. Lambda Functions
4.1 Syntax
lambda arguments: expression
- No
returnstatement (expression is returned automatically). - Used for short, one-time functions (e.g., sorting).
4.2 Example: Sorting with Lambda
students = [("Rohan", 20), ("Sita", 22), ("Ram", 19)]
# Sort by age (second element in tuple)
sorted_students = sorted(students, key=lambda x: x[1])
print(sorted_students)
Output:
[('Ram', 19), ('Rohan', 20), ('Sita', 22)]
4.3 Real-World Example: eSewa Transaction Fees
eSewa calculates fees dynamically. A lambda function could compute a 1% fee for transactions:
fee = lambda amount: amount * 0.01
print(fee(1000)) # 10.0
5. Exam Tip
Function Definition vs. Call:
def func(a, b):→ definition.func(1, 2)→ call.- Common mistake: Forgetting
returnor using=instead of==in conditions.
Scope Pitfalls:
- Global variables inside functions must be declared with
global. - Local variables shadow globals if names clash.
- Global variables inside functions must be declared with
Recursion Questions:
- Always identify the base case and recursive case.
- Draw the call stack (like the factorial trace above).
Modules:
- Know how to import (
import,from ... import,as). - Understand
__name__for conditional execution.
- Know how to import (
Lambda Tricks:
- Useful in
sorted(),map(),filter(). - Example:
list(map(lambda x: x*2, [1, 2, 3]))→[2, 4, 6].
- Useful in
In the Real World
eSewa (Nepal):
- Uses modules to separate payment logic, user authentication, and transaction history.
- Lambda functions might calculate dynamic fees (e.g.,
fee = lambda amount: amount * (1 + tax_rate)).
Daraz Order Processing:
- Queues (FIFO) manage orders, but functions handle each order’s status (e.g.,
update_order_status(order_id, "shipped")). - Recursion could traverse product categories in a nested structure (e.g., electronics → mobile → Samsung).
- Queues (FIFO) manage orders, but functions handle each order’s status (e.g.,
Ncell Billing System:
- Modules separate customer data, billing calculations, and report generation.
- Lambda functions compute discounts (e.g.,
discount = lambda plan: plan.discount_rate * plan.amount).
Bank Loan Interest (Nepalese Banks):
- Recursive functions calculate compound interest:
def compound_interest(principal, rate, years): if years == 0: return principal else: return (principal * (1 + rate)) * compound_interest(principal, rate, years - 1) - Modules organize loan types (home, car, personal) in separate files.
- Recursive functions calculate compound interest:
flowchart TD
A["Function Call\n`greet('Rohan')`"] --> B["Local Scope\n`name = 'Rohan'`"]
A --> C["Global Scope\n`x = 10`"]
B --> D["Return\n'Hello, Rohan!'"]
C --> E["Unchanged\n`x` still 10"]flowchart TD
A["Recursive Function\n`fib(6)`"] --> B["fib(5) + fib(4)"]
B --> C["fib(4) + fib(3)"]
C --> D["fib(3) + fib(2)"]
D --> E["fib(2) + fib(1)"]
E --> F["fib(1) + fib(0)"]
F --> G["Base Case\nfib(0) = 0"]
F --> H["Base Case\nfib(1) = 1"]
G --> I["Returns 1"]
H --> IIn the real world
- eSewa Transaction Processing: Uses recursion in backend systems to validate nested transaction hierarchies (e.g., splitting bulk payments into individual merchant accounts).
- Daraz Order Fulfillment: Employs modules to separate inventory management (e.g.,
inventory.py), order processing (e.g.,orders.py), and shipping logic (e.g.,shipping.py), avoiding naming conflicts via imports. - Ncell Billing System: Applies lambda functions to dynamically calculate variable taxes/fees (e.g.,
fee = lambda amount, tax_rate: amount * (1 + tax_rate)) for different user tiers.
Based on the TU BIM syllabus for Programming with Python (IT243), unit 4.
Discussion
Loading…