10 - Functions
Functions let you name and reuse a piece of logic.
A simple picture
A function is like a small machine with a name:
arguments -> function machine -> returned result
A machine may receive values through parameters, perform one clear job, and send a result back with return.
Defining and calling
def greet(name):
return f"Hello, {name}!"
message = greet("Asha")
print(message)
The def block creates the function. The call greet("Asha") runs it. name is a parameter; "Asha" is an argument.
Four common function types
We can group beginner functions by two questions:
- Does the function receive input through parameters?
- Does the function send a result back with
return?
These are teaching categories, not four different Python keywords.
Type 1: No parameters and no return value
def show_welcome():
print("Welcome to Python")
show_welcome()
This function always performs the same action. It does not receive data and does not send a result back.
Type 2: Parameters and no return value
def greet(name):
print(f"Hello, {name}!")
greet("Asha")
The function receives name, but its job is only to display a message.
Type 3: No parameters and a return value
def get_course_name():
return "Python Basic"
course_name = get_course_name()
print(course_name)
The function needs no input, but it sends a value back to the caller.
Type 4: Parameters and a return value
def add(first, second):
return first + second
total = add(10, 20)
print(total)
This is the most reusable type because it accepts data and produces a result.
return versus print
print() displays a value. return sends a value to the caller:
def add(a, b):
return a + b
total = add(2, 3)
Use return when another part of the program needs to use the result. A function without return returns None.
Important fact:
print()displays something for a person.returnsends a value back to the code that called the function. Printing a value does not automatically make it the function’s returned result.
Python can return more than one value. It actually packs the values into a tuple:
def calculate(a, b):
return a + b, a - b
addition, difference = calculate(10, 3)
print(addition, difference)
Built-in and user-defined functions
Python provides built-in functions such as print(), len(), type(), sum(), and round(). You can call them without defining them first.
When you write a function with def, it is a user-defined function:
def double(number):
return number * 2
Use a built-in function when it clearly solves the problem. Write your own function when you need project-specific behavior or want to give a repeated process a meaningful name.
Parameters, arguments, and defaults
def calculate_total(price, quantity, discount=0):
subtotal = price * quantity
return subtotal - subtotal * discount
print(calculate_total(100, 2))
print(calculate_total(100, 2, discount=0.10))
Positional arguments follow order. Keyword arguments name the parameter and make calls clearer. Required parameters should come before default parameters.
def introduce(name, city="Unknown"):
return f"{name} lives in {city}"
print(introduce("Ravi"))
print(introduce("Ravi", city="Pune"))
Here name is required and city has a default value. A default is used only when the caller does not provide that argument.
Optional extension: variable-length arguments with *args and **kwargs
Variable-length arguments: *args
Sometimes a function should accept any number of positional arguments. Put * before the parameter name:
def add_all(*numbers):
print(numbers) # a tuple containing all received values
return sum(numbers)
print(add_all(2, 4))
print(add_all(2, 4, 6, 8))
The name args is a convention, not a special word. *numbers collects extra positional arguments into a tuple. Use *args only when a variable number of values is genuinely useful; ordinary parameters are easier for beginners to read.
Variable-length keyword arguments: **kwargs
Sometimes a function should accept extra named options. Put ** before the parameter name:
def show_profile(**details):
for key, value in details.items():
print(f"{key}: {value}")
show_profile(name="Meera", city="Hyderabad", role="Student")
**details collects the named arguments into a dictionary. The name kwargs is also only a convention.
*args and **kwargs together
def report(title, *scores, **metadata):
print(title)
print(f"Average: {sum(scores) / len(scores):.2f}")
print(metadata)
report("Math", 80, 90, 85, student="Ravi", term="First")
Learn the idea, but do not use these tools everywhere. Prefer clear named parameters when the number of inputs is known.
Scope
Variables created inside a function are local:
def make_message():
message = "Done"
return message
Prefer passing data into functions and returning results instead of changing global variables. This makes functions easier to test.
Docstrings
def area_of_circle(radius):
"""Return the area of a circle for a given radius."""
return 3.14159 * radius ** 2
Optional extension: recursion
Recursion introduction
A recursive function calls itself and must have a base case:
def factorial(number):
if number == 0:
return 1
return number * factorial(number - 1)
For many beginner problems, a loop is easier to read than recursion.
Real-world design
def collect_item():
name = input("Item: ")
price = float(input("Price: "))
return name, price
def display_item(name, price):
print(f"{name}: Rs. {price:.2f}")
Each function has one responsibility, so changing input or display does not require rewriting the calculation.
Common mistakes
- Defining a function but never calling it.
- Printing instead of returning a value needed elsewhere.
- Using global variables unnecessarily.
- Returning too early inside a loop.
- Forgetting a recursion base case.
- Confusing
*argswith a normal list parameter. - Forgetting that
**kwargscollects named values in a dictionary. - Using
*argsor**kwargswhen simple named parameters would be clearer.
Bug Hunter
Bug 1 — function never called
def greet(name):
return f"Hello, {name}!"
The function is defined, but nothing calls it or displays its result.
Bug 2 — printing instead of returning
def add(first, second):
print(first + second)
total = add(2, 3)
print(total)
The function displays 5, but its returned value is None.
Bug 3 — shared mutable default
def add_task(task, tasks=[]):
tasks.append(task)
return tasks
The default list is created once, so later calls reuse it.
Show Bug Hunter fixes
# Bug 1
message = greet("Maya")
print(message)
# Bug 2
def add(first, second):
return first + second
# Bug 3
def add_task(task, tasks=None):
if tasks is None:
tasks = []
tasks.append(task)
return tasks
Optional deeper look: what happens during a function call?
Python first matches arguments to parameters. It then creates a call frame, a workspace holding the function’s local names and current instruction. When the function returns, that frame finishes and the returned object goes back to the caller. Default values are created once when Python executes the def statement, which explains the shared-list bug above.
Practice
Try these problems on this page. Write the function name, parameters, return value, and one function call before writing the function body.
Problems
- Write a function that returns the square of a number.
- Write a function that checks whether a number is even.
- Write a function that returns the largest of three values.
- Write a function that calculates a bill with an optional discount.
- Write a function that counts vowels in text.
- Split a calculator into separate functions.
- Write a function that returns all factors of a number.
- Write a function that validates a password and returns a reason.
- Write a recursive factorial function and test edge cases.
- Design a reusable student-result module with at least four functions.
Show hints
- Return the number multiplied by itself.
- Return the remainder comparison.
- Keep a current best value.
- Give the discount a default of zero.
- Loop through lowercase text.
- Use one function for each arithmetic operation.
- Test divisors from 1 through the number.
- Return a boolean and a reason, or return a clear message.
- Use a base case for zero.
- Separate input, validation, calculations, and display.
Show solution ideas
def square(number): return number * number.return number % 2 == 0.- Start with the first value and compare the other two.
- Calculate the subtotal, then subtract
subtotal * discount. - Count characters that occur in
"aeiou". - Define
add,subtract,multiply, anddivide. - Return values for which
number % factor == 0. - Check each password rule in order and return after the first failure.
return 1 if number == 0 else number * factorial(number - 1).- Use small functions with clear parameters and return values.
Homework
Refactor one earlier project so that input, validation, calculation, and display are handled by separate functions.
Checkpoint
Break a bill calculator into at least three functions and explain the inputs and outputs of each function.