JSTAcademy
0 XP
Dashboard
Crash Courses
Functions, Scope & Reusable Code
14 min
Masters+170 XP
Crash Courses · Masters

Functions, Scope & Reusable Code

Write clean, reusable functions using parameters, return values, *args, **kwargs, and docstrings.
14 min read+170 XP on completionCert: Python Crash Course
Tap any word in the text below to start reading from there.

Functions, Scope & Reusable Code

Defining and Calling Functions

def greet(name):
    """Return a greeting string for the given name."""
    return f"Hello, {name}!"

message = greet("Jordan")
print(message)   # Hello, Jordan!

# A function without return implicitly returns None
def log(msg):
    print(f"[LOG] {msg}")

result = log("started")
print(result)   # None

---

Default Parameters

def create_user(name, role="viewer", active=True):
    return {"name": name, "role": role, "active": active}

# Use defaults
print(create_user("Jordan"))
# {'name': 'Jordan', 'role': 'viewer', 'active': True}

# Override specific defaults
print(create_user("Owen", role="admin"))
# {'name': 'Owen', 'role': 'admin', 'active': True}

# ⚠️ COMMON BUG: mutable defaults persist across calls
def append_item(item, lst=[]):  # DON'T DO THIS
    lst.append(item)
    return lst

print(append_item(1))   # [1]
print(append_item(2))   # [1, 2] — same list reused!

# CORRECT: use None as default, create list inside function
def append_item(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

---

*args: Variable Positional Arguments

def sum_all(*args):
    """Sum any number of numeric arguments."""
    return sum(args)   # args is a tuple inside the function

print(sum_all(1, 2, 3))           # 6
print(sum_all(10, 20, 30, 40))    # 100
print(sum_all())                   # 0

def log_events(level, *messages):
    for msg in messages:
        print(f"[{level.upper()}] {msg}")

log_events("info", "Server started", "Listening on port 8000", "Ready")
# [INFO] Server started
# [INFO] Listening on port 8000
# [INFO] Ready

---

kwargs: Variable Keyword Arguments

def build_query(**filters):
    """Build a SQL-style query from keyword filters."""
    conditions = [f"{k} = {repr(v)}" for k, v in filters.items()]
    return "WHERE " + " AND ".join(conditions) if conditions else ""

print(build_query(status="active", role="admin"))
# WHERE status = 'active' AND role = 'admin'

# Combine all parameter types: positional, *args, keyword, **kwargs
def fn(required, *args, keyword="default", **kwargs):
    print(f"required={required}")
    print(f"args={args}")
    print(f"keyword={keyword}")
    print(f"kwargs={kwargs}")

fn("hello", 1, 2, 3, keyword="custom", x=10, y=20)
# required=hello
# args=(1, 2, 3)
# keyword=custom
# kwargs={'x': 10, 'y': 20}

---

Scope: LEGB Rule

x = "global"        # Global scope

def outer():
    x = "enclosing"   # Enclosing scope

    def inner():
        x = "local"   # Local scope
        print(x)      # local — local takes priority

    inner()
    print(x)          # enclosing

outer()
print(x)              # global

# global keyword — modify a global inside a function (use sparingly)
count = 0

def increment():
    global count
    count += 1

increment()
increment()
print(count)   # 2

# nonlocal keyword — modify enclosing scope variable
def make_counter():
    total = 0
    def add(n):
        nonlocal total
        total += n
        return total
    return add

counter = make_counter()
print(counter(5))    # 5
print(counter(3))    # 8

---

Docstrings

def calculate_stats(numbers):
    """
    Calculate descriptive statistics for a list of numbers.

    Args:
        numbers: A list of numeric values. Must be non-empty.

    Returns:
        A dict with keys: min, max, mean, total, count.

    Raises:
        ValueError: If the input list is empty.

    Example:
        >>> calculate_stats([1, 2, 3, 4, 5])
        {'min': 1, 'max': 5, 'mean': 3.0, 'total': 15, 'count': 5}
    """
    if not numbers:
        raise ValueError("Cannot calculate stats on an empty list")
    return {
        "min": min(numbers),
        "max": max(numbers),
        "mean": sum(numbers) / len(numbers),
        "total": sum(numbers),
        "count": len(numbers),
    }

# Access docstring
print(calculate_stats.__doc__)
help(calculate_stats)

---

Lambda Functions (One-Line Anonymous Functions)

# lambda args: expression
double = lambda x: x * 2
print(double(5))    # 10

# Most useful as callbacks — sorting, filtering
people = [{"name": "Tony", "age": 34}, {"name": "Aria", "age": 28}]
people.sort(key=lambda p: p["age"])
print(people)   # Aria first (28), then Tony (34)

# But for anything beyond one line, use def — it's clearer
0%