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.
def greet():
return "Hello, World!" # return instead of printing
message = greet()
print(message) # calling the functionFunction Parameters and Return Values
Parameters are inputs; return sends a result back. Prefer returning structured data (e.g., dict) for clarity.
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.
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")) # keywordDefault & Keyword-Only Parameters
Use * to force keywords for clarity on optional knobs.
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.
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.
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.
items = ["aaa", "b", "cc"]
print(sorted(items, key=lambda s: len(s)))Functions Returning Functions
Use factories to create configured calculators.
def make_multiplier(k: float):
def mul(x: float) -> float:
return x * k
return mul
double = make_multiplier(2)
print(double(10)) # 20Docstrings & Type Hints
Explain purpose & types so IDEs and teammates understand intent.
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 * 100Cornerstone 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).
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.
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).
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.
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).
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.