DSM
50 XP
25 minsBeginner50 XP

Default & Keyword Arguments

You've already read this line in the wild: pd.read_csv('data.csv', sep=';', header=0). One required argument, two NAMED ones, and a dozen more silently using sensible defaults. That calling style is not pandas magic — it's two plain Python features you're about to own.

What you'll learn

  • Define parameters with default values
  • Call functions with keyword arguments in any order
  • Order parameters correctly: required first, defaults after
  • Avoid the mutable default argument trap
  • Read library signatures like read_csv fluently

What

A default argument gives a parameter a fallback value in the def, making it optional at the call. A keyword argument is passed as name=value, matching by NAME instead of position.

Why

Real functions accumulate options. Without defaults, every caller passes everything, every time. Without keywords, calls become unreadable positional soup — round(3.14159, 2) is fine, but plot(data, True, False, 0.8, 'red') is a quiz. Defaults + keywords are how Python APIs stay humane at scale.

Where it's used

Every data library call you'll ever write: read_csv's 50 optional parameters, train_test_split(test_size=0.2), plt.plot(alpha=0.5), sorted(key=..., reverse=True).

Where this runs in production

pandasread_csv's 50 defaults

read_csv has one required parameter and roughly fifty optional ones — sep=',', header='infer', encoding=None. Millions of users pass only what they need; defaults do the rest.

AnthropicAPI client parameters

SDK calls like client.messages.create(model=..., max_tokens=1024, temperature=0.7) rely on keyword arguments so code reads as configuration, not a puzzle of positions.

MatplotlibChart styling

plt.plot(x, y, color='steelblue', linewidth=2, alpha=0.8) — positional data, keyword styling. The split you'll use in the visualization course daily.

Theory

The core ideas, in plain language.

A default is declared in the def: `def connect(host, timeout=30):`. Callers may omit timeout (getting 30) or supply their own. One rule of order: parameters WITH defaults must come after parameters without — Python enforces it with a SyntaxError, because otherwise it couldn't tell which positional argument belongs where.
def format_price(amount, currency='USD', decimals=2):
    return f'{amount:.{decimals}f} {currency}'

print(format_price(49.5))                 # both defaults
print(format_price(49.5, 'EUR'))          # positional override
print(format_price(49.5, decimals=0))     # keyword skips currency

Three call styles against one definition. The last line is the point: keywords let you override the SECOND default without touching the first — impossible with positions alone.

Analogy: The coffee order

A café order form has defaults: medium size, whole milk, no extra shot. Regulars just say 'a latte' — defaults apply. Custom orders name only what changes: 'a latte, oat milk'. Nobody recites every option in a fixed order, and the barista never guesses which unlabeled word meant the milk. Keyword arguments are ordering coffee like a human.

Key Concept
Keywords match by name — order stops mattering

split_data(df, test_size=0.2, shuffle=True) and split_data(df, shuffle=True, test_size=0.2) are identical calls. Naming eliminates the silent-swap bug from last lesson AND documents the call site: six months later, test_size=0.2 still explains itself where a bare 0.2 wouldn't. Convention: positional for the obvious core data, keywords for options.

Mixing rules: positional arguments must come before keyword arguments in a call — f(1, x=2) is legal, f(x=2, 1) is a SyntaxError. And each parameter gets exactly one value: f(1, amount=1) where amount is the first parameter raises 'got multiple values for argument'.
Watch out
The mutable default trap

Default values are evaluated ONCE, at definition time — not per call. Harmless for numbers and strings, but `def add_row(row, table=[]):` creates ONE shared list reused by every call that omits table: rows from different calls pile into the same list. The standard fix: default to None and create fresh inside — `def add_row(row, table=None): if table is None: table = []`. This is a favorite interview question because it looks like magic until you know the one-evaluation rule.

Visual Learning

See the concept, then explore it.

How arguments find their parameters

One call — report(sales, 'Q3', top_n=5) — resolved step by step. Click each node.

Select a type to see its full definition, operations, and data science usage.

Worked Examples

Watch it built up, one line at a time.

Very EasyOne default parameter

A greeting utility where the greeting word is optional.

Step 1 of 2

name is required; greeting falls back to 'Hello'. Required-then-default order is mandatory.

Code
01def greet(name, greeting='Hello'):
02 return f'{greeting}, {name}!'
Practice Coding

Your turn — write the code.

Your task

Build a notification formatter for an alerting system. Define format_alert(message, level='INFO', repeat=1) that uppercases the level, prefixes it in brackets, and repeats the line `repeat` times separated by newlines. Produce the three outputs shown using defaults and keywords appropriately.

Expected output
[INFO] backup finished
[WARN] disk almost full
[INFO] service down
[INFO] service down

Write your solution in the editor on the right, then hit Run.

Exercises

Prove it. Reach 80% to complete the lesson.

Mastery Gate0% / 80% required
Easy0/2 solved

Which definition is a SyntaxError?

def resize(img, width=100, height=100): ... — which call sets ONLY height to 50?

Medium0/3 solved

What does this print? def append_log(entry, log=[]): log.append(entry) return log append_log('a') print(append_log('b'))

ScenarioYour team's plotting helper is called as make_chart(df, True, False, 0.5, 'tab10') all over the codebase. A new hire just spent an hour discovering that the third positional argument means 'log scale'.

What convention prevents this?

Define paginate(items, page_size=3) that returns the FIRST page (a list of at most page_size items). Print paginate([1,2,3,4,5,6,7]) and paginate([1,2,3,4,5,6,7], page_size=5). Expected: [1, 2, 3] [1, 2, 3, 4, 5]

Default applies:The first call must use page_size 3 without passing it
Keyword override:The second call overrides page_size by name
Hard0/2 solved

def f(a, b=2): ... — what does f(1, a=3) raise?

ScenarioYou maintain fetch_data(url) used in 80 places. You need optional caching. A colleague proposes fetch_data_cached(url) as a second function; you propose adding a parameter.

Which change keeps all 80 call sites working AND why?

Complete 80% more exercises to unlock.
Interview Prep

How this shows up in real interviews.

Explain the mutable default argument problem and the standard fix.

Show model answer

Default values are evaluated exactly once, when the def statement executes — not on each call. For immutable defaults (numbers, strings, None) that's invisible. But a mutable default like [] or {} becomes a single object SHARED by every call that omits the argument: append to it in one call and the next call sees the leftovers, so state leaks between supposedly independent calls. The standard fix is the None sentinel: declare param=None, and inside the body write `if param is None: param = []` to build a fresh object per call. The follow-up worth volunteering: the same one-evaluation rule means a default like timestamp=now() freezes the time at import — dynamic defaults always belong inside the body.

When do you pass arguments positionally versus by keyword? What convention do major libraries follow?

Show model answer

The working convention: positional for the essential data whose meaning is unmistakable — the DataFrame, the file path, the (x, y) pair — and keywords for everything optional or configuration-like. Keywords buy three things: the call documents itself (test_size=0.2 needs no comment), argument order can't silently swap same-typed values, and you can override the fifth option without restating the four before it. Libraries like pandas and scikit-learn follow exactly this — read_csv(path, sep=';') — and increasingly enforce it by making options keyword-only, so plot(data, True, False) simply won't run. My personal rule: any boolean or any second same-typed argument gets a name.

You need to add an option to a function with dozens of existing call sites. Walk me through doing it safely.

Show model answer

Add a new parameter with a default that exactly reproduces the current behavior — fetch_data(url, use_cache=False) where all existing behavior corresponds to False. Every current call continues to compile and behave identically because the default fills the gap; only new call sites name the option to opt in. That's backwards-compatible API evolution, and it's how read_csv accumulated fifty options over a decade without a breaking release. Things I'd check in review: the default really is behavior-preserving (not just plausible), the new parameter goes after existing ones so positional callers are unaffected, and documentation states the default. The anti-patterns to name: creating fetch_data_v2 (forks maintenance) and changing the parameter order (breaks every positional call silently).

Common Mistakes to Avoid

1) Mutable defaults (=[] or ={}) — shared across calls; use the None sentinel. 2) Required parameter after a defaulted one — SyntaxError at definition. 3) Positional arguments after keyword ones in a call — SyntaxError. 4) Passing a value both positionally and by keyword — 'multiple values' TypeError. 5) Boolean flags passed positionally (f(df, True, False)) — legal, unreadable; name them. 6) Dynamic defaults evaluated at def time (timestamp=now()) — compute inside the body instead.

Ask the AI Tutor

Try these prompts in the AI Tutor panel: • 'Quiz me on which of these six calls are legal and what they bind.' • 'Walk me through the mutable default trap with a fresh example.' • 'Show me read_csv's signature and explain five of its defaults.' • 'Help me redesign this positional-soup function signature.' • 'Interview mode: ask me how to evolve an API without breaking callers.'

Glossary

Default argument — a fallback value declared in the def, making the parameter optional. Keyword argument — an argument passed as name=value, matched by name. Positional argument — matched by order. Signature — a function's name plus its parameter list; the contract callers read. None sentinel — defaulting to None and creating the real (mutable) value inside the body. Keyword-only parameter — one that callers MUST name (enforced with * in the signature — you'll meet it next lesson). Backwards compatibility — new versions keeping old calls working. API surface — everything callers can see and depend on.

Recommended Resources

• Docs: 'Default Argument Values' and 'Keyword Arguments' in the official Python tutorial. • Read: the pandas read_csv API page — count how many defaults you now understand at a glance. • Practice: take a three-flag function you've written and convert every call site to keywords; feel the readability change. • Next in DSM: what if a function should accept ANY number of arguments? *args and **kwargs — the packing/unpacking machinery behind flexible signatures.

Recap

✓ Defaults in the def make parameters optional; required parameters always come first. ✓ Keywords match by name — order-proof, self-documenting, and able to skip earlier defaults. ✓ Positional for core data, keywords for options: the convention every major library follows. ✓ Mutable defaults are evaluated once and shared — use the None sentinel. ✓ Adding a behavior-preserving default is how APIs evolve without breaking callers. ✓ One value per parameter; positionals before keywords in every call. Next up: *args and **kwargs. Some functions must accept any number of arguments — packing and unpacking give you variable-length signatures and the ** trick you'll meet in every framework.

scratchpad — preview this lesson's challenge anytime
notify.pyPython
Ready
Output

Run your code to see the output here.