In order to show how unpacking works in Python, we are going to play with this function.
def f (x, y, z) :
return [x, y, z]
t = (3, 4) # This a tuple aka a sequence of immutable Python objects.
Unpacking Argument Lists
Since items in Python lists need not be of the same type, we are able to pass in the tuple t as an argument for our function f.
assert f(2, t, 5) == [2, (3, 4), 5]
assert f(2, 5, t) == [2, 5, (3, 4)]
Alternatively, you can use the asterisk notation to pass a tuple in as a variable number of arguments.
assert f(2, *t) == [2, 3, 4]
assert f(z = 2, *t) == [3, 4, 2] # Values for X and Y are passed in through the tuple!
assert f(*t, z = 2) == [3, 4, 2] # Values for X and Y are passed in through the tuple!
Before you get carried away with function unpacking, remember a few of key items:
- provide the correct amount of arguments needed (after unpacking)
- following an arbitrary argument, you can only pass named arguments
- arbitrary arguments will try to fill function arguments in order therefore may conflict with named arguments
The following are examples of what NOT to do:
f(*t) # TypeError: f() missing 1 required positional argument: 'z'
f(2, 3, *t) # TypeError: f() takes 3 positional arguments but 4 were given
f(*t, 2) # SyntaxError: only named arguments may follow *expression
f(x = 2, *t) # TypeError: f() got multiple values for argument 'x'
Unpacking Keyword Arguments
note: kwarg == keyword argument
def f (x, y, z) :
return [x, y, z]
d = {"z" : 4, "y" : 3, "x" : 2}
Dictionaries can be "unpacked" by using the double asterisk notation. In this case, we are providing values for XYZ through our argument dictionary.
assert f(**d) == [2, 3, 4]
When doing this make sure to only pass in the required arguments so as to avoid providing multiple values for a single argument.
f(2, **d) # TypeError: f() got multiple values for argument 'x'
f(x = 2, **d) # TypeError: f() got multiple values for keyword argument 'x'
d = {"z" : 4, "y" : 3}
assert f(2, **d) == [2, 3, 4]
After passing in a dictionary of keyword arguments, you can only pass in other named arguments.
# f(**d, 2) # SyntaxError: invalid syntax
assert f(x = 2, **d) == [2, 3, 4]
assert f(**d, x = 2) == [2, 3, 4]
d = {"y" : 3}
assert f(2, z = 4, **d) == [2, 3, 4]
assert f(2, **d, z = 4) == [2, 3, 4]
Use args and *kwargs together
Argument lists and keyword argument dictionaries are most useful when combined, the following examples show the proper combinations of how to use them together.
t = (3,)
d = {"z" : 4}
assert f(2, *t, **d) == [2, 3, 4]
assert f(y = 3, *t, **d) == [3, 3, 4]
assert f(*t, y = 3, **d) == [3, 3, 4]
assert f(*t, **d, y = 3) == [3, 3, 4]
# Bad Example, remember that argument lists try to fill arguments out in order.
assert f(x = 2, *t, **d) == [2, 3, 4] # TypeError: f() got multiple values for argument 'x'