# Unpacking Assignments and Starred Expressions in Python

## Table of contents

* much of this material is based on Brett Slatkin's *Effective Python* 2nd ed., which I highly recommend.

### Unpacking Assignment

*Unpacking Assignments* in Python involves **assigning multiple values with one statement.**

```
three_nice_numbers = [23, 19, 51]
# unpacking
first, second, third = three_nice_numbers
print(first, second, 'and', third) # 23 19 and 51
```

This can be applied to any **iterable**-- any object that can return its members one at a time. For instance, it can be used to assign the values of a tuple to multiple varies in one line.

```
nice_number_tuple = (23, 19, 51)
# unpacking
first, second, third = nice_number_tuple
print(first, second, 'and', third) # 23 19 and 51
```

This is easier to read and less error-prone as compared to accessing the iterable members via indexing and then assigning them separately.

```
nice_number_tuple = (23, 19, 51)
# access via index and assign
first = nice_number_tuple[0]
second = nice_number_tuple[1]
third = nice_number_tuple[2]
```

### Catch-All Unpacking | Starred Expressions

A drawback of assignment unpacking is that you must know the length of the iterable in advance. If you provide the incorrect number of variable names in the statement, you'll get an error:

```
nice_numbers = [23, 19, 51, 62, 54]
# unpacking
first, second, third = nice_numbers
# ValueError: too many values to unpack (expected 3)
```

A neat way around this is to use **starred expressions.**

```
nice_numbers = [23, 19, 51, 62, 54]
# unpacking
first, second, *the_rest = nice_numbers
# 23, 19, [51, 62, 54]
```

Starred expressions always become `list`

instances. You can place them anywhere in the assignment statement:

```
nice_numbers = [23, 19, 51, 62, 54]
# unpacking
first, *middle, last = nice_numbers
# 23, [19, 51, 62], 54
```

If there aren't any leftover items to unpack, the starred expression becomes an empty list.

```
nice_numbers = [23, 54]
# unpacking
first, *middle, last = nice_numbers
# 23, [], 54
```

### Caveats

**Watch out for memory exhaustion when using starred expressions**

- Because the starred expression always becomes a list, in some cases you run the risk of exhausting your computer's memory and causing program termination. So, it is best to use this only if you are sure the resulting data will fit into memory.

**Don't use more than three variables in unpacking statements**

- It's best to avoid cases where you'll need more than three variables to unpack an iterable or data returned from some function. Having four or more is both error-prone and hurts readability.

```
# don't do this
def get_stats():
...
return minimum, maximum, median, average, count
# Unpacking Correctly
minimum, maximum, median, average, count = get_stats()
# Wrong Order, but hard to tell
minimum, maximum, average, median, count = get_stats()
```

Moreover, if the `get_stats`

function took arguments, the last line of code would likely become very long and require wrapping, making the code less readable.

If more than three values needs to be returned and distinctly gotten from a function/iterable, consider using a `namedtuple`

from Python's `collections`

module:

```
from collections import namedtuple
# define the namedtuple and instantiate it with the return values in the function
def get_stats():
...
Stats = namedtuple('Stats', 'min max median average')
stats = AggregateStats(minimum, maximum, median, average)
return stats
aggregate_stats = get_stats()
print('The median is', aggregate_stats.median)
```