Function Arguments

Positional and keyword arguments, default values, and the mutable default that catches everyone once.

Overview

Positional and keyword

def greet(name, greeting="Hello"):

greet("ana") matches by position: the first argument becomes name. greet("ana", greeting="Hi") names the second explicitly. Both reach the same function; the difference is what the call site tells a reader.

Keywords earn their place when the value alone is meaningless. send(msg, True) tells you nothing; send(msg, urgent=True) tells you everything. A boolean argument is almost always worth naming.

One rule: in a call, positional arguments come first. f(greeting="Hi", "ana") is a syntax error, because Python cannot tell where the positional one was meant to go.

arguments.py

arguments.py Python 3
Output

                    

mutable_default.py

mutable_default.py Python 3
Output

                    

Worth knowing

Positional arguments are matched by order; keyword arguments by name.
In a call, every positional argument must come before any keyword one.
Defaults are evaluated once, at definition time - not on each call.
Never default to a list or dict. Default to None and build it inside.

Function Arguments: A Practical Guide

Python matches arguments to parameters two ways — by position and by name — and gives parameters default values. One of those defaults has a trap in it that every Python programmer meets exactly once.

Defaults

A parameter with a default becomes optional:

def greet(name, greeting="Hello", excited=False):

Callers supply what they care about and ignore the rest. Defaults must come after all non-default parameters, for the same reason: otherwise a positional call would be ambiguous.

The mutable default trap

This looks reasonable and is not:

def add_item(item, basket=[]):
    basket.append(item)
    return basket

Call it three times with no basket and you get one item, then two, then three — all in the same list. The reason is a single rule with a large consequence: default values are evaluated once, when the def runs, not on each call. That one list is created at definition time and reused forever, so every mutation accumulates.

The second program on this page prints the id of the default object before and after a call, to show it really is the same object rather than a new one that happens to have old contents.

The fix is idiomatic and worth memorising:

def add_item(item, basket=None):
    if basket is None:
        basket = []

None is immutable, so there is nothing to accumulate, and the fresh list is built inside the call where it belongs.

Immutable defaults — numbers, strings, True, None, tuples — are all safe. The rule is simply: never default a parameter to a list, dict or set.

Why this design

It would be possible to re-evaluate defaults on every call, and some languages do. Python evaluates once because a default is just an expression bound at definition time, like any other value in the enclosing scope. Once you know that, the behaviour stops being surprising — but it is worth knowing before it costs you an afternoon.

Check yourself

0 of 3

Answer without scrolling back up.

  1. When is a default argument value evaluated?

  2. What is the fix for `def f(items=[])`?

  3. Which call is a syntax error?

Cheat sheet

Function Arguments

Python matches arguments to parameters two ways — by position and by name — and gives parameters default values. One of those defaults has a trap in it that every Python programmer meets exactly once.

PYTHON · vizlearn.in/python/function_arguments.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.