Arguments and Unpacking
Master parameter kinds, defaults, variadic calls, and iterable or mapping unpacking.
Python function signatures can express which arguments may be positional, which must be named, and how extra arguments are collected. Unpacking provides the inverse operation: it distributes an iterable or mapping into separate targets or arguments.
Positional and keyword arguments
def describe(name, role):
return f"{name} is a {role}."
describe("Ada", "programmer") # positional
describe(name="Ada", role="programmer") # keyword
describe("Ada", role="programmer") # mixedPositional arguments come before keyword arguments. A parameter must not receive more than one
value, so describe("Ada", name="Grace") raises TypeError.
Keyword arguments improve clarity when values are easy to confuse:
round(3.14159, ndigits=2)Defaults
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Ada"))
print(greet("Ada", greeting="Welcome"))Parameters without defaults must precede parameters with defaults in the same section of a signature.
Default values are evaluated once when def executes, not once per call. Never use a mutable
default for per-call state:
def add_tag(tag, tags=None):
if tags is None:
tags = []
tags.append(tag)
return tagsUse an immutable default directly when it accurately represents the default.
The five parameter kinds
A signature can contain:
- positional-only parameters before
/; - positional-or-keyword parameters;
- variadic positional parameters collected by
*args; - keyword-only parameters after
*or*args; - variadic keyword parameters collected by
**kwargs.
def report(
title,
/,
records,
*formats,
verbose=False,
**metadata,
):
print(title, records, formats, verbose, metadata)Example call:
report(
"Quarterly results",
[10, 12],
"text",
"json",
verbose=True,
owner="Ada",
)Here:
"Quarterly results"must be positional.recordsmay be positional or keyword.- extra positional values become the tuple
formats. verbosemust be passed by keyword.- extra keyword pairs become the dictionary
metadata.
When to constrain arguments
Positional-only parameters are useful when parameter names are implementation details or when the API naturally accepts a value, as many built-ins do.
Keyword-only parameters make options self-documenting:
def connect(host, port, *, timeout=10, use_tls=True):
...
connect("example.com", 443, timeout=5, use_tls=True)Use bare * when no *args collection is needed. This prevents unclear calls such as
connect("example.com", 443, 5, True).
*args and **kwargs
Inside a function, args is a tuple and kwargs is a dictionary:
def total(*numbers):
return sum(numbers)
print(total(2, 3, 5)) # 10def build_profile(name, **attributes):
return {"name": name, **attributes}
profile = build_profile("Ada", city="London", active=True)The names args and kwargs are conventions; the * and ** define the behavior.
Do not add variadic parameters merely to seem flexible. Explicit parameters provide better documentation, validation, editor support, and error messages. Use variadics when the number of values is genuinely open or when forwarding an established interface.
Unpacking in calls
* expands an iterable into positional arguments:
dimensions = (4, 3)
print(pow(*dimensions)) # 64: equivalent to pow(4, 3)** expands a string-keyed mapping into keyword arguments:
options = {"greeting": "Welcome"}
print(greet("Grace", **options))Keys must match accepted parameter names unless the function collects **kwargs. Duplicate
values still raise TypeError.
Assignment unpacking and destructuring
Unpacking binds parts of an iterable to names:
name, score = ("Ada", 98)
first, *rest = [10, 20, 30, 40]
*beginning, last = range(5)
print(rest) # [20, 30, 40]
print(beginning) # [0, 1, 2, 3]The starred assignment target always receives a list. Without a starred target, the number of values must match exactly.
Nested destructuring follows the data shape:
name, (x, y) = ("Ada", (4, 7))Ignore an intentionally unused value by convention with _:
filename, _, extension = "report.final.pdf".rpartition(".")_ is still a normal name; use it only when the value is genuinely irrelevant.
Unpacking collections
Create new collection values:
base = [1, 2]
combined = [0, *base, 3]
defaults = {"theme": "light", "size": 20}
custom = {"theme": "dark"}
settings = {**defaults, **custom}
coordinates = (0, *(4, 7))Later dictionary entries overwrite earlier duplicate keys. The | merge operator is often more
direct for dictionaries, while ** is useful inside a larger dictionary display.
Forwarding arguments
Wrappers sometimes preserve another function's call shape:
def logged_call(function, *args, **kwargs):
print(f"Calling {function.__name__}")
return function(*args, **kwargs)Forwarding is powerful but can obscure an API. For public wrappers, consider an explicit
signature or advanced tools such as functools.wraps and typing.ParamSpec.
Common mistakes
- Using a list or dictionary as a default argument.
- Passing a positional argument after a keyword argument.
- Supplying one parameter both directly and through
**kwargs. - Assuming
*argsis a list; it is a tuple. - Accepting
**kwargsand silently ignoring misspelled options. - Unpacking the wrong number of values.
- Overusing positional arguments for boolean or numeric options.
Decision guidance
- Keep essential inputs positional-or-keyword unless the API benefits from a stronger rule.
- Make optional behavior keyword-only when names prevent ambiguity.
- Use positional-only parameters rarely and intentionally for stable public APIs.
- Use
*argsfor a genuinely variable sequence and**kwargsfor genuinely extensible named options or careful forwarding. - Use destructuring when the data has a small, obvious shape; avoid it when positions are hard to remember.
- Prefer explicit signatures over catch-all flexibility.
Practice
- Write
format_name(first, last, *, uppercase=False)and call it both ways. - Write
product(*numbers)with an identity result of1for no arguments. - Merge default and user settings so user values win.
- Unpack the first, middle, and last values from a five-item sequence.
- Design a signature with positional-only data and keyword-only formatting options, then explain why each constraint helps.
LEARNING RECORD
Finish this lesson
Mark it complete when you can explain the main decision without looking.
KNOWLEDGE CHECK