How to unpack using star expression in Python?


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}")


*** [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


*** Getting the largest and second largest

ValueError Traceback (most recent call last)
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}")


*** Getting the largest - 17

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


*** Getting the second largest - 12

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


*** 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}")


largest: 17
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]

*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

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')


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}")


(0, 1, [])