Skip to content

Commit 7965a36

Browse files
committed
Add lessons on some special iterables: range, zip, enumerate
1 parent 765a174 commit 7965a36

6 files changed

Lines changed: 307 additions & 42 deletions

File tree

courses/pyladies/info.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ plan:
104104
url: https://pyvec.github.io/cheatsheets/lists/lists-cs.pdf
105105
type: cheatsheet
106106

107+
- title: Iterujeme
108+
slug: iteration
109+
materials:
110+
- lesson: beginners/range
111+
- lesson: beginners/zip-enumerate
112+
107113
- title: Grafika
108114
slug: pyglet
109115
materials:

lessons/beginners/range/index.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Range – sekvence čísel
2+
3+
Funkce `range(10)` vrátí speciální hodnotu,
4+
která v sobě obsahuje čísla od 0 do 9:
5+
6+
```pycon
7+
>>> sekvence = range(10)
8+
>>> sekvence
9+
range(0, 10)
10+
```
11+
12+
Je to hodnota typu `range`, podobně jako čísla jsou typu `int`, řetězce typu
13+
`str`, nebo seznamy typu `list`.
14+
15+
Chceš-li se podívat, co v tomhle `range(0, 10)` vlastně je, máš dvě základní
16+
možnosti – projít ho cyklem `for` nebo převést na seznam konkrétních čísel:
17+
18+
```pycon
19+
>>> sekvence
20+
range(0, 10)
21+
>>> for i in sekvence:
22+
... print(i)
23+
0
24+
1
25+
2
26+
3
27+
4
28+
5
29+
6
30+
7
31+
8
32+
9
33+
>>> list(sekvence)
34+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
35+
```
36+
37+
Možná se ptáš – proč tak složitě?
38+
Proč se místo `range(0, 10)` prostě ta čísla neukážou rovnou?
39+
40+
Je to proto, že `range` se dá použít na opravdu dlouhé řady čísel:
41+
42+
```pycon
43+
>>> range(10000)
44+
range(0, 10000)
45+
>>> list(range(10000))
46+
[0, 1, 2, 3, ..., 9999]
47+
```
48+
49+
Kdybys zkusil{{a}} třeba `list(range(1000000000000000000))`, počítači
50+
dojde paměť.
51+
Miliarda čísel se tam prostě nevejde.
52+
Python vyhodí výjimku `MemoryError`.
53+
Se samotným `range(1000000000000000000)` ale není problém.
54+
S konceptem čísel od 0 do miliardy se počítač vypořádá, i když si je neumí
55+
„zapamatovat“ všechny *najednou*.
56+
57+
Je spousta věcí, které Python umí s `range` udělat, aniž by potřeboval
58+
„spočítat“ každé z čísel.
59+
Spousta operací, které znáš od seznamů, bude fungovat i s `range`:
60+
61+
```pycon
62+
>>> zajimava_cisla = range(8, 10000, 3) # Každé třetí číslo od 8 do 9999
63+
>>> zajimava_cisla[80] # Osmdesáté "zajímavé číslo"
64+
248
65+
>>> zajimava_cisla[:5] # Prvních 5 "zajímavých čísel"
66+
range(8, 23, 3)
67+
>>> list(zajimava_cisla[:5]) # Vypsání prvních 5 "zajímavých čísel"
68+
[8, 11, 14, 17, 20]
69+
>>> len(zajimava_cisla) # Kolik tam je čísel?
70+
3331
71+
>>> 1337 in zajimava_cisla # Je v této sekvenci moje konkrétní číslo ?
72+
True
73+
>>> zajimava_cisla.index(1337) # Kolikáté je?
74+
443
75+
```
76+
77+
```pycon
78+
>>> import random
79+
>>> random.choice(zajimava_cisla)
80+
1229
81+
```
82+
83+
```pycon
84+
>>> for i in zajimava_cisla:
85+
... print(i)
86+
... if i > 20:
87+
... break # Stačilo!
88+
8
89+
11
90+
14
91+
17
92+
20
93+
23
94+
```
95+
96+
Objekt `range` ale nejde měnit – metody jako `zajimava_cisla.sort()`,
97+
`zajimava_cisla.pop()` fungovat nebudou.
98+

lessons/beginners/range/info.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
title: Range - sekvence čísel
2+
style: md
3+
attribution: Pro PyLadies Brno napsal Petr Viktorin, 2019.
4+
license: cc-by-sa-40

lessons/beginners/tuple/index.md

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -94,48 +94,6 @@ podil, zbytek = podil_a_zbytek(12, 5)
9494
> ```
9595
9696
97-
## Funkce, které vracejí <var>n</var>-tice
98-
99-
`zip` je zajímavá funkce.
100-
Používá se ve `for` cyklech, podobně jako funkce `range`, která „dává” čísla.
101-
102-
Když funkce `zip` dostane dva seznamy
103-
(či jiné věci použitelné ve `for`),
104-
„dává” dvojice, a to tak, že nejdřív spáruje
105-
první prvek jednoho seznamu s prvním prvkem
106-
druhého seznamu,
107-
pak druhý s druhým, třetí s třetím a tak dál.
108-
109-
Hodí se to, když máš dva seznamy se stejnou
110-
strukturou – příslušné prvky k sobě „patří”
111-
a chceš je zpracovávat společně:
112-
113-
```python
114-
osoby = 'máma', 'teta', 'babička', 'vrah'
115-
vlastnosti = 'hodná', 'milá', 'laskavá', 'zákeřný'
116-
for osoba, vlastnost in zip(osoby, vlastnosti):
117-
print('{} je {}'.format(osoba, vlastnost))
118-
```
119-
120-
Když `zip` dostane tři seznamy,
121-
bude tvořit trojice, ze čtyř seznamů nadělá čtveřice a tak dále.
122-
123-
Další funkce, která vrací dvojice, je `enumerate`.
124-
Jako argument bere seznam (či jinou věc použitelnou
125-
ve `for`) a vždy spáruje index (pořadí v seznamu) s příslušným prvkem.
126-
Jako první tedy dá
127-
(0, *první prvek seznamu*), potom
128-
(1, *druhý prvek seznamu*),
129-
(2, *třetí prvek seznamu*)
130-
a tak dále.
131-
132-
```python
133-
prvocisla = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
134-
135-
for i, prvocislo in enumerate(prvocisla):
136-
print('Prvočíslo č.{} je {}'.format(i, prvocislo))
137-
```
138-
13997
## Malé <var>n</var>-tice
14098
14199
Jak vytvořit <var>n</var>-tici s žádným nebo jedním prvkem? Takhle:
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Iterátory n-tic
2+
3+
Některé hodnoty v Pythonu jsou *iterovatelné* (angl. *iterable*):
4+
obsahují sekvenci jiných hodnot a lze je „projít“ (iterovat) cyklem `for` nebo
5+
je převést na seznam.
6+
Už jich známe několik:
7+
8+
```pycon
9+
>>> list(range(10)) # sekvence čísel
10+
>>> list('ahoj') # řetězec
11+
>>> list(['Ahoj', 'Hello', 'Hei']) # seznam
12+
>>> list((12, 'Sr', True)) # n-tice
13+
```
14+
15+
Spousta těchto typů umí něco navíc: zjistit jestli obsahují nějaký prvek
16+
(`4 in range(10)`), zjistit délku (`len([1, 2, 3])`), převést na velká písmena
17+
(`'abc'.upper()`).
18+
Nic z toho ale není potřeba, aby byl objekt iterovatelný.
19+
20+
Podívejme se na dva dalších iterovatelné objekty: `enumerate` a `zip`.
21+
22+
23+
## Enumerate: očíslování sekvence
24+
25+
Funkce `enumerate` vezme nějakou existující sekvenci a *očísluje ji*:
26+
ve vrácené sekvenci budou dvojice (index, původní hodnota).
27+
28+
Řekněme že máš tento seznam:
29+
30+
```python
31+
trpaslici = ['Prófa', 'Stydlín', 'Dřímal', 'Kejchal', 'Štístko',
32+
'Šmudla', 'Rejpal']
33+
```
34+
35+
Když na něj použiješ `enumerate`, dostaneš objekt `enumerate`,
36+
který podobně jako `range()` neukáže svůj obsah „rovnou“,
37+
ale můžeš se „do něj“ podívat převedením na seznam.
38+
Uvidíš tak seznam dvojic (číslo, trpaslík):
39+
40+
```pycon
41+
>>> enumerate(trpaslici)
42+
<enumerate object at 0x7f0db61b29d8>
43+
>>> list(enumerate(trpaslici))
44+
[(0, 'Prófa'), (1, 'Stydlín'), (2, 'Dřímal'), (3, 'Kejchal'), (4, 'Štístko'), (5, 'Šmudla'), (6, 'Rejpal')]
45+
```
46+
47+
Místo převedení na seznam můžeš přes objekt `enumerate` iterovat cyklem `for`
48+
a pro každou dvojici něco udělat.
49+
Třeba ji hezky vypsat:
50+
51+
```python
52+
for dvojice in enumerate(trpaslici):
53+
# Rozbalení dvojice
54+
index, trpaslik = dvojice
55+
# Vypsání
56+
print(f'Na pozici {index} je {trpaslik}!')
57+
```
58+
59+
Objekt, který funkce `enumerate` vrací, je *iterátor dvojic* – sekvence,
60+
jejíž prvky jsou dvojice.
61+
62+
## Rozbalování v cyklu for
63+
64+
„Trpasličí“ cyklus se dá rozepsat takto:
65+
66+
```python
67+
dvojice = 0, 'Prófa' # toto dělá `for`
68+
index, trpaslik = dvojice
69+
print(f'Na pozici {index} je {trpaslik}!')
70+
71+
dvojice = 1, 'Stydlín' # toto dělá `for`
72+
index, trpaslik = dvojice
73+
print(f'Na pozici {index} je {trpaslik}!')
74+
75+
dvojice = 2, 'Dřímal' # toto dělá `for`
76+
index, trpaslik = dvojice
77+
print(f'Na pozici {index} je {trpaslik}!')
78+
79+
# A tak dále
80+
```
81+
82+
Kdybys to psal{{a}} ručně, lze to zjednodušit – přiřadit do dvou proměnných
83+
najedno, bez pomocné `dvojice`:
84+
85+
```python
86+
index, trpaslik = 0, 'Prófa' # toto by mohl dělat `for`
87+
print(f'Na pozici {index} je {trpaslik}!')
88+
89+
index, trpaslik = 1, 'Stydlín' # toto by mohl dělat `for`
90+
print(f'Na pozici {index} je {trpaslik}!')
91+
92+
index, trpaslik = 2, 'Dřímal' # toto by mohl dělat `for`
93+
print(f'Na pozici {index} je {trpaslik}!')
94+
95+
# A tak dále
96+
```
97+
98+
A `for` tohle ve skutečnosti umí: místo do proměnné `dvojice` může přiřadit
99+
rovnou do dvou proměnných `index, trpaslik`:
100+
101+
```python
102+
for index, trpaslik in enumerate(trpaslici):
103+
print(f'Na pozici {index} je {trpaslik}!')
104+
```
105+
106+
Tohle je docela častẙ způsob práce s *iterátorem n-tic* – máš-li sekvenci,
107+
jejíž prvky jsou <var>n</var>-tice, můžeš jednotlivé součásti <var>n</var>-tice
108+
rozbalit přímo v hlavičce `for` cyklu.
109+
110+
Zkus si to! Zkopíruj si tento seznam:
111+
112+
```python
113+
dny = ['Po', 'Út', 'St', 'Čt', '', 'So', 'Ne']
114+
```
115+
116+
… a zkus vypsat:
117+
118+
```plain
119+
1. Po
120+
2. Út
121+
3. St
122+
4. Čt
123+
5. Pá
124+
6. So
125+
7. Ne
126+
```
127+
128+
{% filter solution %}
129+
130+
```python
131+
dny = ['Po', 'Út', 'St', 'Čt', '', 'So', 'Ne']
132+
for index, den in enumerate(dny):
133+
cislo = index + 1
134+
print(f'{cislo}. {den}')
135+
```
136+
137+
To je trošku kostrbaté, ale dá se to zjednodušit: funkce `enumerate` zná
138+
pojmenovaný argument `start`, pomocí kterého umí sama
139+
počítat od jiného začátku než od nuly:
140+
141+
```python
142+
dny = ['Po', 'Út', 'St', 'Čt', '', 'So', 'Ne']
143+
for index, den in enumerate(dny, start=1):
144+
print(f'{index}. {den}')
145+
```
146+
147+
{% endfilter %}
148+
149+
150+
## Zip: Víc iterací najednou
151+
152+
Další iterátor <var>n</var>-tic je funkce `zip`, která umí projít dvě sekvence
153+
naráz.
154+
Řekněme že máš seznam věcí a k nim příslušných barev:
155+
156+
``` python
157+
veci = ['tráva', 'slunce', 'mrkev', 'řeka']
158+
barvy = ['zelená', 'žluté', 'oranžová', 'modrá']
159+
```
160+
161+
Kdtyž tyto dva seznamy dáš funkci `zip`, dostaneš iterátor který příslušné
162+
hodnoty spáruje.
163+
Bude tedy obsahovat:
164+
165+
* Dvojici prvních prvků obou seznamů
166+
* Dvojici druhých prvků obou seznamů
167+
* Dvojici třetích prvků obou seznamů
168+
* ...
169+
170+
``` python
171+
for vec, barva in zip(veci, barvy):
172+
print(f"{vec} je {barva}")
173+
```
174+
175+
Funguje to i pro více sekvencí.
176+
V následujícím případě je výsledný `zip` iterátor čtveřic (věc, barva,
177+
místo, číslo):
178+
179+
``` python
180+
veci = ['tráva', 'slunce', 'mrkev', 'řeka']
181+
barvy = ['zelená', 'žluté', 'oranžová', 'modrá']
182+
mista = ['na zemi', 'nahoře', 'na talíři', 'za zídkou']
183+
cisla = range(4)
184+
185+
for vec, barva, misto, cislo in zip(veci, barvy, mista, cisla):
186+
print(f"{cislo}. {barva} {vec} je {misto}")
187+
```
188+
189+
Když si ale vypíšeš samotný objekt `zip`, zjistíš že o sobě nic moc neřekne
190+
– podobně jako `enumerate`:
191+
192+
```pycon
193+
>>> zip(veci, barvy, mista, cisla)
194+
<zip object at 0x7f0db61b1f48>
195+
```
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
title: Iterátory n-tic
2+
style: md
3+
attribution: Pro PyLadies Brno napsal Petr Viktorin, 2014-2019.
4+
license: cc-by-sa-40

0 commit comments

Comments
 (0)