A function is a logical block of reusable code designed to perform one defined task.
It typically:
- Accepts inputs via parameters.
- Executes a specific process.
- Produces outputs as return values.
Mathematically:
f(x) = y
In programming:
def f(x):
return x + 5Parameters define what information a function expects to receive. They are placeholders that become actual variables when the function is called.
Example:
def greet(name):
print(f"Hello, {name}")name→ parameter- When called as
greet("Brandon"),"Brandon"is the argument.
| Property | Description |
|---|---|
| Name | Identifier used within the function. |
| Type | Determines what data can be accepted (e.g., int, string). |
| Position | Determines how the argument is matched to the parameter. |
| Default Value | Used when no argument is passed. |
Example:
def user_info(name, age=25):
return f"{name} is {age} years old."Calling user_info("Alex") → “Alex is 25 years old.”
| Type | Description | Example |
|---|---|---|
| Positional Parameters | Values passed in order. | def add(a, b): return a+b |
| Keyword Parameters | Values passed by name. | add(a=5, b=10) |
| Default Parameters | Provide fallback value. | def greet(name="Guest") |
| Variable-Length Parameters | Accept any number of args. | def total(*nums): return sum(nums) |
| Keyword Variable-Length Parameters | Capture key-value pairs. | def info(**data): return data |
A copy of the data is passed; changes don’t affect the original.
void test(int a) { a = 5; } // original unchangedActual reference is passed; modifications persist.
void test(int &a) { a = 5; } // original modifiedPython’s hybrid approach — mutable objects can be modified; immutable ones cannot.
def modify_list(lst):
lst.append(5) # modifies caller’s listdef func(positional, /, positional_or_keyword, *, keyword_only):
Example:
def example(a, /, b, *, c):
return a + b + c/→ everything before it must be positional.*→ everything after must be keyword-based.
A return value is the result produced by a function after execution.
It’s delivered to the caller through the return keyword.
Example:
def add(a, b):
return a + b
result = add(2, 3) # 5- Once a
returnexecutes, the function terminates immediately. - Code after
returnis ignored. - If no return statement is provided, the function implicitly returns
None(in Python) orvoidin typed languages like C.
| Type | Description | Example |
|---|---|---|
| Single Return Value | Returns one output. | return a + b |
| Multiple Return Values | Returns multiple values (tuple or list). | return x, y, z |
| Conditional Return | Return depends on logic. | if n>0: return n else: return 0 |
| Void Return | No data returned. | print("done") |
| Generator Return | Returns sequence lazily. | yield i |
| Type | Description | Example |
|---|---|---|
| Pure | Output depends only on input. | def square(x): return x*x |
| Impure | Output depends on external state. | def get_time(): return datetime.now() |
Pure functions are predictable, testable, and easier to debug.
Before returning:
- Confirm output type matches expectation.
- Avoid mixed-type returns (e.g., int in one case, string in another).
- Document return behavior clearly.
Example:
def safe_divide(a: float, b: float) -> float | None:
"""Returns division result or None if division by zero occurs."""
if b == 0:
return None
return a / bModel:
Inputs (Parameters)
↓
Function Logic
↓
Outputs (Return Value)
Example:
def compute_area(radius):
from math import pi
return pi * radius ** 2
print(compute_area(10)) # 314.159...- Keep function responsibilities singular.
- Validate all input data.
- Document parameters and return types.
- Return consistent data formats.
- Avoid global state dependencies.
- Use descriptive parameter names (
num_students>n). - Use type hints for clarity.
- Do not overload return values with multiple responsibilities.
Example:
def calculate_interest(principal: float, rate: float, years: int) -> float:
"""Compute compound interest."""
return principal * ((1 + rate) ** years)| Concept | Definition | Example | Output |
|---|---|---|---|
| Parameter | Placeholder for input | def f(x) |
Receives input |
| Argument | Actual input value | f(5) |
5 |
| Return Value | Data sent back by function | return x+1 |
Computed result |
| Default Parameter | Provides fallback | def f(x=10) |
Uses 10 if missing |
| *args / **kwargs | Collects flexible input | def f(*a, **b) |
Tuple & Dict |
| Void Return | Function returns nothing | def log(): print() |
None |
| Pure Function | Output depends only on input | add(a,b) |
Deterministic |
| Impure Function | Depends on external state | print_time() |
Non-deterministic |
def power_of(n):
def inner(x):
return x ** n
return inner
square = power_of(2)
print(square(4)) # 16def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)def stats(data):
return min(data), max(data), sum(data) / len(data)
mn, mx, avg = stats([2, 4, 6])
print(mn, mx, avg) # 2 6 4.0Unit test using unittest:
import unittest
def add(a, b):
return a + b
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
self.assertIsInstance(add(1, 2), int)- Explain the relationship between parameters, arguments, and return values.
- Differentiate between positional, keyword, and default parameters. Provide one real-world example for each.
- Describe how parameter passing differs in Python, C, and C++.
- Explain why functions with no return statement still produce a return value in Python.
- What are the advantages of using type hints in parameter and return value definitions?
- Define the difference between “pure” and “impure” functions, and explain their impact on testability.
- Why is it important for return types to remain consistent across all branches of a function?
Analyze the code and predict output with reasoning.
Q1
def func(a, b=3, *args, **kwargs):
return a + b + sum(args) + sum(kwargs.values())
print(func(2, 4, 6, 8, x=10, y=2))- Explain how each parameter type is bound.
- Compute the exact return value.
Q2
def modify(x, lst=[]):
lst.append(x)
return lst
print(modify(1))
print(modify(2))
print(modify(3))- Explain why the output behaves as it does.
- Identify the design flaw and propose a correction.
Q3
def compute(a, b):
if a > b:
return a - b
elif a == b:
return None
return b - a- Identify how many distinct return paths exist.
- What data types might this function return?
- Suggest a more consistent return behavior.
-
Design a function named
safe_average(numbers)that:- Accepts a list of numbers.
- Returns the average value.
- Returns
0.0if the list is empty. - Validates that all inputs are numeric.
-
Create a function that:
- Accepts two parameters
principalandratewith a default rate of0.05. - Returns the total amount after one year using simple interest.
- Document parameter and return types.
- Accepts two parameters
-
Write a recursive function
reverse_string(text)that:- Takes one string parameter.
- Returns the reversed version of that string.
-
Build a function
generate_report(*scores, **metadata)that:- Calculates average score.
- Returns a dictionary combining metadata and the computed average.
- Demonstrates use of both *args and **kwargs.
- Why might returning multiple data types from the same function create maintenance problems?
- Explain how parameter immutability affects debugging and refactoring.
- In large systems, why is documenting parameter purpose and return type essential for team-based development?
- Given that parameters and returns define a function’s “contract,” how does breaking this contract affect software reliability?
Functions are contracts between input and output. Parameters define what enters; return values define what exits. Mastering both ensures logical clarity, predictable code, and maintainable software architecture.