## Python Function Unpacking ( *args and **kwargs )

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'
```
Archive