• Get application security done the right way! Detect, Protect, Monitor, Accelerate, and more…
  • Python is the most used programming language. Today you’ll learn to use one of its core — but often ignored — features, unpacking in Python.

    You’ve probably seen * and ** in other’s code or even have used them without actually knowing what their purpose is. We’ll be walking through the concept of unpacking, and how to use it to write more Pythonic code.

    Here is a list of concepts that you’ll find useful while reading this tutorial:

    • Iterable: Any sequence that can be iterated by a for-loop, like sets, lists, tuples, and dictionaries
    • Callable: A Python object that can be called using double parenthesis (), for example, myfunction()
    • Shell: Interactive runtime environment which let us run Python code. We can call it by running “python” in a terminal
    • Variable: Symbolic name that stores an object and has a reserved memory location.

    Let’s start with the most frequent confusion: Asteristics in Python are also arithmetic operators. One asterisk (*) is used for multiplication, while two of them (**) refer to exponentiation.

    We can prove that by opening a Python shell and typing:

    >>> 3*3
    9
    >>> 3**3
    27
    

    Note: You need to have Python 3 installed to follow along with this tutorial. If you don’t have it installed check out our Python installation guide.

    As you can see, we’re using the asterisk after the first number and before the second one. When you see this, it means we’re using the arithmetic operators.

    On the other hand, we use the asterisks (*, **) before an iterable to unpack it — for instance:

    >>> *range(1, 6),
    (1, 2, 3, 4, 5)
    >>> {**{'vanilla':3, 'chocolate':2}, 'strawberry':2}
    {'vanilla': 3, 'chocolate': 2, 'strawberry': 2}
    

    Don’t worry if you don’t get it, this is just a preamble to unpacking in Python. So go ahead and read the entire tutorial!

    What’s unpacking?

    Unpacking is the process of getting out stuff — iterables such as lists, tuples, and dictionaries. Think of it as opening a box and getting out different items like cables, headphones, or a USB.

    Unpacking box image
    Unpacking in Python is similar to unpack a box in real life.

    Let’s translate this same example into code for a better understanding:

    >>> mybox = ['cables', 'headphones', 'USB']
    >>> item1, item2, item3 = mybox

    As you can see, we’re assigning the three items inside of the mybox list to three variables item1, item2, item2. This kind of variable assignment is the fundamental concept of unpacking in Python.

    If you try to get the value of each item, you’ll notice that item1, refers to “cables”, item2, refers to “headphones” and so on.

    >>> item1
    'cables'
    >>> item2
    'headphones'
    >>> item3
    'USB'

    Until here, everything seems to be just fine with this code, but what if we wanted to unpack a list with more elements in it — keeping the same amount of assigned variables?

    >>> newbox = ['cables', 'headphones', 'USB', 'mouse']
    >>> item1, item2, item3 = newbox
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: too many values to unpack (expected 3)

    It’s probably you expected this kind of error. Essentially we’re assigning 4 list items to three variables, how does Python manage to assign the right values?

    It doesn’t, that’s because we get a ValueError with the message “too many values to unpack”. This is happening because we’re setting three variables at the left, and four values (corresponding to the newbox list) at the right.

    If you try to do a similar process, but with more variables than values to unpack, you’ll get another ValueError except that with a slightly different message:

    >>> lastbox = ['cables', 'headphones']
    >>> item1, item2, item3 = lastbox
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: not enough values to unpack (expected 3, got 2)
    

    Note: We’ve been working with lists but you can use this form of unpacking with any iterable (lists, sets, tuples, dictionaries)

    So how do we overcome this situation? Is there any way to unpack all of the items of an iterable to a couple of variables without getting any errors?

    Sure there is, and it’s called unpacking operator or asterisk operator (*, **). Let’s see how to use it in Python.

    How to Unpack Lists With the * operator

    The asterisk operator (*) is used to unpack all the values of an iterable that have not been assigned yet.

    Let’s suppose you want to get the first and last element of a list without using indexes, we could do it with the asterisk operator:

    >>> first, *unused, last = [1, 2, 3, 5, 7]
    >>> first
    1
    >>> last
    7
    >>> unused
    [2, 3, 5]
    

    As you can appreciate, we get all the unused values with the asterisk operator. The preferred way to discard values is to use an underscore variable (_), which is sometimes used as a “dummy variable”.

    >>> first, *_, last = [1, 2, 3, 5, 7]
    >>> _
    [2, 3, 5]
    

    We can still use this trick even if the list only has two elements:

    >>> first, *_, last = [1, 2]
    >>> first
    1
    >>> last
    2
    >>> _
    []

    In this case, the underscore variable (dummy variable) stores an empty list so the other two variables around them can access the available values of the list.

    Common troubleshooting

    We can unpack a unique element of an iterable. For example, you’d come up with something like this:

    >>> *string = 'PythonIsTheBest'

    However, the above code will return a SyntaxError:

    >>> *string = 'PythonIsTheBest'
      File "<stdin>", line 1
    SyntaxError: starred assignment target must be in a list or tuple
    

    This because according to the PEP specification:

    A tuple (or list) on the left side of a simple assignment

    If we want to unpack all the values of an iterable to a single variable, we must set up a tuple, hence adding a simple comma will be enough:

    >>> *string, = 'PythonIsTheBest'
    >>> string
    ['P', 'y', 't', 'h', 'o', 'n', 'I', 's', 'T', 'h', 'e', 'B', 'e', 's', 't']
    

    Another example would be using the range function, which returns a sequence of numbers.

    >>> *numbers, = range(5)
    >>> numbers
    [0, 1, 2, 3, 4]
    

    Now that you know how to unpack lists and tuples with an asterisk, it’s time to get into unpacking dictionaries.

    How to Unpack Dictionaries With ** operator

    While a single asterisk is used to unpack lists and tuples, the double-asterisk (**) is used to unpack dictionaries.

    Unfortunately, we can’t unpack a dictionary to a single variable as we’ve been doing with tuples and lists. That means the following will throw an error:

    >>> **greetings, = {'hello': 'HELLO', 'bye':'BYE'} 
    ...
    SyntaxError: invalid syntax
    

    However, we can use the ** operator inside of callables and other dictionaries. For example, if we want to create a merged dictionary, made from other dictionaries, we could use the code below:

    >>> food = {'fish':3, 'meat':5, 'pasta':9} 
    >>> colors = {'red': 'intensity', 'yellow':'happiness'}
    >>> merged_dict = {**food, **colors}
    >>> merged_dict
    {'fish': 3, 'meat': 5, 'pasta': 9, 'red': 'intensity', 'yellow': 'happiness'}

    This is a pretty short way to create compound dictionaries, however, this isn’t the main approach of unpacking in Python.

    Let’s see how we can use unpacking with callables

    Packing in Functions: args and kwargs

    You’ve probably seen args and kwargs before either implemented on classes or functions. Let’s see why do we need to use them along with callables.

    Packing with the * operator (args)

    Suppose we have a function that calculates the product of two numbers.

    >>> def product(n1, n2):
    ...     return n1 * n2
    ... 
    >>> numbers = [12, 1]
    >>> product(*numbers)
    12
    

    As you can see we’re unpacking the list numbers to the function, so we’re actually running the following:

    >>> product(12, 1)
    12
    

    Until here, everything works just fine, but what if we wanted to pass a longer list? It’ll certainly raise an error because the function is receiving more arguments than it’s capable of manage.

    >>> numbers = [12, 1, 3, 4]
    >>> product(*numbers)
    ...
    TypeError: product() takes 2 positional arguments but 4 were given
    

    We can solve all of this just by packing the list directly on the function, which creates an iterable inside of it and allows us to pass any number of arguments to the function.

    >>> def product(*args):
    ...     result = 1
    ...     for i in args:
    ...             result *= i
    ...     return result
    ...
    >>> product(*numbers)
    144
    

    Here we’re treating the args parameter as an iterable, walking across its elements and returning the product of all the numbers. Note how the starting number of the result must be one because if we start with zero, the function will always return zero.

    Note: args is just a convention, you can use any other parameter name

    We could also pass arbitrary numbers to the function without using a list, just like with the built-in print function.

    >>> product(5, 5, 5)
    125
    >>> print(5, 5, 5)
    5 5 5

    Finally, let’s get the object type of the args of a function.

    >>> def test_type(*args):
    ...     print(type(args))
    ...     print(args)
    ... 
    >>> test_type(1, 2, 4, 'a string')
    <class 'tuple'>
    (1, 2, 4, 'a string')
    

    As noted in the above code, the type of args will be always tuple, and the content of it will be all the non-key-worded arguments passed to the function.

    Packing with the ** operator (kwargs)

    As we saw previously, the ** operator is used exclusively for dictionaries. This means that with this operator we’re able to pass key-value pairs to the function as a parameter.

    Let’s create a function make_person, which receives a positional argument “name”, and an undefined amount of keyworded arguments.

    >>> def make_person(name, **kwargs):
    ...     result = name + ': '
    ...     for key, value in kwargs.items():
    ...             result += f'{key} = {value}, '
    ...     return result
    ... 
    >>> make_person('Melissa', id=12112, location='london', net_worth=12000)
    'Melissa: id = 12112, location = london, net_worth = 12000, '
    

    As you can see, the **kwargs statement converts all the keyworded arguments to a dictionary, which we can iterate inside the function.

    Note: kwargs is just a convention you can name this parameter with whatever you want

    We can check the type of the kwargs the same way we did with args:

    >>> def test_kwargs(**kwargs):
    ...     print(type(kwargs))
    ...     print(kwargs)
    ... 
    >>> test_kwargs(random=12, parameters=21)
    <class 'dict'>
    {'random': 12, 'parameters': 21}
    

    The kwargs internal variable always turns to be a dictionary, which stores the key-value pairs passed to the function.

    Finally, let’s make use of args and kwargs in the same function:

    >>> def my_final_function(*args, **kwargs):
    ...     print('Type args: ', type(args))
    ...     print('args: ', args)
    ...     print('Type kwargs: ', type(kwargs))
    ...     print('kwargs: ', kwargs)
    ... 
    >>> my_final_function('Python', 'The', 'Best', language='Python', users='A lot')
    Type args:  <class 'tuple'>
    args:  ('Python', 'The', 'Best')
    Type kwargs:  <class 'dict'>
    kwargs:  {'language': 'Python', 'users': 'A lot'}
    

    Conclusion

    Unpacking operators are really useful in day-to-day tasks, now you know how to use them both in individual statements and function parameters.

    In this tutorial you learned :

    • You use * for tuples and lists and ** for dictionaries
    • You can use unpacking operators in functions and classes constructors
    • args are used to pass non-key-worded parameters to functions
    • kwargs are used to pass keyworded parameters to functions.