2.2. Unpack Star¶
a, b, *c = 1, 2, 3, 4, 5
Used when there is arbitrary number of values to unpack
Could be used from start, middle, end
There can't be multiple star expressions in one assignment statement
_
is regular variable name, not a special Python syntax_
by convention is used for data we don't want to access in future

2.2.1. Example¶
>>> def get_user_details(username):
... return 'Mark', 'Watney', 'mwatney@nasa.gov', 'mwatney@esa.int', 'mwatney@polsa.gov.pl'
>>>
>>>
>>> firstname, lastname, *email = get_user_details('mwatney')
>>>
>>> firstname
'Mark'
>>>
>>> lastname
'Watney'
>>>
>>> email
['mwatney@nasa.gov', 'mwatney@esa.int', 'mwatney@polsa.gov.pl']
2.2.2. Arbitrary Number of Arguments¶
Unpack values at the right side:
>>> a, b, *c = [1, 2, 3, 4, 5]
>>>
>>> print(f'{a=}, {b=}, {c=}')
a=1, b=2, c=[3, 4, 5]
Unpack values at the left side:
>>> *a, b, c = [1, 2, 3, 4, 5]
>>>
>>> print(f'{a=}, {b=}, {c=}')
a=[1, 2, 3], b=4, c=5
Unpack values from both sides at once:
>>> a, *b, c = [1, 2, 3, 4, 5]
>>>
>>> print(f'{a=}, {b=}, {c=}')
a=1, b=[2, 3, 4], c=5
Unpack from variable length:
>>> a, *b, c = [1, 2]
>>>
>>> print(f'{a=}, {b=}, {c=}')
a=1, b=[], c=2
2.2.3. Errors¶
Cannot unpack from both sides at once:
>>> *a, b, *c = [1, 2, 3, 4, 5]
Traceback (most recent call last):
SyntaxError: multiple starred expressions in assignment
Unpack requires values for required arguments:
>>> a, *b, c = [1]
Traceback (most recent call last):
ValueError: not enough values to unpack (expected at least 2, got 1)
2.2.4. Skipping Values¶
_
is regular variable name, not a special Python syntax_
by convention is used for data we don't want to access in future
>>> _ = 'Mark Watney'
>>>
>>> print(_)
Mark Watney
>>> line = 'Mark,Watney,mwatney@nasa.gov,mwatney@esa.int,mwatney@polsa.gov.pl'
>>> firstname, lastname, *_ = line.split(',')
>>>
>>> print(f'{firstname=}, {lastname=}')
firstname='Mark', lastname='Watney'
>>> line = '4.9,3.1,1.5,0.1,setosa'
>>> *_, label = line.split(',')
>>>
>>> print(f'{label=}')
label='setosa'
>>> line = 'watney:x:1000:1000:Mark Watney:/home/watney:/bin/bash'
>>> username, _, uid, *_ = line.split(':')
>>>
>>> print(f'{username=}, {uid=}')
username='watney', uid='1000'
2.2.5. For Loop Unpacking¶
>>> DATA = [
... (5.8, 2.7, 5.1, 1.9, 'virginica'),
... (5.1, 3.5, 1.4, 0.2, 'setosa'),
... (5.7, 2.8, 4.1, 1.3, 'versicolor'),
... ]
>>> for row in DATA:
... print(f'{row=}')
...
row=(5.8, 2.7, 5.1, 1.9, 'virginica')
row=(5.1, 3.5, 1.4, 0.2, 'setosa')
row=(5.7, 2.8, 4.1, 1.3, 'versicolor')
>>> for row in DATA:
... values = row[0:4]
... species = row[-1]
... print(f'{values=}, {species=}')
...
values=(5.8, 2.7, 5.1, 1.9), species='virginica'
values=(5.1, 3.5, 1.4, 0.2), species='setosa'
values=(5.7, 2.8, 4.1, 1.3), species='versicolor'
>>> for row in DATA:
... *values, species = row
... print(f'{values=}, {species=}')
...
values=[5.8, 2.7, 5.1, 1.9], species='virginica'
values=[5.1, 3.5, 1.4, 0.2], species='setosa'
values=[5.7, 2.8, 4.1, 1.3], species='versicolor'
>>> for *values, species in DATA:
... print(f'{values=}, {species=}')
...
values=[5.8, 2.7, 5.1, 1.9], species='virginica'
values=[5.1, 3.5, 1.4, 0.2], species='setosa'
values=[5.7, 2.8, 4.1, 1.3], species='versicolor'
2.2.6. Multi Dimensional¶
>>> from pprint import pprint
>>> DATA = [
... ('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
... (5.8, 2.7, 5.1, 1.9, 'virginica'),
... (5.1, 3.5, 1.4, 0.2, 'setosa'),
... (5.7, 2.8, 4.1, 1.3, 'versicolor'),
... ]
>>> header = DATA[0]
>>> rows = DATA[1:]
>>>
>>> pprint(header)
('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species')
>>>
>>> pprint(rows)
[(5.8, 2.7, 5.1, 1.9, 'virginica'),
(5.1, 3.5, 1.4, 0.2, 'setosa'),
(5.7, 2.8, 4.1, 1.3, 'versicolor')]
>>> header, *rows = DATA
>>>
>>> pprint(header)
('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species')
>>>
>>> pprint(rows)
[(5.8, 2.7, 5.1, 1.9, 'virginica'),
(5.1, 3.5, 1.4, 0.2, 'setosa'),
(5.7, 2.8, 4.1, 1.3, 'versicolor')]
2.2.7. Use Case - 0x01¶
>>> a, b, c = range(0, 3)
>>> a, b, c, d, e = range(0, 5)
>>> a, b, *c = range(0, 10)
2.2.8. Use Case - 0x01¶
>>> line = 'ares3,watney,lewis,vogel,johanssen'
>>> mission, *crew = line.split(',')
>>>
>>> print(f'{mission=}, {crew=}')
mission='ares3', crew=['watney', 'lewis', 'vogel', 'johanssen']
2.2.9. Use Case - 0x02¶
>>> first, *middle, last = [1, 2, 3, 4]
>>>
>>> print(f'{first=}, {middle=}, {last=}')
first=1, middle=[2, 3], last=4
>>> first, second, *others = [1, 2, 3, 4]
>>>
>>> print(f'{first=}, {second=}, {others=}')
first=1, second=2, others=[3, 4]
2.2.10. Use Case - 0x03¶
>>> first, second, *others = range(0,10)
>>>
>>> print(f'{first=}, {second=}, {others=}')
first=0, second=1, others=[2, 3, 4, 5, 6, 7, 8, 9]
>>> first, second, *_ = range(0,10)
>>>
>>> print(f'{first=}, {second=}')
first=0, second=1
2.2.11. Use Case - 0x04¶
Python Version
>>> import sys
>>>
>>>
>>> major, minor, *_ = sys.version_info
>>>
>>> print(major, minor, sep='.')
3.11
2.2.12. Use Case - 0x05¶
Iris 1D
>>> *values, species = (5.8, 2.7, 5.1, 1.9, 'virginica')
>>>
>>> print(f'{values=}, {species=}')
values=[5.8, 2.7, 5.1, 1.9], species='virginica'
2.2.13. Use Case - 0x06¶
>>> *values, species = (5.8, 2.7, 5.1, 1.9, 'virginica')
>>> avg = sum(values) / len(values)
>>>
>>> print(f'{avg=:.2f}, {species=}')
avg=3.88, species='virginica'
2.2.14. Use Case - 0x07¶
Iris 2D
>>> DATA = [
... (5.8, 2.7, 5.1, 1.9, 'virginica'),
... (5.1, 3.5, 1.4, 0.2, 'setosa'),
... (5.7, 2.8, 4.1, 1.3, 'versicolor'),
... ]
>>>
>>>
>>> for *values, species in DATA:
... avg = sum(values) / len(values)
... print(f'{avg=:.2f} {species=}')
avg=3.88 species='virginica'
avg=2.55 species='setosa'
avg=3.48 species='versicolor'
2.2.15. Assignments¶
"""
* Assignment: Unpack Star List
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 min
English:
1. Separate ip address from host names
2. Use asterisk `*` notation
3. Run doctests - all must succeed
Polish:
1. Odseparuj adres ip od nazwy hostów
2. Skorzystaj z notacji z gwiazdką `*`
3. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert ip is not Ellipsis, \
'Assign your result to variable `ip`'
>>> assert hosts is not Ellipsis, \
'Assign your result to variable: `hosts`'
>>> assert type(ip) is str, \
'Variable `ip` has invalid type, should be str'
>>> assert type(hosts) is list, \
'Variable `hosts` has invalid type, should be list'
>>> assert all(type(x) is str for x in hosts), \
'All rows in `hosts` should be str'
>>> assert '' not in hosts, \
'Do not pass any arguments to str.split() method'
>>> ip
'10.13.37.1'
>>> hosts
['nasa.gov', 'esa.int', 'polsa.gov.pl']
"""
DATA = ['10.13.37.1', 'nasa.gov', 'esa.int', 'polsa.gov.pl']
# String with IP address: '10.13.37.1'
# type: str
ip = ...
# List of hostnames: ['nasa.gov', 'esa.int', 'polsa.gov.pl']
# type: list[str]
hosts = ...
"""
* Assignment: Unpack Star Func
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 min
English:
1. Separate ip address from host names
2. Use asterisk `*` notation
3. Run doctests - all must succeed
Polish:
1. Odseparuj adres ip od nazwy hostów
2. Skorzystaj z notacji z gwiazdką `*`
3. Uruchom doctesty - wszystkie muszą się powieść
Hints:
* `str.split()`
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert ip is not Ellipsis, \
'Assign your result to variable `ip`'
>>> assert hosts is not Ellipsis, \
'Assign your result to variable: `hosts`'
>>> assert type(ip) is str, \
'Variable `ip` has invalid type, should be str'
>>> assert type(hosts) is list, \
'Variable `hosts` has invalid type, should be list'
>>> assert all(type(x) is str for x in hosts), \
'All rows in `hosts` should be str'
>>> assert '' not in hosts, \
'Do not pass any arguments to str.split() method'
>>> ip
'10.13.37.1'
>>> hosts
['nasa.gov', 'esa.int', 'polsa.gov.pl']
"""
DATA = '10.13.37.1 nasa.gov esa.int polsa.gov.pl'
# String with IP address: '10.13.37.1'
# type: str
ip = ...
# List of host names: ['nasa.gov', 'esa.int', 'polsa.gov.pl']
# type: list[str]
hosts = ...
"""
* Assignment: Unpack Star Nested
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 min
English:
1. Separate values from species name
2. Use asterisk `*` notation
3. Run doctests - all must succeed
Polish:
1. Odseparuj wartości od nazwy gatunku
2. Skorzystaj z konstrukcji z gwiazdką `*`
3. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert values is not Ellipsis, \
'Assign result to variable: `values`'
>>> assert species is not Ellipsis, \
'Assign result to variable: `species`'
>>> assert len(values) > 0, \
'Variable `values` cannot be empty'
>>> assert len(species) > 0, \
'Variable `species` cannot be empty'
>>> assert type(values) is list, \
'Variable `values` has invalid type, should be list'
>>> assert type(species) is str, \
'Variable `species` has invalid type, should be str'
>>> assert all(type(x) is float for x in values), \
'All rows in `values` should be float'
>>> values
[5.1, 3.5, 1.4, 0.2]
>>> species
'setosa'
"""
DATA = (5.1, 3.5, 1.4, 0.2, 'setosa')
# All numeric values from DATA
# type: tuple[str]
values = ...
# Species name from DATA (last element)
# type: list[tuple]
species = ...
"""
* Assignment: Unpack Star Nested
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 min
English:
1. Separate header and rows
2. Use asterisk `*` notation
3. Run doctests - all must succeed
Polish:
1. Odseparuj nagłówek od wierszy danych
2. Skorzystaj z konstrukcji z gwiazdką `*`
3. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert header is not Ellipsis, \
'Assign result to variable: `header`'
>>> assert rows is not Ellipsis, \
'Assign result to variable: `rows`'
>>> assert len(header) > 0, \
'Variable `header` cannot be empty'
>>> assert len(rows) > 0, \
'Variable `rows` cannot be empty'
>>> assert type(header) is tuple, \
'Variable `header` has invalid type, should be tuple'
>>> assert type(rows) is list, \
'Variable `hosts` has invalid type, should be list'
>>> assert all(type(x) is str for x in header), \
'All rows in `header` should be str'
>>> assert all(type(x) is tuple for x in rows), \
'All rows in `rows` should be tuple'
>>> header
('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species')
>>> rows # doctest: +NORMALIZE_WHITESPACE
[(5.8, 2.7, 5.1, 1.9, 'virginica'),
(5.1, 3.5, 1.4, 0.2, 'setosa'),
(5.7, 2.8, 4.1, 1.3, 'versicolor'),
(6.3, 2.9, 5.6, 1.8, 'virginica'),
(6.4, 3.2, 4.5, 1.5, 'versicolor'),
(4.7, 3.2, 1.3, 0.2, 'setosa')]
"""
DATA = [
('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
(5.8, 2.7, 5.1, 1.9, 'virginica'),
(5.1, 3.5, 1.4, 0.2, 'setosa'),
(5.7, 2.8, 4.1, 1.3, 'versicolor'),
(6.3, 2.9, 5.6, 1.8, 'virginica'),
(6.4, 3.2, 4.5, 1.5, 'versicolor'),
(4.7, 3.2, 1.3, 0.2, 'setosa')]
# first line from DATA
# type: tuple[str]
header = ...
# all the other lines from DATA, beside first line
# type: list[tuple]
rows = ...
"""
* Assignment: Unpack Star Loop
* Complexity: easy
* Lines of code: 4 lines
* Time: 5 min
English:
1. Iterate over data splitting `*features` from `label`
2. Define `result: list[str]` with
species names ending with "ca" or "osa"
3. Run doctests - all must succeed
Polish:
1. Iteruj po danych rozdzielając `*features` od `label`
2. Zdefiniuj `result: list[str]` z
nazwami gatunków kończącymi się na "ca" lub "osa"
3. Uruchom doctesty - wszystkie muszą się powieść
Hints:
* `str.endswith()`
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert len(result) > 0, \
'Variable `result` cannot be empty'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert all(type(x) is str for x in result), \
'All rows in `result` should be str'
>>> result
['virginica', 'setosa', 'virginica', 'setosa']
"""
DATA = [
('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
(5.8, 2.7, 5.1, 1.9, 'virginica'),
(5.1, 3.5, 1.4, 0.2, 'setosa'),
(5.7, 2.8, 4.1, 1.3, 'versicolor'),
(6.3, 2.9, 5.6, 1.8, 'virginica'),
(6.4, 3.2, 4.5, 1.5, 'versicolor'),
(4.7, 3.2, 1.3, 0.2, 'setosa')]
SUFFIXES = ('ca', 'osa')
# species names ending with "ca" or "osa"
# type: list[str]
result = ...