7.2. Loop For¶
7.2.1. Rationale¶
>>> data = ['a', 'b', 'c']
>>> i = 0
>>>
>>> while i < len(data):
... x = data[i]
... print(x)
... i += 1
a
b
c
>>> data = ['a', 'b', 'c']
>>>
>>> for x in data:
... print(x)
a
b
c
7.2.2. Syntax¶
ITERABLE
must implementiterator
interfaceMore information in Protocol Iterator
For loop syntax:
for <variable> in <iterable>:
<do something>
>>> for digit in [1, 2, 3]:
... pass
7.2.3. Convention¶
The longer the loop scope, the longer the variable name should be
Avoid one letters if scope is longer than one line
Prefer locally meaningful name over generic names
Generic names:
obj
- generic name (in Python everything is an object)element
- generic nameitem
- generic namex
- ok for oneliners, bad for more than one linee
- ok for oneliners, bad for more than one linel
- bado
- badd
- bad (for digit)
Locally meaningful name:
letter
feature
digit
person
color
username
etc.
Special meaning (by convention):
i
- for loop counter_
- if value is not used
>>> for x in [1, 2, 3]:
... print(x)
1
2
3
>>> for i in range(0,3):
... print(i)
0
1
2
>>> for _ in range(3):
... spawn_thread()
7.2.4. Iterating Sequences¶
Iterating works for builtin sequences:
str
bytes
list
tuple
set
frozenset
dict
>>> DATA = 'NASA'
>>>
>>> for letter in DATA:
... print(letter)
N
A
S
A
>>> DATA = [1, 2, 3]
>>>
>>> for digit in DATA:
... print(digit)
1
2
3
>>> DATA = ['a', 'b', 'c']
>>>
>>> for letter in DATA:
... print(letter)
a
b
c
>>> CREW = ['Mark Watney', 'Melissa Lewis', 'Rick Martinez']
>>>
>>> for astronaut in CREW:
... print(astronaut)
Mark Watney
Melissa Lewis
Rick Martinez
>>> DATA = [5.1, 3.5, 1.4, 0.2, 'setosa']
>>>
>>> for value in DATA:
... print(value)
5.1
3.5
1.4
0.2
setosa
7.2.5. Range¶
range(start, stop, step)
start
is inclusive, default:0
stop
is exclusive, requiredstep
default:1
>>> range(0, 5)
range(0, 5)
>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(0, 5))
[0, 1, 2, 3, 4]
>>> list(range(0, 5, 1))
[0, 1, 2, 3, 4]
>>> list(range(0, 5, 2))
[0, 2, 4]
Loops with range
:
>>> for i in range(0, 3):
... print(i)
0
1
2
Loops with range
:
>>> for number in range(4, 11, 2):
... print(number)
4
6
8
10
7.2.6. Note to the Programmers of 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);
}
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 likeforeach
in other languages.Python
while
is more likefor
in other languages.
7.2.7. Nested Loops¶
You can have loop inside a loop:
>>> for row in [1, 2, 3]: # doctest: +NORMALIZE_WHITESPACE
... print()
...
... for column in ['A', 'B', 'C']:
... print(f'{column}{row}', end=' ')
A1 B1 C1
A2 B2 C2
A3 B3 C3
7.2.8. Assignments¶
"""
* Assignment: Loop For Count
* Complexity: easy
* Lines of code: 7 lines
* Time: 5 min
English:
1. Use data from "Given" section (see below)
2. Count occurrences of each color
3. Compare results with "Tests" section below
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Zlicz wystąpienia każdego z kolorów
3. Porównaj wynik z sekcją "Tests" poniżej
Tests:
>>> type(red)
<class 'int'>
>>> type(green)
<class 'int'>
>>> type(blue)
<class 'int'>
>>> red
3
>>> green
2
>>> blue
2
"""
# Given
DATA = ['red', 'green', 'blue', 'red', 'green', 'red', 'blue']
red = ... # int: number of 'red' elements in DATA
green = ... # int: number of 'green' elements in DATA
blue = ... # int: number of 'blue' elements in DATA
"""
* Assignment: Loop For Counter
* Complexity: easy
* Lines of code: 5 lines
* Time: 5 min
English:
1. Use data from "Given" section (see below)
2. Iterate over `DATA`
3. Count occurrences of each number
4. Create empty `result: dict[int, int]`:
a. key - digit
b. value - number of occurrences
5. Iterating over numbers check if number is already in `result`
a. If first occurrence, then add it to `result` with value 1
b. If exists, then increment the value by 1
6. Compare results with "Tests" section below
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Iteruj po `DATA`
3. Policz wystąpienia każdej z cyfr
4. Stwórz pusty `result: dict[int, int]`:
a. klucz - cyfra
b. wartość - liczba wystąpień
5. Iterując po cyfrach sprawdź czy cyfra znajduje się już w `result`
a. Jeżeli pierwsze wystąpienie, to dodaj ją do `result` z wartością 1
b. Jeżeli istnieje, to zwiększ w wartość o 1
6. Porównaj wynik z sekcją "Tests" poniżej
Tests:
>>> import sys
>>> sys.tracebacklimit = 0
>>> assert type(result) is dict
>>> assert all(type(x) is int for x in result.keys())
>>> assert all(type(x) is int for x in result.values())
>>> assert all(x in result.keys() for x in range(0, 10))
>>> result
{1: 7, 4: 8, 6: 4, 7: 4, 5: 4, 0: 7, 9: 5, 8: 6, 2: 2, 3: 3}
"""
# Given
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 = ... # dict[int,int]: number of occurrences of each digit from DATA
"""
* Assignment: Loop For Segmentation
* Complexity: easy
* Lines of code: 10 lines
* Time: 8 min
English:
1. Use data from "Given" section (see below)
2. Count occurrences of each group
3. Define groups:
a. `small` - numbers in range [0-3)
b. `medium` - numbers in range [3-7)
c. `large` - numbers in range [8-9]
4. Print `result: dict[str, int]`:
a. key - group
b. value - number of occurrences
5. Compare results with "Tests" section below
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Policz wystąpienia każdej z group
3. Zdefiniuj grupy
a. `small` - liczby z przedziału <0-3)
b. `medium` - liczby z przedziału <3-7)
c. `large` - liczby z przedziału <7-9>
4. Wypisz `result: dict[str, int]`:
a. klucz - grupa
b. wartość - liczba wystąpień
5. Porównaj wynik z sekcją "Tests" poniżej
Tests:
>>> import sys
>>> sys.tracebacklimit = 0
>>> type(result)
<class '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}
"""
# Given
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 = { # dict[str,int] number of digit occurrences in segments
'small': 0,
'medium': 0,
'large': 0}
"""
* Assignment: Loop For Newline
* Complexity: easy
* Lines of code: 2 lines
* Time: 5 min
English:
1. Use data from "Given" section (see below)
2. Define `result: str`
3. Use `for` to iterate over `DATA`
4. Join lines of text with newline (`\n`) character
5. Do not use `str.join()`
6. Compare result with "Tests" section (see below)
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Zdefiniuj `result: str`
3. Użyj `for` do iterowania po `DATA`
4. Połącz linie tekstu znakiem końca linii (`\n`)
5. Nie używaj `str.join()`
6. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> import sys
>>> sys.tracebacklimit = 0
>>> assert type(result) is str
>>> result.count('\\n')
3
>>> result # doctest: +NORMALIZE_WHITESPACE
'We choose to go to the Moon.\\nWe choose to go to the Moon in this decade
and do the other things.\\nNot because they are easy, but because they are
hard.\\n'
"""
# Given
DATA = [
'We choose to go to the Moon.',
'We choose to go to the Moon in this decade and do the other things.',
'Not because they are easy, but because they are hard.',
]
result = ... # str: DATA joined with newline - \n
"""
* Assignment: Loop For Translate
* Complexity: easy
* Lines of code: 2 lines
* Time: 5 min
English:
1. Use data from "Given" section (see below)
2. Define `result: str`
3. Use `for` to iterate over `DATA`
4. If letter is in `PL` then use conversion value as letter
5. Add letter to `result`
6. Compare result with "Tests" section (see below)
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Zdefiniuj `result: list`
3. Użyj `for` do iteracji po `DATA`
4. Jeżeli litera jest w `PL` to użyj przekonwertowanej wartości jako litera
5. Dodaj literę do `result`
6. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> type(result)
<class 'str'>
>>> result
'zazolc gesla jazn'
"""
# Given
PL = {
'ą': 'a',
'ć': 'c',
'ę': 'e',
'ł': 'l',
'ń': 'n',
'ó': 'o',
'ś': 's',
'ż': 'z',
'ź': 'z',
}
DATA = 'zażółć gęślą jaźń'
result = ... # str: DATA with substituted PL diacritic chars to ASCII letters
"""
* Assignment: Loop For Months
* Complexity: easy
* Lines of code: 4 lines
* Time: 5 min
English:
1. Use data from "Given" section (see below)
2. Convert `MONTH` into dict:
a. Keys: month number
b. Values: month name
3. Do not use `enumerate`
4. Compare result with "Tests" section (see below)
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Przekonwertuj `MONTH` w słownik:
a. klucz: numer miesiąca
b. wartość: nazwa miesiąca
3. Nie używaj `enumerate`
4. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> import sys
>>> sys.tracebacklimit = 0
>>> type(result)
<class '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
>>> result # doctest: +NORMALIZE_WHITESPACE
{1: 'January',
2: 'February',
3: 'March',
4: 'April',
5: 'May',
6: 'June',
7: 'July',
8: 'August',
9: 'September',
10: 'October',
11: 'November',
12: 'December'}
"""
# Given
MONTHS = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
result = ... # dict[int,str]: dict with month number and name. Start with 1
"""
* Assignment: Loop For Text
* Complexity: medium
* Lines of code: 14 lines
* Time: 13 min
English:
1. Use data from "Given" section (see below)
2. Given is text of the "Moon Speech" by John F. Kennedy's [1]
3. Sentences are separated by period (`.`)
4. Clean each sentence from whitespaces at the beginning and at the end
5. Words are separated by spaces
6. Print the total number in whole text:
a. adverbs (words ending with "ly")
b. sentences
c. words
d. letters
e. characters (including spaces inside sentences, but not comas `,`)
f. comas (`,`)
7. Compare results with "Tests" section below
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Dany jest tekst przemówienia "Moon Speech" wygłoszonej
przez John F. Kennedy'ego [1]
3. Zdania oddzielone są kropkami (`.`)
4. Każde zdanie oczyść z białych znaków na początku i końcu
5. Słowa oddzielone są spacjami
6. Wypisz także ile jest łącznie w całym tekście:
a. przysłówków (słów zakończonych na "ly")
b. zdań
c. słów
d. liter
e. znaków (łącznie ze spacjami wewnątrz zdań, ale bez przecinków `,`)
f. przecinków (`,`)
7. Porównaj wynik z sekcją "Tests" poniżej
References:
[1] Kennedy, J.F. Moon Speech - Rice Stadium.
Year: 1962.
Retrieved: 2021-03-06.
URL: http://er.jsc.nasa.gov/seh/ricetalk.htm
Tests:
>>> type(result)
<class 'dict'>
>>> print(result) # doctest: +NORMALIZE_WHITESPACE
{'sentences': 7,
'words': 71,
'characters': 347,
'letters': 283,
'commas': 1,
'adverbs': 0}
"""
# Given
TEXT = """
We choose to go to the Moon.
We choose to go to the Moon in this decade and do the other things.
Not because they are easy, but because they are hard.
Because that goal will serve to organize and measure the best of our energies and skills.
Because that challenge is one that we are willing to accept.
One we are unwilling to postpone.
And one we intend to win
"""
result = { # dict[str,int]: number of occurrences of each grammar object
'sentences': 0,
'words': 0,
'characters': 0,
'letters': 0,
'commas': 0,
'adverbs': 0,
}