Functions
Defining and calling functions, parameters vs arguments, return values, default/positional/keyword arguments, *args and **kwargs, variable scope, lambdas, recursion, and the map/filter/reduce higher-order functions.
As programs grow, repeating the same block of code in multiple places becomes messy and hard to maintain. Functions let you package logic into a reusable, named block — write it once, use it as many times as you need.
1. What is a Function?
What is it?
A function is a named, reusable block of code that performs a specific task. You define it once and can "call" (run) it as many times as needed, from anywhere in your program.
Definition: A function is a reusable block of code designed to perform a specific task.
Why do we use it?
- Avoid repetition — write logic once, reuse it everywhere.
- Organize code — break a large program into smaller, understandable pieces.
- Easier debugging — if something goes wrong, you know exactly which function to check.
- Reusability across projects — well-written functions can be reused in other programs entirely.
How does it work?
You define a function using the def keyword, giving it a name and (optionally) inputs it needs. Later, you call the function by its name to actually run the code inside it.
Syntax
pythondef function_name(parameters): # code to run return value # optional
Simple Example
pythondef greet(): print("Hello! Welcome to Python.") greet() # calling the function greet() # can be called as many times as needed
Output:
Hello! Welcome to Python.
Hello! Welcome to Python.Explanation of the Code
def greet():defines a function namedgreetthat takes no inputs.- The indented block is the function's body — the code that runs each time it's called.
greet()(with parentheses) is what actually executes it. Just writinggreetwithout parentheses refers to the function itself, not a call to it.
Real-World Example
In a large application, a function like send_welcome_email(user) might be called every time a new user signs up — instead of rewriting the email logic at every signup point in the code.
Common Mistakes
- Forgetting the parentheses when calling a function:
greetvsgreet()— only the second one actually runs the code. - Forgetting the colon
:after the function definition line. - Incorrect indentation of the function body.
Important Points
- Function names follow the same rules as variable names (snakecase is the Python convention: `calculatetotal
, notCalculateTotal`). - A function must be defined before it is called in the code.
Practice
- Write a function
say_hello()that prints a greeting message, and call it 3 times.
2. Parameters and Arguments
What is it?
- A parameter is the name listed in the function's definition — a placeholder for a value the function expects.
- An argument is the actual value you pass in when calling the function.
Simple Example
pythondef greet(name): # "name" is a parameter print(f"Hello, {name}!") greet("Aditi") # "Aditi" is the argument greet("Rohan")
Output:
Hello, Aditi!
Hello, Rohan!Explanation
nameis just a placeholder in the definition — it has no value until the function is actually called.- Each call supplies a different argument, so the same function produces different, personalized output.
Common Mistakes
- Calling a function without the required arguments:
greet()→TypeError: greet() missing 1 required positional argument: 'name'. - Using the words "parameter" and "argument" interchangeably in interviews — knowing the distinction is a common interview question.
Important Points
- Parameters are defined; arguments are supplied at call time.
- A function can have zero, one, or many parameters.
3. Return Values
What is it?
return sends a value back from the function to wherever it was called, so that value can be stored or used further.
Simple Example
pythondef add(a, b): return a + b result = add(5, 3) print(result) # 8
Explanation
- Unlike
print(), which just displays something,returnactually gives the value back to the caller so it can be stored in a variable (result) and used elsewhere in the program. - Once
returnruns, the function stops immediately — any code afterreturninside the function does not execute.
Common Mistakes
- Confusing
print()(just displays a value) withreturn(actually sends a value back for further use). - Forgetting a function without an explicit
returnreturnsNoneby default.
pythondef add_no_return(a, b): print(a + b) # only displays, doesn't return anything result = add_no_return(3, 4) # prints "7" print(result) # None (nothing was returned!)
Important Points
- A function can return any type: a number, string, list, dictionary, even another function.
returnimmediately exits the function.- No
returnstatement means the function returnsNone.
Practice
- Write a function
square(n)that returns the square of a number, and print the result for 3 different numbers.
4. Default Arguments
What is it?
A default argument provides a fallback value for a parameter, used only if the caller doesn't supply one.
Simple Example
pythondef greet(name="Guest"): print(f"Hello, {name}!") greet() # Hello, Guest! greet("Aditi") # Hello, Aditi!
Common Mistakes
- Placing a default parameter before a non-default one:
def greet(name="Guest", age):→SyntaxError. Default parameters must come after all non-default ones. - Using a mutable default value (like a list), which can cause unexpected shared behavior across calls (an advanced gotcha worth knowing).
Important Points
- Default arguments make functions more flexible without requiring every caller to supply every value.
- All non-default parameters must appear before any default parameters in the function definition.
5. Positional vs Keyword Arguments
What is it?
- Positional arguments are matched to parameters based on their order.
- Keyword arguments are matched by explicitly naming the parameter, regardless of order.
Simple Example
pythondef describe_student(name, age, course): print(f"{name} is {age} years old, studying {course}") # Positional — order matters describe_student("Aditi", 21, "Computer Science") # Keyword — order doesn't matter describe_student(course="Computer Science", name="Aditi", age=21)
Both calls produce the same output:
Aditi is 21 years old, studying Computer ScienceCommon Mistakes
- Mixing positional and keyword arguments incorrectly — positional arguments must always come before keyword arguments in a call:
describe_student(name="Aditi", 21, "CS")→SyntaxError.
Important Points
- Keyword arguments improve readability, especially when a function has many parameters.
- Positional arguments are simpler but require you to remember the exact order.
Practice
- Write a function with 3 parameters and call it once using positional arguments and once using keyword arguments.
6. *args and **kwargs
What is it?
*argslets a function accept any number of positional arguments, collected into a tuple.**kwargslets a function accept any number of keyword arguments, collected into a dictionary.
Simple Example — *args
pythondef add_all(*numbers): return sum(numbers) print(add_all(1, 2, 3)) # 6 print(add_all(10, 20, 30, 40)) # 100
Explanation: *numbers gathers however many arguments are passed into a single tuple, e.g. (1, 2, 3), which sum() then adds together.
Simple Example — **kwargs
pythondef print_profile(**details): for key, value in details.items(): print(f"{key}: {value}") print_profile(name="Aditi", age=21, course="CS")
Output:
name: Aditi
age: 21
course: CSExplanation: **details gathers all keyword arguments into a dictionary, so any number of named values can be passed flexibly.
Real-World Example
Functions like Python's own print() accept a flexible number of arguments — this is exactly the kind of flexibility *args and **kwargs provide in your own functions.
Common Mistakes
- Confusing the order of parameters — the correct order in a function definition is: normal parameters, then
*args, then default parameters, then**kwargs. - Trying to access
*argslike a dictionary or**kwargslike a tuple — remember:argsis a tuple,kwargsis a dictionary.
Important Points
- The names
argsandkwargsare just convention — the*and**are what matter, not the exact names. *args→ tuple of positional arguments.**kwargs→ dictionary of keyword arguments.
Practice
- Write a function using
*argsthat returns the maximum of any number of arguments passed in. - Write a function using
**kwargsthat prints a formatted "profile card" from any number of named details.
7. Variable Scope
What is it?
Scope determines where in your program a variable can be accessed.
- Local scope — a variable defined inside a function; only accessible within that function.
- Global scope — a variable defined outside any function; accessible everywhere (including inside functions, for reading).
Simple Example
pythonx = 10 # global variable def show_value(): y = 5 # local variable, only exists inside this function print(x, y) # can read global x, and its own local y show_value() print(x) # 10 — works, x is global print(y) # NameError! y only exists inside show_value()
Modifying a Global Variable Inside a Function
pythoncount = 0 def increment(): global count count += 1 increment() increment() print(count) # 2
Explanation: Without the global keyword, Python would treat count += 1 as creating a brand-new local variable inside the function, causing an error (since it's used before being assigned locally). global count tells Python to modify the actual global variable instead.
Common Mistakes
- Trying to modify a global variable inside a function without using the
globalkeyword, resulting in anUnboundLocalError. - Assuming a variable defined inside a function is accessible outside it — it isn't.
Important Points
- Local variables only exist while their function is running.
- Use the
globalkeyword only when you genuinely need to modify a global variable from inside a function — overusing globals is generally considered poor practice.
Practice
- Create a global variable
total = 0and write a function that adds a number to it using theglobalkeyword.
8. Lambda Functions
What is it?
A lambda is a small, anonymous (unnamed) function, written in a single line — used for short, simple operations, often passed directly into another function.
Syntax
pythonlambda arguments: expression
Simple Example
pythonsquare = lambda x: x ** 2 print(square(5)) # 25 add = lambda a, b: a + b print(add(3, 4)) # 7
Explanation
lambda x: x ** 2is exactly equivalent to writing:
pythondef square(x): return x ** 2
just in a shorter, single-line form.
Real-World Example
Lambdas are commonly used as a quick "key function" when sorting:
pythonstudents = [("Aditi", 85), ("Rohan", 92), ("Zara", 78)] students.sort(key=lambda student: student[1]) print(students)
Output:
[('Zara', 78), ('Aditi', 85), ('Rohan', 92)]Common Mistakes
- Trying to write multi-line logic inside a lambda — lambdas can only contain a single expression, not full statements or multiple lines.
- Overusing lambdas for complex logic, which hurts readability — use a regular
deffunction when the logic is more than a simple one-liner.
Important Points
- Lambdas have no name (unless assigned to a variable) and no
returnkeyword — the expression's result is automatically returned. - Best used for short, throwaway functions, especially with
sort(),map(), andfilter().
Practice
- Write a lambda function that returns whether a number is even.
- Use a lambda to sort a list of words by their length.
9. Recursion
What is it?
Recursion is when a function calls itself to solve a smaller version of the same problem, until it reaches a simple "base case" that stops the recursion.
Simple Example — Factorial
pythondef factorial(n): if n == 0 or n == 1: # base case return 1 return n * factorial(n - 1) # recursive case print(factorial(5)) # 120
Explanation of the Code
factorial(5)callsfactorial(4), which callsfactorial(3), and so on, down tofactorial(1), which returns1(the base case).- The results then multiply back up the chain:
1 -> 2 -> 6 -> 24 -> 120. - Every recursive function must have a base case, or it will call itself forever, eventually crashing with a
RecursionError.
Real-World Example
Recursion naturally fits problems with a repeating, self-similar structure — like navigating folders within folders, or calculating Fibonacci numbers.
pythondef fibonacci(n): if n <= 1: return n return fibonacci(n - 1) + fibonacci(n - 2) for i in range(7): print(fibonacci(i), end=" ")
Output:
0 1 1 2 3 5 8Common Mistakes
- Forgetting the base case, causing infinite recursion and a crash.
- Using recursion for problems that would be simpler and more efficient with a plain loop.
Important Points
- Every recursive function needs a base case (a stopping condition) and a recursive case (that moves toward the base case).
- Recursion is elegant for tree-like or self-similar problems, but can be less efficient than loops for simple repetitive tasks.
Practice
- Write a recursive function to calculate the sum of numbers from 1 to
n. - Write a recursive function to reverse a string.
10. Higher-Order Functions: map, filter, reduce
What is it?
A higher-order function is a function that takes another function as an argument (or returns one). Python provides three especially useful built-in ones: map(), filter(), and reduce().
map() — Apply a Function to Every Item
pythonnumbers = [1, 2, 3, 4, 5] squared = list(map(lambda x: x ** 2, numbers)) print(squared) # [1, 4, 9, 16, 25]
Explanation: map() applies the given function to every item in numbers, producing a new sequence of results.
filter() — Keep Only Items That Pass a Condition
pythonnumbers = [1, 2, 3, 4, 5, 6, 7, 8] evens = list(filter(lambda x: x % 2 == 0, numbers)) print(evens) # [2, 4, 6, 8]
Explanation: filter() keeps only the items for which the given function returns True.
reduce() — Combine All Items Into a Single Value
pythonfrom functools import reduce numbers = [1, 2, 3, 4] total = reduce(lambda a, b: a + b, numbers) print(total) # 10
Explanation: reduce() repeatedly combines items two at a time: ((1 + 2) + 3) + 4 = 10. Unlike map() and filter(), reduce() must be imported from the functools module.
Comparison Table
| Function | Purpose | Returns |
|---|---|---|
map() | Transform every item | New sequence (same length) |
filter() | Keep items matching a condition | New sequence (same or shorter length) |
reduce() | Combine all items into one value | A single value |
Common Mistakes
- Forgetting to wrap
map()/filter()results inlist(...)to actually see the values (they return special iterator objects, not lists directly). - Forgetting to
import reducefromfunctools— unlikemap/filter, it's not a built-in available by default.
Important Points
map(),filter(), andreduce()are often used with lambda functions for compact, one-line data processing.- They can often be replaced with list comprehensions, which many Python developers find more readable (e.g.,
[x**2 for x in numbers]instead ofmap()).
Practice
- Use
map()to convert a list of Celsius temperatures to Fahrenheit. - Use
filter()to extract only the words longer than 4 letters from a list of words. - Use
reduce()to find the maximum value in a list without using the built-inmax().
Common Beginner Mistakes — Summary for This Section
- Confusing
print()withreturn. - Forgetting a function without
returngives backNone. - Placing default parameters before non-default ones.
- Forgetting the
globalkeyword when modifying a global variable inside a function. - Writing recursive functions without a proper base case.
Cheat Sheet — Functions
pythondef my_function(a, b=10, *args, **kwargs): return a + b my_function(5) # uses default b my_function(5, 20) # positional my_function(a=5, b=20) # keyword my_function(1, 2, 3, 4) # extra positional -> args my_function(1, x=5, y=10) # extra keyword -> kwargs square = lambda x: x ** 2 # lambda list(map(square, [1, 2, 3])) # map list(filter(lambda x: x > 1, [1, 2, 3])) # filter from functools import reduce reduce(lambda a, b: a + b, [1, 2, 3]) # reduce
Mini Project: Expense Tracker
Objective
Build a function-based command-line program that lets a user add expenses, view them, and see a running total.
Requirements
- Store expenses as a list of dictionaries (
{"category": ..., "amount": ...}). - Provide functions to add an expense, view all expenses, and calculate the total.
- Use a loop to let the user keep adding expenses until they choose to stop.
Concepts Used
Functions, parameters/return values, lists, dictionaries, loops, conditionals.
Complete Code
pythonexpenses = [] def add_expense(category, amount): expenses.append({"category": category, "amount": amount}) print(f"Added: {category} - Rs.{amount}") def view_expenses(): if not expenses: print("No expenses recorded yet.") return for expense in expenses: print(f"{expense['category']}: Rs.{expense['amount']}") def calculate_total(): return sum(expense["amount"] for expense in expenses) while True: print("\n1. Add Expense 2. View Expenses 3. View Total 4. Exit") choice = input("Choose an option: ") if choice == "1": category = input("Category: ") amount = float(input("Amount: ")) add_expense(category, amount) elif choice == "2": view_expenses() elif choice == "3": print(f"Total Expenses: Rs.{calculate_total():.2f}") elif choice == "4": print("Goodbye!") break else: print("Invalid choice, try again.")
Code Explanation
- Each menu option calls a dedicated function, keeping the main loop clean and readable.
calculate_total()uses a generator expression insidesum()to add up every expense's amount without needing a separate loop.- The
while Trueloop keeps the menu running until the user selects "Exit."
Sample Output
1. Add Expense 2. View Expenses 3. View Total 4. Exit
Choose an option: 1
Category: Groceries
Amount: 1500
Added: Groceries - Rs.1500.0
1. Add Expense 2. View Expenses 3. View Total 4. Exit
Choose an option: 3
Total Expenses: Rs.1500.00Possible Improvements
- Add a function to delete or edit an existing expense.
- Group and display expenses by category with subtotals.
- Save expenses to a file so they persist after the program closes (covered in the File Handling section).
Challenge Task
Add a function that shows the total spent per category using a dictionary that accumulates totals as expenses are added.
Interview Questions
Q1. What is the difference between a parameter and an argument? Answer: A parameter is the variable name listed in a function's definition; an argument is the actual value passed in when the function is called.
*Q2. What's the difference between `args and kwargs`? Answer: *args collects extra positional arguments into a tuple. **kwargs collects extra keyword arguments into a dictionary.
Q3. What does a function return if there's no explicit `return` statement? Answer: None.
Q4. What is the difference between local and global scope? Answer: A local variable is defined inside a function and only accessible there. A global variable is defined outside any function and accessible throughout the program (though modifying it inside a function requires the global keyword).
Q5. What is a lambda function, and when would you use one? Answer: A small, anonymous, single-expression function, typically used for short operations passed into functions like sort(), map(), or filter().
Q6. What are the two essential parts of any recursive function? Answer: A base case (a condition that stops the recursion) and a recursive case (where the function calls itself with a smaller version of the problem).
Practice Questions
Beginner
- Write a function
is_even(n)that returnsTrueif a number is even. - Write a function that takes a name and greets it with a default value of "Guest" if no name is passed.
- Write a function
add(a, b, c)and call it using keyword arguments in a different order. - Write a lambda function that multiplies two numbers.
- Write a function that returns the maximum of any number of arguments using
*args.
Intermediate
- Write a recursive function to calculate the factorial of a number.
- Write a function that takes a list of numbers and returns a new list with only the even numbers, using
filter(). - Write a function that takes a sentence and returns the number of vowels in it.
- Write a function using
**kwargsthat builds and returns a formatted string from any number of key-value details. - Write a function that calculates simple interest, with default values for rate and time.
Challenge
- Write a recursive function to calculate the nth Fibonacci number, and compare its speed to an iterative version for large
n. - Write a function that takes a list of student dictionaries and returns the name of the student with the highest marks, using
max()with a lambdakey. - Extend the Expense Tracker mini project to filter and display expenses above a certain amount, entered by the user.