12.1. For About

  • Iterating works for builtin sequences

  • Works with: str, bytes, list, tuple, set, dict

  • Naming Current Element: letter, digit, number, user, color, sentence

Iterating Str:

>>> DATA = 'abc'
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating Tuple:

>>> DATA = ('a', 'b', 'c')
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating List:

>>> DATA = ['a', 'b', 'c']
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating Set:

>>> DATA = {'a', 'b', 'c'}
>>>
>>> for x in sorted(DATA):
...     print(x)
a
b
c

12.1.1. Problem

>>> data = ['a', 'b', 'c']
>>> i = 0
>>>
>>> while i < len(data):
...     x = data[i]
...     print(x)
...     i += 1
a
b
c

12.1.2. Solution

>>> data = ['a', 'b', 'c']
>>>
>>> for x in data:
...     print(x)
a
b
c

12.1.3. Iterating Str

>>> DATA = 'abc'
>>>
>>> for x in DATA:
...     print(x)
a
b
c

12.1.4. Iterating Tuple

>>> DATA = ('a', 'b', 'c')
>>>
>>> for x in DATA:
...     print(x)
a
b
c

12.1.5. Iterating List

>>> DATA = ['a', 'b', 'c']
>>>
>>> for x in DATA:
...     print(x)
a
b
c

12.1.6. Iterating Set

  • Set order depends on element hash

  • Each time the result of the function will be different

  • Use sorted(DATA) to get deterministic order

Set order depends on element hash, therefore each time the result of the function will be different:

>>> DATA = {'a', 'b', 'c'}
>>>
>>> for x in DATA:
...     print(x)
c
a
b

Use sorted(DATA) to get deterministic order:

>>> DATA = {'a', 'b', 'c'}
>>>
>>> for x in sorted(DATA):
...     print(x)
a
b
c

12.1.7. Iterating Dict

  • By default iterating is over the keys

  • More information in For Dict

>>> DATA = {'a':1, 'b':2, 'c':3}
>>>
>>> for x in DATA:
...     print(x)
a
b
c

12.1.8. Naming Current Element

  • The longer the loop scope, the longer the variable name should be

  • Avoid single-letter variables if scope is longer than one line

  • Prefer locally meaningful name over generic names

  • Good names: letter, digit, number, user, color, sentence

  • Ok names (depends on the scope): x, value, item

  • Bad names: obj, element, e, v

  • Very bad names: i (by convention it is a loop counter)

Good names:

>>> data = [1, 2, 3]
>>>
>>> for number in data:
...     print(number)
1
2
3
>>> data = ['a', 'b', 'c']
>>>
>>> for letter in data:
...     print(letter)
a
b
c

Ok names:

>>> data = ['a', 'b', 'c']
>>>
>>> for item in data:
...     print(item)
a
b
c
>>> data = ['a', 'b', 'c']
>>>
>>> for value in data:
...     print(value)
a
b
c

Bad names:

>>> data = ['a', 'b', 'c']
>>>
>>> for element in data:
...     print(element)
a
b
c

Very bad names: i (by convention it is a loop counter):

>>> data = ['a', 'b', 'c']
>>>
>>> for i in data:
...     print(i)
a
b
c

12.1.9. Note to the Programmers of Other Languages

  • In programming we have multiple types of loops: for, foreach, while, do while, until, loop

  • In Python we have two types of loops: for, while

  • Python for behaves like foreach in other languages

There are several types of loops in general:

  • for

  • foreach

  • while

  • do while

  • until

But in Python we have only two:

  • while

  • for

This does not takes into consideration comprehensions and generator expressions, which will be covered in next chapters.

Note, that Python for is not the same as for in other languages, such as C, C++, C#, JAVA, Java Script. Python for loop is more like foreach. Check the following example in JAVA:

char[] DATA = {'a', 'b', 'c'};

forEach (var letter : DATA) {
    System.out.println(letter);
}
$data = array('a', 'b', 'c');

foreach ($data as $letter) {
    echo $letter;
}
DATA = ['a', 'b', 'c']

for (let letter of DATA) {
    console.log(letter)
}

And this relates to Python regular for loop:

>>> DATA = ['a', 'b', 'c']
>>>
>>> for letter in DATA:
...     print(letter)
a
b
c

Regular for loop in other languages looks like that (example in C++):

char DATA[] = {'a', 'b', 'c'}

for (int i = 0; i < std::size(DATA); i++) {
   letter = data[i];
   printf(letter);
}

Python equivalent will be:

>>> DATA = ['a', 'b', 'c']
>>> i = 0
>>>
>>> while i < len(DATA):
...     letter = DATA[i]
...     print(letter)
...     i += 1
a
b
c

Yes, that's true, it is a while loop. This is due to the fact, that for loop from other languages is more like a while loop in Python.

Nevertheless, the very common bad practice is to do range(len()):

>>> data = ['a', 'b', 'c']
>>>
>>> for i in range(len(data)):
...     letter = data[i]
...     print(letter)
a
b
c

Note, how similar are those concepts. This is trying to take syntax from other languages and apply it to Python. range(len()) is considered a bad practice and it will not work with generators. But it gives similar look-and-feel.

Please remember:

  • Python for is more like foreach in other languages.

  • Python while is more like for in other languages.

foreach data as x:
    print(x)

12.1.10. Recap

  • Iterating works for builtin sequences

  • Works with: str, bytes, list, tuple, set, dict

  • Naming Current Element: letter, digit, number, user, color, sentence

Iterating Str:

>>> DATA = 'abc'
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating Tuple:

>>> DATA = ('a', 'b', 'c')
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating List:

>>> DATA = ['a', 'b', 'c']
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating Set:

>>> DATA = {'a', 'b', 'c'}
>>>
>>> for x in sorted(DATA):
...     print(x)
a
b
c

12.1.11. Assignments

# %% About
# - Name: For About Count
# - Difficulty: easy
# - Lines: 7
# - Minutes: 5

# %% 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

# %% English
# 1. Count occurrences of each color in `DATA`
# 2. Define `red: int` with number of occurrences of string "red" in `DATA`
# 3. Define `green: int` with number of occurrences of string "green" in `DATA`
# 4. Define `blue: int` with number of occurrences of string "blue" in `DATA`
# 5. Use `for` loop
# 6. Do not use `list.count()`
# 7. Run doctests - all must succeed

# %% Polish
# 1. Zlicz wystąpienia każdego z kolorów w `DATA`
# 2. Zdefiniuj zmienną `red` z liczbą wystąpień ciągu znaków "red" w `DATA`
# 3. Zdefiniuj zmienną `green` z liczbą wystąpień ciągu znaków "green" w `DATA`
# 4. Zdefiniuj zmienną `blue` z liczbą wystąpień ciągu znaków "blue" w `DATA`
# 5. Użyj pętli `for`
# 6. Nie używaj `list.count()`
# 7. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# red = 3
# green = 2
# blue = 2

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert red is not Ellipsis, \
'Assign your result to variable `red`'
>>> assert green is not Ellipsis, \
'Assign your result to variable `green`'
>>> assert blue is not Ellipsis, \
'Assign your result to variable `blue`'

>>> assert type(red) is int, \
'Variable `red` has invalid type, should be list'
>>> assert type(green) is int, \
'Variable `green` has invalid type, should be list'
>>> assert type(blue) is int, \
'Variable `blue` has invalid type, should be list'

>>> red
3
>>> green
2
>>> blue
2
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
red: int
green: int
blue: int

# %% Data
DATA = ['red', 'green', 'blue', 'red', 'green', 'red', 'blue']

red = 0
green = 0
blue = 0

# %% Result

# %% About
# - Name: For About Counter
# - Difficulty: easy
# - Lines: 5
# - Minutes: 5

# %% 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

# %% English
# 1. Count occurrences of each color in `DATA`
# 2. Define `result: dict`:
#    - key: color name (str)
#    - value: number of occurrences (int)
# 3. Use `for` loop to iterate over `DATA`
# 4. Do not use `list.count()`
# 5. Run doctests - all must succeed

# %% Polish
# 1. Zlicz wystąpienia każdego z kolorów w `DATA`
# 2. Zdefiniuj `result: dict`:
#    - klucz: nazwa koloru (str)
#    - wartość: liczba wystąpień (int)
# 3. Użyj pętli `for` do iterowania po `DATA`
# 4. Nie używaj `list.count()`
# 5. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# {'red': 3, 'green': 2, 'blue': 2}

# %% Hints
# - Check if `color` is already in `result`
# - If does not exist, then add it to `result` with value 1
# - If exists, then increment the value by 1

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is dict, \
'Variable `result` has invalid type, should be dict'
>>> assert all(type(x) is int for x in result.values()), \
'All values must be `int`'
>>> assert 'red' in result.keys()
>>> assert 'green' in result.keys()
>>> assert 'blue' in result.keys()

>>> result
{'red': 3, 'green': 2, 'blue': 2}
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: dict[str,int]

# %% Data
DATA = ['red', 'green', 'blue', 'red', 'green', 'red', 'blue']

# %% Result
result = ...

# %% About
# - Name: For About Segmentation
# - Difficulty: easy
# - Lines: 10
# - Minutes: 8

# %% 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

# %% English
# 1. Count numbers in ranges (lower included, upper excluded)
# 2. Define `small: int` - with count of numbers between 0 and 3
# 3. Define `medium: int` - with count of numbers between 3 and 7
# 4. Define `large: int` - with count of numbers between 7 and 10
# 5. Use `for` loop to iterate over `DATA`
# 6. Run doctests - all must succeed

# %% Polish
# 1. Zlicz liczby w przedziałach (dolny włącznie, górny rozłącznie)
# 2. Zdefiniuj `small: int` - liczba wystąpień liczb pomiędzy 0 i 3
# 3. Zdefiniuj `medium: int` - liczba wystąpień liczb pomiędzy 3 i 7
# 4. Zdefiniuj `large: int` - liczba wystąpień liczb pomiędzy 7 i 10
# 5. Użyj pętli `for` do iterowania po `DATA`
# 6. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# {'small': 16, 'medium': 19, 'large': 15}

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is dict, \
'Variable `result` has invalid type, should be dict'

>>> assert all(type(x) is str for x in result.keys())
>>> assert all(type(x) is int for x in result.values())

>>> result
{'small': 16, 'medium': 19, 'large': 15}
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: dict[str,int]

# %% Data
DATA = [
    1, 4, 6, 7, 4, 4, 4, 5, 1, 7, 0,
    0, 6, 5, 0, 0, 9, 7, 0, 4, 4, 8,
    2, 4, 0, 0, 1, 9, 1, 7, 8, 8, 9,
    1, 3, 5, 6, 8, 2, 8, 1, 3, 9, 5,
    4, 8, 1, 9, 6, 3,
]

# %% Result
result = {'small': 0, 'medium': 0, 'large': 0}

# %% About
# - Name: For About Newlines
# - Difficulty: easy
# - Lines: 2
# - Minutes: 5

# %% 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

# %% English
# 1. Join lines from `DATA` with newline character `\n`
# 2. Define `result: str` with the result
# 3. Use `for` loop to iterate over `DATA`
# 4. Do not use `str.join()`
# 5. Run doctests - all must succeed

# %% Polish
# 1. Złącz linie z `DATA` za pomocą znaku końca linii `\n`
# 2. Zdefiniuj `result: str`z wynikiem
# 3. Użyj pętli `for` do iterowania po `DATA`
# 4. Nie używaj `str.join()`
# 5. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# ('Nobody expects the Spanish Inquisition!\n'
#  'Our chief weapon is surprise.\n'
#  ...
#  'Fear and surprise.\n')

# %% Hints
# - POSIX defines a line as a string with a newline at the end
# - `str += str` - increment add operator

# %% References
# [1] Monty Python
#     The Spanish Inquisition
#     Year: 1970
#     Retrieved: 2025-02-27
#     URL :https://people.csail.mit.edu/paulfitz/spanish/script.html

# %% Doctests
"""
>>> 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 str, \
'Variable `result` has invalid type, should be str'

>>> result.count('\\n')
4

>>> pprint(result)
('Nobody expects the Spanish Inquisition!\\n'
 'Our chief weapon is surprise.\\n'
 'Surprise and fear.\\n'
 'Fear and surprise.\\n')
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: str

# %% Data
DATA = [
    'Nobody expects the Spanish Inquisition!',
    'Our chief weapon is surprise.',
    'Surprise and fear.',
    'Fear and surprise.'
]

# %% Result
result = ...

# %% About
# - Name: For About Remove PL Chars
# - Difficulty: easy
# - Lines: 2
# - Minutes: 5

# %% 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

# %% English
# 1. Convert polish characters in `DATA` to their counterparts without "accents"
# 2. If letter is in `PL` then use conversion value as letter
# 3. Define `result: str` with the result
# 4. Use `for` to iterate over `DATA`
# 5. Add letter to `result`
# 6. Run doctests - all must succeed

# %% Polish
# 1. Przekonwertuj polskie znaki w `DATA` na ich odpowiedniki bez "ogonków"
# 2. Jeżeli litera jest w `PL` to użyj przekonwertowanej wartości jako litera
# 3. Zdefiniuj `result: str` z wynikiem
# 4. Użyj pętli `for`
# 5. Dodaj literę do `result`
# 6. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# 'zazolc gesla jazn'

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is str, \
'Variable `result` has invalid type, should be str'

>>> result
'zazolc gesla jazn'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: str

# %% Data
PL = {
    'ą': 'a',
    'ć': 'c',
    'ę': 'e',
    'ł': 'l',
    'ń': 'n',
    'ó': 'o',
    'ś': 's',
    'ż': 'z',
    'ź': 'z',
}

DATA = 'zażółć gęślą jaźń'

# %% Result
result = ...

# %% About
# - Name: For About Months
# - Difficulty: easy
# - Lines: 4
# - Minutes: 5

# %% 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

# %% English
# 1. Convert `MONTH` into `result: dict[int,str]`:
#    - Keys: month number
#    - Values: month name
# 2. Run doctests - all must succeed

# %% Polish
# 1. Przekonwertuj `MONTH` w `result: dict[int,str]`:
#    - klucz: numer miesiąca
#    - wartość: nazwa miesiąca
# 2. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# {1: 'January',
#  2: 'February',
#  3: 'March',
#  ...
#  11: 'November',
#  12: 'December'}

# %% Doctests
"""
>>> 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 dict, \
'Variable `result` has invalid type, should be dict'

>>> assert all(type(x) is int for x in result.keys())
>>> assert all(type(x) is str for x in result.values())
>>> assert all(x in result.keys() for x in range(1, 13))
>>> assert all(x in result.values() for x in MONTHS)

>>> 13 not in result
True
>>> 0 not in result
True

>>> pprint(result)
{1: 'January',
 2: 'February',
 3: 'March',
 4: 'April',
 5: 'May',
 6: 'June',
 7: 'July',
 8: 'August',
 9: 'September',
 10: 'October',
 11: 'November',
 12: 'December'}
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: dict[int,str]

# %% Data
MONTHS = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
]

# %% Result
result = ...

# %% About
# - Name: For About Endswith
# - Difficulty: easy
# - Lines: 5
# - Minutes: 5

# %% 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

# %% English
# 1. Define `result: list` with email addresses from `DATA`,
#    having domain name mentioned in `DOMAINS`
# 2. Domain name is a part of the email address after `@` character
# 3. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj `result: list` z adresami email z `DATA`,
#    mającymi domenę wymienioną w `DOMAINS`
# 2. Nazwa domeny to część adresu email po znaku `@`
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# ['alice@example.com',
#  'bob@example.com',
#  ...
#  'mallory@example.net']

# %% Why
# - Check if you can filter data
# - Check if you know string methods
# - Check if you know how to iterate over list[dict]

# %% Doctests
"""
>>> 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 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'

>>> result = sorted(result)
>>> pprint(result)
['alice@example.com',
 'bob@example.com',
 'carol@example.com',
 'mallory@example.net']
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: list[str]

# %% Data
DATA = [
    {'name': 'Alice', 'email': 'alice@example.com'},
    {'name': 'Bob', 'email': 'bob@example.com'},
    {'name': 'Carol', 'email': 'carol@example.com'},
    {'name': 'Dave', 'email': 'dave@example.org'},
    {'name': 'Eve', 'email': 'eve@example.org'},
    {'name': 'Mallory', 'email': 'mallory@example.net'},
]

DOMAINS = ('example.com', 'example.net')

# %% Result
result = ...