Parameter Packs

12_parameter_packs

Parameter Packs

  • Star Args: *some_sequence
  • Star Star Key Wargs: **some_dictionary
  • Keyword Only Arguments

Star Args

Let’s say we have a function that takes *args as its only argument. Let’s also say that we have a sequence of values that we would like to pass to this function. The function is expecting several input arguments, but it wants them individually, and not as a sequence. How do we unpack a sequence into its constituent parts? Obviously we could solve this by changing the function so that it takes a sequence, but lets say we can’t do that – maybe the function is in a library that we do not control.

In [0]:
def some_func(*args):
    return sum(args)
In [0]:
param_pack = (2, 5, 10)

print(some_func(*param_pack))
17

Star Star Key Wargs

This same idea can be extended to dictionaries and a functions that take **kwargs as input. We just use two stars. A single star would give us a sequence of keys, but two stars will give us the key-value pairs we’re looking for.

In [0]:
def print_name_age(**kwargs):
    for name, age in kwargs.items():
        print(name, age)
In [0]:
named_params = {
    "Joe": 42,
    "Jim": 73,
    "Jane": 21,
    "Kim": 84,
}

print_name_age(**named_params)
Joe 42
Jim 73
Jane 21
Kim 84

Keyword Only Arguments

Lets say we want to design a function that takes a keyword-only argument. The reason we might want to do this is to reduce the likelihood of our users sending arguments in the wrong order. This can be handy for functions that have a variety of valid calling signatures. First a simple example:

In [0]:
def keyword_only(*, magic_word):
    print(magic_word)
keyword_only("alpha")

This doesn’t work!

TypeError: keyword_only() takes 0 positional arguments but 1 was given
In [0]:
keyword_only(magic_word="Alacasam")
Alacasam

Complex Example

Below we have a function that can take an unbounded number of positional arguments plus one keyword argument name. It will sum the positional args and output a tuple – the total and a greeting. This is a contrived example but I hope you can see the power this gives the function designer. It allows us to disambiguate potentionally hazardous calling signatures.

Note that the keyword-only argument must come after the star args in the function definition. If instead if we put the name parameter first it would be a positional argument – and therefore it would be optional and easily confussed with our other arguments.

In [0]:
def nums_n_name(*nums, name):
    return sum(nums), f"Hello, {name}"
In [0]:
print(nums_n_name(1, 2, 3, 4, name="Yoda"))
(10, 'Hello, Yoda')