13.4. For Patterns — Python
Range - when you need a sequential number
Range of Length - when you need: index
Enumerate - when you need: index and element
Zip - when you need elements at the same index from both A and B sequences
13.4.1. Range
range(stop)range(start, stop)range(start, stop, step)Negative step means reverse order
Range from 0 to 5:
>>> for x in range(0, 5): ... print(x) ... 0 1 2 3 4
5-times (equivalent to range(0,5)):
>>> for x in range(5): ... print(x) ... 0 1 2 3 4
Step (each second element from 0 to 5):
>>> for x in range(0, 5, 2): ... print(x) ... 0 2 4
Negative step (each element from 5 to 0):
>>> for x in range(5, 0, -1): ... print(x) ... 5 4 3 2 1
Negative step (each second element from 5 to 0):
>>> for x in range(5, 0, -2): ... print(x) ... 5 3 1
13.4.2. Range of Length
In most cases it's a bad practice
This is a pattern taken from other languages and applied to Python
In Python we use
forloop for doing thatThat's because Python
forloop is aforeachloopAlso
for x in range(len(...))twice as slow as plainfor x in ...
>>> users = ['alice', 'bob', 'carol'] >>> >>> for i in range(len(users)): ... user = users[i] ... print(user) ... alice bob carol
But the following is more Pythonic:
>>> users = ['alice', 'bob', 'carol'] >>> >>> for user in users: ... print(user) ... alice bob carol
The output is exactly the same. The second example is more Pythonic and easier to read.
Performance:
>>> users = ['alice', 'bob', 'carol'] >>> >>> ## doctest: +SKIP ... %%timeit -r1000 -n1000 ... for user in users: ... pass ... 36.1 ns ± 7.42 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) 34.1 ns ± 5.85 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) 36.6 ns ± 8.1 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) 36.6 ns ± 7 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) 34.6 ns ± 8.2 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
>>> users = ['alice', 'bob', 'carol'] >>> >>> ## doctest: +SKIP ... %%timeit -r1000 -n 1000 ... for i in range(len(users)): ... user = users[i] ... 72.5 ns ± 15.2 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) 71.3 ns ± 14.6 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) 71 ns ± 14.8 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) 71.8 ns ± 14.8 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) 72.9 ns ± 16.5 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
Date: 2024-12-05
Python: 3.13.0
IPython: 8.30.0
System: macOS 15.1.1
Computer: MacBook M3 Max
CPU: 16 cores (12 performance and 4 efficiency) / 3nm
RAM: 128 GB RAM LPDDR5
13.4.3. Enumerate
Later you will learn builtin
enumerate()function which does that
>>> users = ['alice', 'bob', 'carol'] >>> i = 0 >>> >>> for user in users: ... print(f'{i=}, {user=}') ... i += 1 ... i=0, user='alice' i=1, user='bob' i=2, user='carol'
13.4.4. Zip
Later you will learn builtin
zip()function which does that
>>> dataA = ['Alice', 'Bob', 'Carol'] >>> dataB = ['Apricot', 'Blackthorn', 'Corn'] >>> >>> times = min(len(dataA), len(dataB)) # 3 >>> >>> for i in range(times): # for i in range(3) ... a = dataA[i] ... b = dataB[i] ... print(f'{a=}, {b=}') ... a='Alice', b='Apricot' a='Bob', b='Blackthorn' a='Carol', b='Corn'
Because:
>>> dataA = ['Alice', 'Bob', 'Carol'] >>> dataB = ['Apricot', 'Blackthorn', 'Corn'] >>> >>> >>> a = dataA[0] >>> b = dataB[0] >>> print(f'{a=}, {b=}') a='Alice', b='Apricot' >>> >>> a = dataA[1] >>> b = dataB[1] >>> print(f'{a=}, {b=}') a='Bob', b='Blackthorn' >>> >>> a = dataA[2] >>> b = dataB[2] >>> print(f'{a=}, {b=}') a='Carol', b='Corn'
13.4.5. Recap
Range - when you need a sequential number
Range of Length - when you need: index
Enumerate - when you need: index and element
Zip - when you need elements at the same index from both A and B sequences
Range:
>>> for x in range(3): ... print(x) ... 0 1 2
Range of Length:
>>> users = ['alice', 'bob', 'carol'] >>> >>> for i in range(len(users)): ... user = users[i] ... print(user) ... alice bob carol
Enumerate:
>>> users = ['alice', 'bob', 'carol'] >>> i = 0 >>> >>> for user in users: ... print(f'{i=}, {user=}') ... i += 1 ... i=0, user='alice' i=1, user='bob' i=2, user='carol'
Zip:
>>> dataA = ['Alice', 'Bob', 'Carol'] >>> dataB = ['Apricot', 'Blackthorn', 'Corn'] >>> >>> times = min(len(dataA), len(dataB)) # 3 >>> >>> for i in range(times): # for i in range(3) ... a = dataA[i] ... b = dataB[i] ... print(f'{a=}, {b=}') ... a='Alice', b='Apricot' a='Bob', b='Blackthorn' a='Carol', b='Corn'
13.4.6. Assignments
# %% About # - Name: For Patterns Range # - Difficulty: easy # - Lines: 3 # - Minutes: 3 # %% 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. Generate list of integers from 0 (inclusive) to 5 (exclusive) # 2. Define variable `result` with the solution # 3. Use for-range pattern # 4. Run doctests - all must succeed # %% Polish # 1. Wygeneruj listę liczb całkowitych od 0 (włącznie) do 5 (rozłącznie) # 2. Zdefiniuj zmienną `result` z rozwiązaniem # 3. Użyj wzorca for-range # 4. Uruchom doctesty - wszystkie muszą się powieść # %% Expected # >>> result # [0, 1, 2, 3, 4] # %% Doctests """ >>> import sys; sys.tracebacklimit = 0 >>> assert sys.version_info >= (3, 9), \ 'Python has an is invalid version; expected: `3.9` or newer.' >>> assert 'result' in globals(), \ 'Variable `result` is not defined; assign result of your program to it.' >>> assert result is not Ellipsis, \ 'Variable `result` has an invalid value; assign result of your program to it.' >>> assert type(result) is list, \ 'Variable `result` has an invalid type; expected: `list`.' >>> assert all(type(x) is int for x in result), \ 'Variable `result` has elements of an invalid type; all items should be: `int`.' >>> from pprint import pprint >>> pprint(result, width=79, sort_dicts=False) [0, 1, 2, 3, 4] """ # %% Run # - PyCharm: right-click in the editor and `Run Doctest in ...` # - PyCharm: keyboard shortcut `Control + Shift + F10` # - Terminal: `python -m doctest -f -v myfile.py` # %% Imports # %% Types result: list[int] # %% Data # %% Result result = ...
# %% About # - Name: For Patterns Enumerate # - Difficulty: easy # - Lines: 6 # - 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 `MONTHS` to list of tuples with month numbers and names # 2. Define variable `result` with the solution: # - first element: month number (from 1 to 12) # - second element: month name (January, February, March, ...) # 3. Month numbers starts with 1 # 4. Use `for-enumerate` pattern # 5. Do not use builtin function `enumerate()` # 6. Run doctests - all must succeed # %% Polish # 1. Przekonwertuj `MONTHS` do listy krotek z numerami i nazwami miesięcy # 2. Zdefiniuj zmienną `result` z rozwiązaniem: # - pierwszy element: numer miesiąca (od 1 do 12) # - drugi element: nazwa miesiąca (January, February, March, ...) # 3. Numery miesięcy zaczynają się od 1 # 4. Użyj wzorca `for-enumerate` # 5. Nie używaj wbudowanej funkcji `enumerate()` # 6. Uruchom doctesty - wszystkie muszą się powieść # %% Expected # >>> 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')] # %% Doctests """ >>> import sys; sys.tracebacklimit = 0 >>> assert sys.version_info >= (3, 9), \ 'Python has an is invalid version; expected: `3.9` or newer.' >>> assert 'result' in globals(), \ 'Variable `result` is not defined; assign result of your program to it.' >>> assert result is not Ellipsis, \ 'Variable `result` has an invalid value; assign result of your program to it.' >>> assert type(result) is list, \ 'Variable `result` has an invalid type; expected: `list`.' >>> assert all(type(x) is tuple for x in result), \ 'Variable `result` has elements of an invalid type; all items should be: `tuple`.' >>> assert len(result) == 12, \ 'Variable `result` has an invalid length; expected: `12`.' >>> assert all(i>0 for i,month in result), \ 'Month number must be greater than 0' >>> assert all(i<13 for i,month in result), \ 'Month number must be less than 13' >>> from pprint import pprint >>> pprint(result, width=79, sort_dicts=False) [(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 -f -v myfile.py` # %% Imports # %% Types result: list[tuple] # %% Data MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ] # %% Result result = ...
# %% About # - Name: For Patterns Zip # - 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. Merge `FIRSTNAMES` and `LASTNAMES` into list of tuples # 2. Define variable `result` with the solution: # - first element - firstname # - second element - lastname # 3. Use `for-zip` pattern # 4. Do not use builtin function `zip()` # 5. Run doctests - all must succeed # %% Polish # 1. Połącz `FIRSTNAMES` i `LASTNAMES` w listę krotek # 2. Zdefiniuj `result` z rozwiązaniem: # - pierwszy element - imię # - drugi element - nazwisko # 3. Użyj wzorca `for-zip` # 4. Nie używaj wbudowanej funkcji `zip()` # 5. Uruchom doctesty - wszystkie muszą się powieść # %% Expected # >>> result # [('Alice', 'Apricot'), # ('Bob', 'Blackthorn'), # ('Carol', 'Corn')] # %% Doctests """ >>> import sys; sys.tracebacklimit = 0 >>> assert sys.version_info >= (3, 9), \ 'Python has an is invalid version; expected: `3.9` or newer.' >>> assert 'result' in globals(), \ 'Variable `result` is not defined; assign result of your program to it.' >>> assert result is not Ellipsis, \ 'Variable `result` has an invalid value; assign result of your program to it.' >>> assert type(result) is list, \ 'Variable `result` has an invalid type; expected: `list`.' >>> assert all(type(x) is tuple for x in result), \ 'Variable `result` has elements of an invalid type; all items should be: `tuple`.' >>> from pprint import pprint >>> pprint(result, width=30, sort_dicts=False) [('Alice', 'Apricot'), ('Bob', 'Blackthorn'), ('Carol', 'Corn')] """ # %% Run # - PyCharm: right-click in the editor and `Run Doctest in ...` # - PyCharm: keyboard shortcut `Control + Shift + F10` # - Terminal: `python -m doctest -f -v myfile.py` # %% Imports # %% Types result: list[tuple] # %% Data FIRSTNAMES = ['Alice', 'Bob', 'Carol'] LASTNAMES = ['Apricot', 'Blackthorn', 'Corn'] # %% Result result = ...
# %% About # - Name: For Patterns Zip # - Difficulty: easy # - Lines: 6 # - 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 `HEADER` and `ROW` to `dict` # 2. Define variable `result` with the solution: # - key: column name from the header (firstname, lastname lub age) # - value: value from the row (ie. Alice, Apricot, 30) # 3. Use `for-zip` pattern # 4. Do not use builtin function `zip()` # 5. Run doctests - all must succeed # %% Polish # 1. Przekonwertuj `HEADER` i `ROW` do `dict` # 2. Zdefiniuj zmienną `result` z rozwiązaniem: # - klucz: nazwa kolumny z nagłówka (firstname, lastname lub age) # - wartość: wartość z wiersza (np. Alice, Apricot, 30) # 3. Użyj wzorca `for-zip` # 4. Nie używaj wbudowanej funkcji `zip()` # 5. Uruchom doctesty - wszystkie muszą się powieść # %% Expected # >>> result # {'firstname': 'Alice', # 'lastname': 'Apricot', # 'age': 30} # %% Doctests """ >>> import sys; sys.tracebacklimit = 0 >>> assert sys.version_info >= (3, 9), \ 'Python has an is invalid version; expected: `3.9` or newer.' >>> assert 'result' in globals(), \ 'Variable `result` is not defined; assign result of your program to it.' >>> assert result is not Ellipsis, \ 'Variable `result` has an invalid value; assign result of your program to it.' >>> assert type(result) is dict, \ 'Variable `result` has an invalid type; expected: `dict`.' >>> from pprint import pprint >>> pprint(result, width=30, sort_dicts=False) {'firstname': 'Alice', 'lastname': 'Apricot', 'age': 30} """ # %% Run # - PyCharm: right-click in the editor and `Run Doctest in ...` # - PyCharm: keyboard shortcut `Control + Shift + F10` # - Terminal: `python -m doctest -f -v myfile.py` # %% Imports # %% Types result: dict[str, str|int] # %% Data HEADER = ('firstname', 'lastname', 'age') ROW = ('Alice', 'Apricot', 30) # %% Result result = ...
# %% About # - Name: For Patterns Iterable Zip # - Difficulty: medium # - Lines: 11 # - 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. Convert `list[tuple]` to `list[dict]` # 2. Define variable `result` with the solution: # - key: column name from the header (firstname, lastname lub age) # - value: value from the row (ie. Alice, Apricot, 30) # 3. Use `for-zip` pattern # 4. Do not use builtin function `zip()` # 5. Run doctests - all must succeed # %% Polish # 1. Przekonwertuj `list[tuple]` do `list[dict]` # 2. Zdefiniuj zmienną `result` z rozwiązaniem: # - klucz: nazwa kolumny z nagłówka (firstname, lastname lub age) # - wartość: wartość z wiersza (np. Alice, Apricot, 30) # 3. Użyj wzorca `for-zip` # 4. Nie używaj wbudowanej funkcji `zip()` # 5. Uruchom doctesty - wszystkie muszą się powieść # %% Expected # >>> result # [{'firstname': 'Alice', 'lastname': 'Apricot', 'age': 30}, # {'firstname': 'Bob', 'lastname': 'Blackthorn', 'age': 31}, # {'firstname': 'Carol', 'lastname': 'Corn', 'age': 32}, # {'firstname': 'Dave', 'lastname': 'Durian', 'age': 33}, # {'firstname': 'Eve', 'lastname': 'Elderberry', 'age': 34}, # {'firstname': 'Mallory', 'lastname': 'Melon', 'age': 15}] # %% Doctests """ >>> import sys; sys.tracebacklimit = 0 >>> assert sys.version_info >= (3, 9), \ 'Python has an is invalid version; expected: `3.9` or newer.' >>> assert 'result' in globals(), \ 'Variable `result` is not defined; assign result of your program to it.' >>> assert result is not Ellipsis, \ 'Variable `result` has an invalid value; assign result of your program to it.' >>> assert type(result) is list, \ 'Variable `result` has an invalid type; expected: `list`.' >>> assert all(type(x) is dict for x in result) >>> from pprint import pprint >>> pprint(result, width=120, sort_dicts=False) [{'firstname': 'Alice', 'lastname': 'Apricot', 'age': 30}, {'firstname': 'Bob', 'lastname': 'Blackthorn', 'age': 31}, {'firstname': 'Carol', 'lastname': 'Corn', 'age': 32}, {'firstname': 'Dave', 'lastname': 'Durian', 'age': 33}, {'firstname': 'Eve', 'lastname': 'Elderberry', 'age': 34}, {'firstname': 'Mallory', 'lastname': 'Melon', 'age': 15}] """ # %% Run # - PyCharm: right-click in the editor and `Run Doctest in ...` # - PyCharm: keyboard shortcut `Control + Shift + F10` # - Terminal: `python -m doctest -f -v myfile.py` # %% Imports # %% Types result: list[dict[str,str|int]] # %% Data DATA = [ ('firstname', 'lastname', 'age'), ('Alice', 'Apricot', 30), ('Bob', 'Blackthorn', 31), ('Carol', 'Corn', 32), ('Dave', 'Durian', 33), ('Eve', 'Elderberry', 34), ('Mallory', 'Melon', 15), ] # %% Result result = ...