How to unpack using star expression in Python?


Introduction

One of the basic limitation of unpacking is that you must know the length of the sequences you are unpacking in advance.

How to do it..

random_numbers = [0, 1, 5, 9, 17, 12, 7, 10, 3, 2]
random_numbers_descending = sorted(random_numbers, reverse=True)
print(f"Output \n*** {random_numbers_descending}")

Output

*** [17, 12, 10, 9, 7, 5, 3, 2, 1, 0]

If I now wanted to find out the largest and second largest from the numbers, we will get an exception "too many values to unpack".

print(f"Output \n*** Getting the largest and second largest")
largest, second_largest = random_numbers_descending

Output

*** Getting the largest and second largest


---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in
1 print(f"Output \n*** Getting the largest and second largest")
----> 2 largest, second_largest = random_numbers_descending

ValueError: too many values to unpack (expected 2)

Python often rely on indexing and slicing. For example, when I want to extract the largest, second largest from a list of items below is how we can do.

largest = random_numbers_descending[0]
print(f"Output \n*** Getting the largest - {largest}")

Output

*** Getting the largest - 17


second_largest = random_numbers_descending[1]
print(f"Output \n*** Getting the second largest - {second_largest}")

Output

*** Getting the second largest - 12


rest_of_numbers = random_numbers_descending[2:]
print(f"Output \n*** Getting the rest of numbers - {rest_of_numbers}")

Output

*** Getting the rest of numbers - [10, 9, 7, 5, 3, 2, 1, 0]

While this works, all of the indexing and slicing is visually noisy. In practice, it is error prone to divide the members of a sequence into various subsets this way.

To do it better, Python supports catch-all unpacking through a starred expression.

This starred syntax allows one part of the unpacking assignment to receive all values that do not match any other part of the unpacking pattern.

largest,second_largest, *rest_of_numbers = random_numbers_descending
print(f"Output \n largest: {largest} \n second_largest:{second_largest} \n rest_of_numbers:{rest_of_numbers}")

Output

largest: 17
second_largest:12
rest_of_numbers:[10, 9, 7, 5, 3, 2, 1, 0]

How does the above code look? In a single line which is also easier to read we are able to acheive the output. A starred expression may appear in any position, so you can get the benefits of catch-all unpacking anytime you need to extract one slice

largest: 17
rest_of_numbers:[12, 10, 9, 7, 5, 3, 2, 1]
smallest:0


*rest_of_numbers, second_smallest, smallest = random_numbers_descending
print(f"Output \n rest_of_numbers:{rest_of_numbers} \n second_smallest: {second_smallest} \n smallest:{smallest}")


rest_of_numbers:[17, 12, 10, 9, 7, 5, 3, 2]
second_smallest: 1
smallest:0

However, to unpack assignments that contain a starred expression, you must have at least one required part, or else you’ll get a SyntaxError. We can’t use a catch-all expression on its own.

*rest_of_numbers = random_numbers_descending


File "", line 1
*rest_of_numbers = random_numbers_descending
^
SyntaxError: starred assignment target must be in a list or tuple

We also cannot use multiple catch-all expressions in a single-level unpacking pattern. This is another important note to consider.

*rest_of_numbers, *more_smallest, smallest = random_numbers_descending


File "", line 1
*rest_of_numbers, *more_smallest, smallest = random_numbers_descending
^
SyntaxError: two starred expressions in assignment


But it is possible to use multiple starred expressions in an unpacking assignment statement, as long as they’re catch-alls for different parts of the multilevel structure being unpacked.

player_grandslame_and_atptitles = {
'Federer': (20, 103),
'Nadal': (20,84),}

((player1, (grandslam1, *atptitles1)), (player2, (grandslam2, *atptitles2))) = player_grandslame_and_atptitles.items()

print(f'Output \nPlayer - {player1} Have acheived {grandslam1} grandslams and , {atptitles1} atp tour titles')
print(f'Player - {player2} Have acheived {grandslam2} grandslams and , {atptitles2} atp tour titles')


Output


Player - Federer Have acheived 20 grandslams and , [103] atp tour titles
Player - Nadal Have acheived 20 grandslams and , [84] atp tour titles

Starred expressions become list instances in all cases. If there are no leftover items from the sequence being unpacked, the catch-all part will be an empty list. This is especially useful when you are processing a sequence that you know in advance has at least N elements.

random_numbers = [0, 1]
first, second, *rest = random_numbers
print(f"Output \n{first, second, rest}")

Output

(0, 1, [])

Updated on: 09-Nov-2020

1K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements