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