# 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),

((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, [])