7.2. Tuple Unpacking#

import sys
from pathlib import Path

# Find project root by looking for _config.yml
current = Path.cwd()
for parent in [current, *current.parents]:
    if (parent / '_config.yml').exists():
        project_root = parent
        break
else:
    project_root = Path.cwd().parent.parent

# Add project root to path
sys.path.insert(0, str(project_root))

# Import shared teaching helpers and cell magics
from shared import thinkpython, diagram, jupyturtle, structshape
from shared.download import download

7.2.1. Basic Unpacking#

You can assign multiple variables from a tuple or any sequence.

a, b = 1, 2

Values are assigned left to right. In this example, a gets 1 and b gets 2. We can display the results like this:

a, b
(1, 2)

More generally, if the left side is a tuple of variables, the right side can be any sequence - a string, list, or tuple. For example, to split an email address into a user name and domain:

email = 'monty@python.org'
username, domain = email.split('@')

split returns a list with two elements; the first goes to username, the second to domain.

username, domain
('monty', 'python.org')

The number of variables on the left and values on the right must match; otherwise you get a ValueError.

%%expect ValueError
a, b = 1, 2, 3
ValueError: too many values to unpack (expected 2)

Tuple assignment is a clean way to swap two variables. With conventional assignments, you need a temporary variable:

temp = a
a = b
b = temp

That works, but tuple assignment does the same swap without a temporary variable.

a, b = b, a
### Exercise: Tuple Assignment
#   1. Unpack the tuple (10, 20, 30) into three variables x, y, z and print them.
#   2. Split the email address 'ada@lovelace.org' into username and domain using
#      split('@') and tuple assignment, then print both.
#   3. Swap the values of two variables a=5, b=99 using tuple assignment.
### Your code starts here.




### Your code ends here.

Hide code cell source

### solution

x, y, z = (10, 20, 30)
print(x, y, z)                                  # 10 20 30

username, domain = 'ada@lovelace.org'.split('@')
print(username, domain)                          # ada lovelace.org

a, b = 5, 99
a, b = b, a
print(a, b)                                      # 99 5
10 20 30
ada lovelace.org
99 5

7.2.2. Starred Unpacking#

Use a starred name to capture “the rest” of a sequence during assignment.

first, *middle, last = range(6)
first, middle, last
(0, [1, 2, 3, 4], 5)

This works because all expressions on the right side are evaluated before any assignments.

Tuple assignment is also handy in for loops. For example, to loop through the items in a dictionary, use the items method.

d = {'one': 1, 'two': 2}
print(type(d.items()))
for item in d.items():          # items() returns a dict_items view of key-value pairs
    key, value = item
    print(key, '->', value)
<class 'dict_items'>
one -> 1
two -> 2

Each time through the loop, item is a tuple with a key and its value. We can unpack it directly:

for key, value in d.items():
    print(key, '->', value)
one -> 1
two -> 2
### Exercise: Starred Unpacking
#   Given data = (1, 2, 3, 4, 5, 6)
#   1. Unpack the first element into `head`, the last into `tail`,
#      and everything in between into `body` using starred unpacking.
#   2. Print all three.
#   3. Loop over {'x': 10, 'y': 20, 'z': 30}.items() and unpack
#      each key-value pair directly in the for statement, printing each pair.
### Your code starts here.

data = (1, 2, 3, 4, 5, 6)



### Your code ends here.

Hide code cell source

### solution

data = (1, 2, 3, 4, 5, 6)

head, *body, tail = data
print(head, body, tail)      # 1 [2, 3, 4, 5] 6

for key, value in {'x': 10, 'y': 20, 'z': 30}.items():
    print(key, '->', value)
1 [2, 3, 4, 5] 6
x -> 10
y -> 20
z -> 30

Now key and value are assigned on each iteration.