3.1. Star Assignment
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
3.1.1. Recap
a = 1
- inta = 1, 2
- tuplea, b = 1, 2
- multiple assignmenta, b, c = 1, 2, 3
- multiple assignment
3.1.2. Example
>>> def get_user_details(username):
... return 'Mark', 'Watney', 'mwatney@nasa.gov', 'mwatney@gmail.com'
>>> firstname, lastname, *email = get_user_details('mwatney')
>>>
>>> firstname
'Mark'
>>>
>>> lastname
'Watney'
>>>
>>> email
['mwatney@nasa.gov', 'mwatney@gmail.com']
3.1.3. Arbitrary Number of Arguments
Unpack values at the right side
Unpack values at the left side
Unpack values from both sides at once
Unpack from variable length
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
3.1.4. Errors
Cannot unpack from both sides at once
Unpack requires values for required arguments
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)
3.1.5. Skipping Values
_
is used to skip valuesIt is a regular variable name, not a special Python syntax
By convention it is used for data we don't want to access in future
It can be used multiple times in the same statement
>>> line = 'Mark,Watney,mwatney@nasa.gov,mwatney@gmail.com'
>>> firstname, lastname, *_ = line.split(',')
>>>
>>> print(f'{firstname=}, {lastname=}')
firstname='Mark', lastname='Watney'
>>> line = 'watney:x:1000:1000:Mark Watney:/home/watney:/bin/bash'
>>> username, _, uid, *_ = line.split(':')
>>>
>>> print(f'{username=}, {uid=}')
username='watney', uid='1000'
3.1.6. For Loop Unpacking
Use star expression to unpack values in for loop
>>> 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'
3.1.7. Multi Dimensional
Unpack values from multi-dimensional data
>>> 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')]
3.1.8. Case Study
# avg=3.4, species='virginica'
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'),
(7.0, 3.2, 4.7, 1.4, 'versicolor'),
(7.6, 3.0, 6.6, 2.1, 'virginica'),
(4.6, 3.1, 1.5, 0.2, 'setosa'),
]
header, *rows = DATA
# header = DATA[0]
# rows = DATA[1:]
# avg=3.4, species='virginica'
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'),
(7.0, 3.2, 4.7, 1.4, 'versicolor'),
(7.6, 3.0, 6.6, 2.1, 'virginica'),
(4.6, 3.1, 1.5, 0.2, 'setosa'),
]
header, *rows = DATA
for row in rows:
values = row[:-1]
species = row[-1]
avg = sum(values) / len(values)
print(f'{avg=:.1f}, {species=}')
# avg=3.4, species='virginica'
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'),
(7.0, 3.2, 4.7, 1.4, 'versicolor'),
(7.6, 3.0, 6.6, 2.1, 'virginica'),
(4.6, 3.1, 1.5, 0.2, 'setosa'),
]
header, *rows = DATA
for row in rows:
*values, species = row
avg = sum(values) / len(values)
print(f'{avg=:.1f}, {species=}')
# avg=3.4, species='virginica'
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'),
(7.0, 3.2, 4.7, 1.4, 'versicolor'),
(7.6, 3.0, 6.6, 2.1, 'virginica'),
(4.6, 3.1, 1.5, 0.2, 'setosa'),
]
header, *rows = DATA
for *values, species in rows:
avg = sum(values) / len(values)
print(f'{avg=:.1f}, {species=}')
3.1.9. Use Case - 1
>>> a, b, c = range(0, 3)
>>> a, b, c, d, e = range(0, 5)
>>> a, b, *c = range(0, 10)
3.1.10. Use Case - 1
>>> line = 'ares3,watney,lewis,vogel,johanssen'
>>> mission, *crew = line.split(',')
>>>
>>> print(f'{mission=}, {crew=}')
mission='ares3', crew=['watney', 'lewis', 'vogel', 'johanssen']
3.1.11. Use Case - 2
>>> 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]
3.1.12. Use Case - 3
>>> 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
3.1.13. Use Case - 4
Python Version
>>> import sys
>>>
>>>
>>> major, minor, *_ = sys.version_info
>>>
>>> print(major, minor, sep='.')
3.13
3.1.14. Use Case - 5
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'
3.1.15. Use Case - 6
>>> *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'
3.1.16. Use Case - 7
>>> line = '1969-07-21, 02:56:15, WARNING, Neil Armstrong first words on the Moon'
>>> d, t, lvl, *msg = line.split(', ')
>>>
>>> d
'1969-07-21'
>>> t
'02:56:15'
>>> lvl
'WARNING'
>>> msg
['Neil Armstrong first words on the Moon']
3.1.17. Use Case - 8
>>> line = 'watney:x:1000:1000:Mark Watney:/home/watney:/bin/bash'
>>> username, password, uid, *others = line.split(':')
>>>
>>> username
'watney'
>>> password
'x'
>>> uid
'1000'
>>> others
['1000', 'Mark Watney', '/home/watney', '/bin/bash']
3.1.18. Use Case - 9
>>> line = 'watney:x:1000:1000:Mark Watney:/home/watney:/bin/bash'
>>> username, _, uid, *_ = line.split(':')
>>>
>>> username
'watney'
>>> uid
'1000'
3.1.19. Use Case - 10
>>> line = '4.9,3.1,1.5,0.1,setosa'
>>> *values, species = line.split(',')
>>> values
['4.9', '3.1', '1.5', '0.1']
>>> species
'setosa'
3.1.20. Use Case - 11
>>> data = (5.8, 2.7, 5.1, 1.9, 'virginica')
>>> *values, species = data
>>> values
[5.8, 2.7, 5.1, 1.9]
>>> species
'virginica'
3.1.21. Use Case - 12
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'
3.1.22. Assignments
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Star Assignment List
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2
# %% 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 sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> 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']
# Separate ip address from host names
# Use asterisk `*` notation
# type: ip = str # example: '10.13.37.1'
# type: hosts = list # example: ['nasa.gov', 'esa.int', 'polsa.gov.pl']
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Star Assignment Func
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2
# %% English
# 1. Separate ip address from host names
# 2. Use star expression
# 3. Mind, this assignment is very similar
# to the previous one, but not identical
# 4. Run doctests - all must succeed
# %% Polish
# 1. Odseparuj adres ip od nazwy hostów
# 2. Użyj wyrażenia z gwiazdką
# 3. Zwróć uwagę, że to zadanie jest bardzo podobne
# do poprzedniego, ale to nie jest identyczne
# 4. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `str.split()`
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> 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'
# Separate ip address from host names
# Use asterisk `*` notation
# type: ip = str # example: '10.13.37.1'
# type: hosts = list # example: ['nasa.gov', 'esa.int', 'polsa.gov.pl']
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Star Assignment Func
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2
# %% English
# 1. Separate ip address from host names
# 2. Use star expression
# 3. Run doctests - all must succeed
# %% Polish
# 1. Odseparuj adres ip od nazwy hostów
# 2. Użyj wyrażenia z gwiazdką
# 3. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `str.split()`
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> 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'
# Separate ip address from host names
# Use asterisk `*` notation
# type: ip = str # example: '10.13.37.1'
# type: hosts = list # example: ['nasa.gov', 'esa.int', 'polsa.gov.pl']
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Star Assignment Nested
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2
# %% English
# 1. Separate values from species name
# 2. Use star expression
# 3. Run doctests - all must succeed
# %% Polish
# 1. Odseparuj wartości od nazwy gatunku
# 2. Użyj wyrażenia z gwiazdką
# 3. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> 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')
# Separate values from species name
# Use star expression
# type: values = list[float] # example: [5.1, 3.5, 1.4, 0.2]
# type: species = str # example: 'setosa'
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Star Assignment Nested
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2
# %% English
# 1. Separate header and rows
# 2. Use star expression
# 3. Run doctests - all must succeed
# %% Polish
# 1. Odseparuj nagłówek od wierszy danych
# 2. Użyj wyrażenia z gwiazdką
# 3. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> 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'),
]
# Separate header and rows
# Use star expression
# type: header = tuple[str] # example: ('sepal_length', 'sepal_width', ...)
# type: rows = list[tuple] # [(5.8, 2.7, 5.1, 1.9, 'virginica'), ...]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Star Assignment Loop
# - Difficulty: easy
# - Lines: 4
# - Minutes: 5
# %% English
# 1. Define `result: list[str]`
# 2. Iterating over `DATA` unpack row to:
# - `values` - all beside last
# - `species` - last in the row
# 3. Append to `result` species names with suffix in `SUFFIXES`
# 4. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj `result: list[str]`
# 2. Iterując po `DATA` rozpakuj wiersz do:
# - `values` - wszystkie poza ostatnim
# - `species` - ostatni w wierszu
# 3. Dodaj do `result` nazwy gatunków (species) z końcówką w `SUFFIXES`
# 4. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `str.endswith()`
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from pprint import pprint
>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is list, \
'Result must be a list'
>>> assert len(result) > 0, \
'Result cannot be empty'
>>> assert all(type(element) is str for element in result), \
'All elements in result must be a str'
>>> pprint(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 with suffix in `SUFFIXES`
# type: list[str]
result = ...