Starred unpacking
The gotcha
* and ** in assignment, function calls, and (since 3.5) literals do different things in different positions. A few subtle rules trip people up.
Minimal repro
Assignment
a, *b, c = [1, 2, 3, 4, 5]
print(a, b, c) # 1 [2, 3, 4] 5
# `*b` is always a list — even if it captures one element or zero:
a, *b = [1]
print(b) # [] (not None)
a, *b, c = [1, 2]
print(b) # [] (a=1, c=2)
Function definitions
def f(a, *b, c, **d):
# *b: variable positional → tuple
# c is keyword-only because it comes after *b
# **d: variable keyword → dict
...
f(1, 2, 3, c=10, x=1, y=2)
# a=1, b=(2, 3), c=10, d={'x': 1, 'y': 2}
Function calls
def f(a, b, c): ...
args = [1, 2, 3]
f(*args) # spreads: f(1, 2, 3)
kwargs = {"a": 1, "b": 2, "c": 3}
f(**kwargs) # spreads as keywords
# Combining:
f(1, *[2], **{"c": 3}) # legal
Literal merging (3.5+)
[*a, *b] # concat lists into a new list
{*a, *b} # union of sets
{**a, **b} # merge dicts (right wins on key conflict)
(*a, *b) # tuple of concatenated
Forbidden / surprising
# Multiple stars in target — illegal:
*a, *b = [1, 2, 3] # SyntaxError: multiple starred expressions in assignment
# Star without context — illegal:
*a = [1, 2, 3] # SyntaxError
# Star in dict literal must be **:
{*a: 1} # SyntaxError, you'd need {**other_dict, "a": 1}
**kwargs consumes only str keys (when calling)
def f(**kw): ...
f(**{"a": 1}) # ok
f(**{1: "x"}) # TypeError: keywords must be strings
Why it matters
Used heavily in: function wrappers (def wrap(*args, **kwargs)), partial application, dict merging in factories, splatting tuples into iterables.
How to avoid mistakes
- Remember:
*in target always produces a list; in function call it spreads. - Remember:
**kwargsis a dict in the function, but a spread when calling. - Keyword-only args after
*are a feature — use them to force named arguments:
def fetch(url, *, timeout=10, retries=3):
# caller MUST write fetch("...", timeout=5)
...
Interview angle
“What does a, *b, c = range(2) do?” (ValueError: not enough values to unpack — needs at least 2 values, but *b requires at least 0, so this needs at least 2: a and c). Or “What’s the difference between def f(a, b) and def f(a, *, b)?”