Home/Learn/Python A–Z/Functions — def, Return Values & Default Arguments

Functions — def, Return Values & Default Arguments

Beginner
Functions

Functions are first-class objects defined with def, returning None unless told otherwise — with keyword arguments and default values that make call sites self-documenting.

Overview

Python functions are objects: you can assign them to variables, pass them around, and store them in dicts (that's how routing tables and strategy patterns work without interfaces). Every function returns something — None if you don't return explicitly. Arguments can be passed by position or by name (keyword arguments), and defaults make parameters optional. One famous trap lives here: mutable default arguments are evaluated ONCE at definition time — the single most-asked Python interview gotcha.

Definition, Keyword Args & Multiple Returns

Call with names for readability (send_mail(to="x", urgent=True)). Returning multiple values actually returns one tuple, unpacked at the call site.

Defaults, keyword calls, tuple returns
def apply_discount(price, percent=10):     # percent is optional
    discounted = price * (1 - percent / 100)
    return round(discounted, 2)

apply_discount(1000)               # 900.0  — default used
apply_discount(1000, 25)           # 750.0  — positional
apply_discount(price=1000, percent=25)   # named — self-documenting

# "Multiple" return values = one tuple
def min_max(nums):
    return min(nums), max(nums)    # returns a tuple

lo, hi = min_max([4, 9, 1])        # unpacked
print(lo, hi)                      # 1 9

# Functions are objects
operations = {"double": lambda x: x * 2, "square": lambda x: x ** 2}
print(operations["square"](6))     # 36

THE Trap: Mutable Default Arguments

Default values are evaluated once, when def runs — not on every call. A mutable default (list/dict) is therefore SHARED across all calls. The fix: default to None and create inside.

Mutable default — the classic Python gotcha
# BUG — the default list is created ONCE
def add_task(task, tasks=[]):
    tasks.append(task)
    return tasks

print(add_task("read"))    # ['read']
print(add_task("code"))    # ['read', 'code']  ← surprise! same list

# FIX — None sentinel
def add_task(task, tasks=None):
    if tasks is None:
        tasks = []            # fresh list per call
    tasks.append(task)
    return tasks

print(add_task("read"))    # ['read']
print(add_task("code"))    # ['code']  ✓

Key Points to Remember

  • 1No explicit return → the function returns None
  • 2Keyword arguments make call sites readable; defaults make params optional
  • 3NEVER use mutable defaults (list/dict) — use None + create inside
  • 4Returning a, b returns a tuple; unpack with x, y = f()

Interview Questions

Sign in to ask Aria
1

What is wrong with def f(x, items=[])? Explain exactly why and fix it.

MediumAmazon
2

What does a Python function return if there is no return statement?

EasyHCL
3

How does Python return multiple values from a function — what is really happening?

EasyJio

Ask Aria about Functions — def, Return Values & Default Arguments

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…