Functions In Python — PBA Institute Tutorial
Chapter 07 · Python Programming Series
12 min read Beginner

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 returns None.
  • Call a function by writing function_name(arguments).
  • Parameters are the variables in the definition; arguments are the values passed during the call.
Functions — Syntax
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: def creates the function but does not run it. Calling it with name(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: return sends 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 *args to accept any number of positional arguments (as a tuple) and **kwargs for keyword arguments (as a dict). Great for wrappers and decorators.
  • Scope and lifetime: Variables created inside a function are local. Use global or nonlocal sparingly. Prefer passing values explicitly and returning new objects.

Code Examples

Example 1 — Simple Function
def square(x):
    return x * x

print(square(7))
Output 49
Example 2 — Default & Keyword Arguments
def power(base, exp=2):
    return base ** exp

print(power(5))
print(power(2, exp=10))
Output 25
1024
Example 3 — Multiple Return Values
def divmod_pair(a, b):
    return a // b, a % b

q, r = divmod_pair(17, 5)
print("Quotient:", q, "Remainder:", r)
Output Quotient: 3 Remainder: 2
Example 4 — *args
def total(*nums):
    return sum(nums)

print(total(1, 2, 3, 4, 5))
Output 15
Example 5 — **kwargs
def profile(**info):
    for k, v in info.items():
        print(f"{k}: {v}")

profile(name="Ankit", age=22, city="Delhi")
Output name: Ankit
age: 22
city: Delhi
Example 6 — Higher-Order Function (Functions as Args)
def apply(fn, value):
    return fn(value)

print(apply(lambda x: x ** 3, 4))
Output 64

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, not calc.
  • 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=[])) — use None and 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 returns None.
  • Mutable default arguments: a default [] is shared across calls — surprising bug.
  • Shadowing built-ins: naming a parameter list or type hides 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 *args and returns the longest one.

Interview Questions

  • Q1. What is the difference between a parameter and an argument?
  • Q2. Explain *args and **kwargs with 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 return and print?

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

Next

Go to Next Chapter