Functions

Functions are reusable blocks of code that perform a specific task. Business analysts use them to turn repeated steps into one-click actions: cleaning text, computing KPIs, generating summaries. Mastering functions lets you ship reliable tools instead of one-off scripts.

Estimated reading time: 25–30 minutes

Useful Function Patterns

  • Pure functions → same input ⇒ same output (easy to test)
  • Small & focused → one clear job, one return value
  • Keyword-only args → safer, self-documenting APIs
  • Higher-order → functions that return functions

Great for: KPI calculators, transformers, validators

Best Practices & Pitfalls

  • Prefer return values over printing from functions
  • Add docstrings & type hints for clarity
  • Avoid mutable default args (e.g., list, dict)
  • Keep side effects (I/O) at the edges; logic in pure functions

Great for: maintainable code that tools & teammates understand

Defining and Calling Functions

A function is created with def plus a name and parentheses. Keep it short with a single responsibility. Return a value so other code can reuse the result.

python
def greet():
    return "Hello, World!"  # return instead of printing

message = greet()
print(message)  # calling the function

Function Parameters and Return Values

Parameters are inputs; return sends a result back. Prefer returning structured data (e.g., dict) for clarity.

python
def add(a: float, b: float) -> float:
    return a + b

result = add(5, 3)
print("The sum is:", result)

Positional vs Keyword Arguments

Keyword arguments make calls self-documenting and harder to mix up.

python
def describe_pet(animal_type: str, pet_name: str) -> str:
    return f"I have a {animal_type} named {pet_name}."

print(describe_pet("dog", "Buddy"))                   # positional
print(describe_pet(pet_name="Milo", animal_type="cat"))  # keyword

Default & Keyword-Only Parameters

Use * to force keywords for clarity on optional knobs.

python
def price(qty: int, unit: float, *, currency: str = "USD", discount: float = 0.0) -> dict:
    total = qty * unit * (1 - discount)
    return {"total": round(total, 2), "currency": currency}

print(price(3, 1200, discount=0.1))   # must name keyword-only args

*args and **kwargs

Accept flexible inputs; perfect for wrappers and loggers.

python
def log(*msgs, **meta):
    return " | ".join(map(str, msgs)) + " " + str(meta)

print(log("Start", step=1, user="ana"))

Multiple Returns & Unpacking

Return a tuple for multiple values; unpack where you call it.

python
def revenue_cost() -> tuple[int, int]:
    return 50000, 30000

rev, cost = revenue_cost()
print(rev, cost)

Lambda Functions

Small anonymous functions, great for sort keys and tiny transforms.

python
items = ["aaa", "b", "cc"]
print(sorted(items, key=lambda s: len(s)))

Functions Returning Functions

Use factories to create configured calculators.

python
def make_multiplier(k: float):
    def mul(x: float) -> float:
        return x * k
    return mul

double = make_multiplier(2)
print(double(10))  # 20

Docstrings & Type Hints

Explain purpose & types so IDEs and teammates understand intent.

python
def roi(investment: float, returns: float) -> float:
    """Return investment ROI percentage. Returns 0 if investment is 0."""
    if investment == 0:
        return 0.0
    return (returns - investment) / investment * 100

Cornerstone Project — Team Feedback & Mood Summary (step-by-step)

Build a tiny, office-friendly tool to summarize a weekly pulse survey. Colleagues rate their week (1–5) and add 1–3 tags. You’ll write small, testable functions and combine them into a useful report you can share in stand-up, retros, or 1:1s.

Step 1 — Define the input data

Start with a simple list of dicts (later you can load from CSV).

python
responses = [
    {"employee":"Ana","mood":4,"tags":["busy","deliverable"]},
    {"employee":"Bob","mood":3,"tags":["meetings","support"]},
    {"employee":"Carol","mood":5,"tags":["win","collaboration","product"]},
    {"employee":"David","mood":2,"tags":["bugs","deadlines"]},
]

Step 2 — Write tiny, pure helper functions

Pure functions (no I/O) are easy to trust and reuse.

python
from typing import Iterable, Sequence, Dict, Any
from collections import Counter

def safe_average(nums: Iterable[float]) -> float:
    vals = [n for n in nums if isinstance(n, (int, float))]
    return round(sum(vals) / len(vals), 2) if vals else 0.0

def mood_label(score: float) -> str:
    if score >= 4: return "😊 Positive"
    if score >= 3: return "😐 Neutral"
    return "😟 Needs Attention"

def top_items(counter: Counter, n: int = 3):
    return counter.most_common(n)

Step 3 — Build the core summary function

Combine the helpers. Return a structured dict (easy to display or export).

python
def feedback_summary(rows: Sequence[Dict[str, Any]]) -> Dict[str, Any]:
    # Extract moods
    moods = [r.get("mood") for r in rows]
    avg = safe_average(moods)

    # Count tags
    tag_counts = Counter()
    for r in rows:
        for t in r.get("tags", []):
            tag_counts[t] += 1

    return {
        "average_mood": avg,
        "mood_label": mood_label(avg),
        "top_themes": top_items(tag_counts, n=3)
    }

Step 4 — Call it and print a friendly report

Keep printing outside the function so logic stays reusable.

python
report = feedback_summary(responses)

print("Team Mood Report")
print("-----------------")
print("Average mood:", report["average_mood"], report["mood_label"])
print("Top themes:")
for tag, count in report["top_themes"]:
    print(f" • {tag}: {count}")

Step 5 — Optional: Add a simple recommender

Map common pain tags to suggested actions (all plain functions).

python
SUGGESTIONS = {
    "meetings": "Try a focus block (no meetings) 2–4pm, Tue–Thu.",
    "bugs": "Schedule a bug bash and triage the top 5.",
    "deadlines": "Break into milestones; negotiate scope cut if needed.",
    "support": "Create a rotating on-call schedule to spread load.",
}

def suggest_actions(top_themes: list[tuple[str, int]]) -> list[str]:
    out = []
    for tag, _ in top_themes:
        if tag in SUGGESTIONS:
            out.append(f"{tag}: {SUGGESTIONS[tag]}")
    return out

actions = suggest_actions(report["top_themes"])
if actions:
    print("\nSuggested actions:")
    for a in actions:
        print(" •", a)

How this helps at work

  • Repeatable: paste weekly results, re-run, share insights in seconds
  • Actionable: turns vague sentiment into a clear weekly plan
  • Portable: later swap responses for CSV/JSON without changing functions

Key Takeaways

  • Functions turn repeated steps into reliable, reusable tools
  • Return values over prints → easier testing & composition
  • Docstrings & type hints make intent clear to teammates & IDEs
  • Small pure helpers + one orchestrator function = maintainable design
  • Cornerstone: a practical team pulse tool you can actually use this week

Next Steps

You've mastered functions. Next, explore modules & packages to organize functions into libraries, or dive into error handling to make your functions robust against bad input.