Python 101Free
FUNCTIONS

Arguments

All the ways to pass values into a function.

SECTION 01

Positional vs keyword

By default, arguments bind to parameters by position. greet("Ada", "hi") matches the first parameter to "Ada" and the second to "hi". The order matters and Python does not check whether the values look right for their slots.

Keyword arguments bind by name. greet(greeting="hi", name="Ada") ignores the order and assigns each value to the matching parameter. This is more verbose but lets the call document itself, which is worth a lot in functions with several parameters.

A call can mix the two, but positional arguments must come before keyword ones. The general rule is: positional for the obvious values, keyword for anything where order is not self-evident or where you want to skip past defaults.

python
def greet(name, greeting="hi"):
    return f"{greeting}, {name}"

greet("Ada")                       # by position
greet(name="Ada", greeting="yo")   # by name, any order
SECTION 02

Default values

Parameters can have defaults. def greet(name, greeting="hello"): lets the caller skip the second argument, and the function still works. Defaults are how you make functions backwards-compatible when you add new parameters later.

The trap is that defaults are evaluated once, at function-definition time, not on each call. If you write def push(item, lst=[]):, every call that omits lst shares the same list object. Successive calls keep growing the same default list, which is rarely what you want.

The fix is to default to None and create a fresh container inside the body: def push(item, lst=None): if lst is None: lst = []. This pattern looks awkward but is the standard way to avoid the trap.

python
def push(item, lst=[]):    # BUG: default list is shared
    lst.append(item)
    return lst

push(1)   # [1]
push(2)   # [1, 2]   surprise!

def push(item, lst=None):  # fix
    if lst is None:
        lst = []
    lst.append(item)
    return lst
SECTION 03

args and kwargs

*args in a parameter list collects any extra positional arguments into a tuple. **kwargs collects any extra keyword arguments into a dict. The names are convention; what matters is the single and double star.

This is how you write functions that accept a variable number of arguments without writing a separate function per arity. print itself uses *args, which is why it can take any number of values to print.

The star also works at the call site. f(*items) unpacks items into separate positional arguments, and f(**opts) unpacks opts into separate keyword arguments. The symmetry between the two ends is what makes the feature easy to remember.

python
def log(*args, **kwargs):
    print(args, kwargs)

log(1, 2, level="warn")
# (1, 2) {'level': 'warn'}

row = ["Ada", 92]
log(*row)   # unpack at the call site
← PREVIOUS
Defining Functions
NEXT →
Scope and Closures