Reusable Code With Functions
Functions are the building blocks of every serious Python program. They package logic into named, reusable units — making code shorter, cleaner, easier to test, and easier to share. In this lesson you'll learn how to define functions, pass arguments, return values, set defaults, and apply best practices used in professional Python codebases.
Overview
Reusable
Write once, call as many times as you want with different inputs.
Testable
Each function does one thing — easy to unit-test in isolation.
Documented
Docstrings make functions self-explaining and tool-friendly.
Flexible Args
Mix positional, keyword, default, and variable-length arguments.
First-Class
Functions are objects — pass them around, store in lists, return from other functions.
Syntax
- Define a function with
def function_name(parameters):followed by an indented body. - Return a value with
return; without it, the function returnsNone. - Call a function by writing
function_name(arguments). - Parameters are the variables in the definition; arguments are the values passed during the call.
def greet(name, greeting="Hello"):
"""Return a friendly greeting."""
return f"{greeting}, {name}!"
# Calls
print(greet("Riya"))
print(greet("Sam", greeting="Hi"))
Detailed Explanation
- Why functions matter: They turn complex programs into a collection of well-named tasks. Each function has one job; together they compose a system. Reusable logic also makes testing easier.
- Definition vs call:
defcreates the function but does not run it. Calling it withname(args)actually executes the body. - Parameters and arguments: Parameters are placeholders declared in the function signature; arguments are the concrete values supplied when calling it. Python supports positional, keyword, default, and variable-length arguments.
- Return values:
returnsends a value back to the caller and immediately exits the function. A function may return any object — a number, string, list, dict, even another function. - *args and **kwargs: Use
*argsto accept any number of positional arguments (as a tuple) and**kwargsfor keyword arguments (as a dict). Great for wrappers and decorators. - Scope and lifetime: Variables created inside a function are local. Use
globalornonlocalsparingly. Prefer passing values explicitly and returning new objects.
Code Examples
def square(x):
return x * x
print(square(7))
def power(base, exp=2):
return base ** exp
print(power(5))
print(power(2, exp=10))
1024
def divmod_pair(a, b):
return a // b, a % b
q, r = divmod_pair(17, 5)
print("Quotient:", q, "Remainder:", r)
def total(*nums):
return sum(nums)
print(total(1, 2, 3, 4, 5))
def profile(**info):
for k, v in info.items():
print(f"{k}: {v}")
profile(name="Ankit", age=22, city="Delhi")
age: 22
city: Delhi
def apply(fn, value):
return fn(value)
print(apply(lambda x: x ** 3, 4))
Real-World Use Cases
Math Libraries
math.sqrt, math.factorial — all built as Python functions.
Web APIs
Each HTTP endpoint maps to a view function in Flask or Django.
Data Pipelines
ETL scripts compose small functions for extract, transform, load.
Testing
Each unit test is itself a function calling other functions.
Automation
Re-usable utilities for emailing, file handling, or data backups.
Machine Learning
Pre-processing, model training, and prediction are wrapped as functions.
Notes & Pro Tips
- Give functions descriptive verb-based names:
calculate_total, notcalc. - Keep a function under ~30 lines — split anything longer.
- Use docstrings (
"""...""") — IDEs, help() and Sphinx all read them. - Avoid mutable default arguments (
def f(x=[])) — useNoneand create inside. - Type hints (
def add(x: int, y: int) -> int) improve readability and tooling. - Prefer pure functions: same inputs → same outputs, no side effects.
Common Mistakes
- Forgetting
return: the function silently returnsNone. - Mutable default arguments: a default
[]is shared across calls — surprising bug. - Shadowing built-ins: naming a parameter
listortypehides the built-in. - Overusing global: makes code hard to test and reason about.
- Side effects everywhere: modifying a list passed in instead of returning a new one surprises callers.
- Too many parameters: if a function needs 7+ args, group them into a dict or class.
Practice Problems
- Problem 1: Write a function that checks whether a given number is prime.
- Problem 2: Create a function
factorial(n)that computes n! recursively and iteratively. - Problem 3: Write a function that takes a list and returns the largest and smallest as a tuple.
- Problem 4: Build
convert_temp(value, unit)that converts between Celsius and Fahrenheit. - Problem 5: Write a function
palindrome(s)that returns True if s reads the same forwards and backwards. - Problem 6: Create a function that accepts any number of strings via
*argsand returns the longest one.
Interview Questions
- Q1. What is the difference between a parameter and an argument?
- Q2. Explain
*argsand**kwargswith examples. - Q3. What is the difference between positional and keyword arguments?
- Q4. What is a lambda function? When would you use it?
- Q5. Are Python functions first-class objects? Why does it matter?
- Q6. What is the difference between
returnandprint?
Frequently Asked Questions
- Q1: What does return None mean?
If you don't explicitly return a value, Python returns the special object None. You can use this for procedures that perform side-effects only. - Q2: Can a function return multiple values?
Technically it returns one tuple containing many values. Unpack on the call site: a, b = my_func(). - Q3: What is a docstring?
A triple-quoted string immediately after def. It documents the purpose, parameters, and return value of the function. Accessible via help() and function.__doc__. - Q4: Can functions call themselves?
Yes — recursion. Always have a base case to prevent infinite recursion. - Q5: What is the difference between *args and **kwargs?
*args collects extra positional arguments into a tuple; **kwargs collects extra keyword arguments into a dict. - Q6: Are functions objects in Python?
Yes. You can assign them to variables, put them in lists, return them from other functions — making higher-order programming natural.
Summary
Functions transform raw scripts into reusable, testable, professional codebases. Master parameters, default values, *args/**kwargs, return values, and scoping — and you've unlocked one of Python's most powerful productivity tools. Write small focused functions, document them, and your future self (and your team) will thank you.
Continue Learning
Previous
Go to Previous Chapter