channel_summary hands you a dict of totals — spend, leads, CPL per channel. Now the CMO wants those printed as ranked lines for the weekly report. How would you start?
channel_summary gives me a dict keyed by channel — total spend, leads, CPL per key. I'd loop it and build an f-string for each row: rank, channel name, spend with commas, leads, CPL. Except I've written basically this exact format in Day 5, Day 11, Day 14...
You just named the problem. Same formatting logic, three different places. In Excel, what do you do when you find yourself re-entering the same formula across a dozen cells?
I name it — wrap it in a macro so I write the logic once and call it everywhere.
That's a function. def is the keyword that names a block of logic. Parameters are the inputs. return hands the result back to whoever called it. The triple-quoted string right below the def line — the docstring — is the one-sentence note to your future self about what it does:
def make_report_line(channel: str, stats: dict, rank: int) -> str:
"""Return a ranked report line for one channel."""
spend = stats["total_spend"]
leads = stats["total_leads"]
cpl = stats["avg_cpl"]
result = f"#{rank} {channel} — Spend: ${spend:,} | Leads: {leads} | CPL: ${cpl:.2f}"
return resultWhere exactly does the docstring go — and does Python actually read it, or is it just a comment?
Python reads it — it becomes the function's __doc__ attribute, shown by help(). It sits on the very first line inside the function, before any other code. A # comment is invisible to Python's object model; a docstring is attached to the function itself. Once the function exists, you can call it with keyword arguments and every argument is labelled:
stats = {"total_spend": 12400, "total_leads": 52, "avg_cpl": 238.46}
line = make_report_line(channel="Paid Search", stats=stats, rank=1)
print(line) # #1 Paid Search — Spend: $12,400 | Leads: 52 | CPL: $238.46Named arguments — so I can read the call site without scrolling up to check the parameter order. format_campaign, format_kpi_line, make_report_line — they're all the same shape. I could drop them in one file and import them.
Future-you will send present-you a thank-you note. That file with a collection of related functions has a name: a module. The pattern you've been assembling this week, without knowing the word for it, is a reporting library.
def, Parameters, return, DocstringsA function packages logic under a name you can call anywhere.
def name(param: type, ...) -> return_type:
"""One-sentence purpose."""
# body
return value
| Part | What it does |
|---|---|
def | Declares the function and its name |
| Parameters | Named inputs — received as local variables in the body |
| Docstring | First string in the body — attached to __doc__, shown by help() |
return | Sends a value back to the caller; without it, the function returns None |
make_report_line(channel="Paid Search", stats=s, rank=1) — names each argument, documents intent, survives parameter reordering.
channel_summary hands you a dict of totals — spend, leads, CPL per channel. Now the CMO wants those printed as ranked lines for the weekly report. How would you start?
channel_summary gives me a dict keyed by channel — total spend, leads, CPL per key. I'd loop it and build an f-string for each row: rank, channel name, spend with commas, leads, CPL. Except I've written basically this exact format in Day 5, Day 11, Day 14...
You just named the problem. Same formatting logic, three different places. In Excel, what do you do when you find yourself re-entering the same formula across a dozen cells?
I name it — wrap it in a macro so I write the logic once and call it everywhere.
That's a function. def is the keyword that names a block of logic. Parameters are the inputs. return hands the result back to whoever called it. The triple-quoted string right below the def line — the docstring — is the one-sentence note to your future self about what it does:
def make_report_line(channel: str, stats: dict, rank: int) -> str:
"""Return a ranked report line for one channel."""
spend = stats["total_spend"]
leads = stats["total_leads"]
cpl = stats["avg_cpl"]
result = f"#{rank} {channel} — Spend: ${spend:,} | Leads: {leads} | CPL: ${cpl:.2f}"
return resultWhere exactly does the docstring go — and does Python actually read it, or is it just a comment?
Python reads it — it becomes the function's __doc__ attribute, shown by help(). It sits on the very first line inside the function, before any other code. A # comment is invisible to Python's object model; a docstring is attached to the function itself. Once the function exists, you can call it with keyword arguments and every argument is labelled:
stats = {"total_spend": 12400, "total_leads": 52, "avg_cpl": 238.46}
line = make_report_line(channel="Paid Search", stats=stats, rank=1)
print(line) # #1 Paid Search — Spend: $12,400 | Leads: 52 | CPL: $238.46Named arguments — so I can read the call site without scrolling up to check the parameter order. format_campaign, format_kpi_line, make_report_line — they're all the same shape. I could drop them in one file and import them.
Future-you will send present-you a thank-you note. That file with a collection of related functions has a name: a module. The pattern you've been assembling this week, without knowing the word for it, is a reporting library.
def, Parameters, return, DocstringsA function packages logic under a name you can call anywhere.
def name(param: type, ...) -> return_type:
"""One-sentence purpose."""
# body
return value
| Part | What it does |
|---|---|
def | Declares the function and its name |
| Parameters | Named inputs — received as local variables in the body |
| Docstring | First string in the body — attached to __doc__, shown by help() |
return | Sends a value back to the caller; without it, the function returns None |
make_report_line(channel="Paid Search", stats=s, rank=1) — names each argument, documents intent, survives parameter reordering.
Harper's marketing team uses `channel_summary` to build a dict of totals per channel. Now they need each entry formatted as a ranked one-liner for the weekly report. Write `make_report_line(channel, stats, rank)` that takes a channel name string, a stats dict with `"total_spend"`, `"total_leads"`, and `"avg_cpl"` keys, and an integer rank, and returns a string like `"#1 Paid Search — Spend: $12,400 | Leads: 52 | CPL: $238.46"`. Include a docstring. Use `:,` for spend (no decimals) and `:.2f` for CPL.
Tap each step for scaffolded hints.
No blank-editor panic.