Unpacking with * and **
Spread sequences and mappings with * and ** — in calls, assignments, literals and returns.
The * and ** operators do double duty. In a function definition they collect arguments (that is *args/**kwargs). In an expression they do the opposite: they unpack a sequence or mapping into its parts.
Star unpacking in assignment
Grab the ends and keep the middle in one line — the starred name always becomes a list:
first, *middle, last = [1, 2, 3, 4, 5]
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5Spreading into literals and calls
- Merge lists:
[*a, *b]. Merge dicts:{**a, **b}(later keys win). - Forward arguments:
func(*args, **kwargs). - Build a call from data:
point(*coords)unpacks a tuple into positional arguments.
Dict merging with {**a, **b} is the clean, non-mutating way to combine configurations — the original dictionaries are untouched.
Example
When to use it
- A function call uses **config_dict to pass a dictionary of settings as keyword arguments.
- A catch-all unpacking assigns the first and last items of a list to variables, collecting the middle with *.
- Two lists are merged inline using [*list_a, *list_b] to build a combined list without mutating either.
More examples
Extended iterable unpacking with *
Uses * to collect all middle elements into a list while binding the ends to named variables.
first, *middle, last = [1, 2, 3, 4, 5]
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5Merge lists and dicts inline
Spreads two lists into a new list and merges two dicts, with the later dict winning on duplicate keys.
a = [1, 2, 3]
b = [4, 5, 6]
combined = [*a, *b]
print(combined) # [1, 2, 3, 4, 5, 6]
defaults = {'timeout': 30, 'retries': 3}
overrides = {'timeout': 10}
config = {**defaults, **overrides}
print(config) # {'timeout': 10, 'retries': 3}Unpack into function arguments
Unpacks a dict as keyword arguments and a tuple as positional arguments in function calls.
def connect(host, port, timeout):
print(f'Connecting to {host}:{port} (timeout={timeout}s)')
params = {'host': 'db.local', 'port': 5432, 'timeout': 10}
connect(**params)
# Connecting to db.local:5432 (timeout=10s)
args = ('cache.local', 6379, 5)
connect(*args)
# Connecting to cache.local:6379 (timeout=5s)
Discussion