# Unpacking

``````def foo(a, b):
print(a, b)

x = [1, 2]
foo(*xs)  # Unpacks the values in x into positional args.
# As if you'd called
foo(1, 2)

d = {'a': 1, 'b': 2}
foo(**d)  # Unpacks into param `d`, a dict.
# As if you'd called
foo(a=1, b=2)``````

Writing `def foo(*args) ...` creates a function that accepts zero or more positional args, slurping them all into a list:

``````def foo(*stuff):
print(stuff)

x = [1, 2]
foo(*x) # Unpacks `x`, and prints out `[1, 2]`.
# Works as if you'd called
foo(1, 2)``````

This effectively unpacks x, then re-packs it into the `stuff` param in the body of the function.

Writing `def foo(**named) ...` creates a function that accepts zero or more named args, and which then slurps them all into a dict:

``````def foo(**named):
print(named)

# foo(1, 2, 3)      # ERROR
foo(a=1, b=2, c=3)  # prints out a dict

# And note:
d = {'a': 11, 'b': 12, 'c': 13}
foo(**d)
# Works as if you'd called
foo(a=11, b=12, c=13)``````

This effectively unpacks `d` into keyword-args, then repacks it into a dict (the `named` param) in the body of the function.

* * *

This is all separate from the other type of unpacking (“extended iterable unpacking”):

``a, *b, c = [1, 2, 3, 4, 5]  # `b` gets `[2, 3, 4]`.``

There’s no `**whatever` (“named args”-style) syntax for this kind of unpacking.