Skip to content

Commit 193c5f2

Browse files
committed
def: Switch the lesson to zamen code (+ rewordings & clarfications)
1 parent 6d334d2 commit 193c5f2

3 files changed

Lines changed: 148 additions & 47 deletions

File tree

lessons/beginners/def/index.md

Lines changed: 115 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Funkce
1+
# Definice funkcí
22
[Dříve]({{ lesson_url('beginners/functions') }}) jsme
33
volal{{gnd('i', 'y', both='i')}} funkce, které napsal někdo jiný:
44

@@ -8,20 +8,71 @@ print('Ahoj světe!')
88

99
Dnes si ukážeme, jak psát funkce vlastní.
1010

11-
Pokud umíš `if` a `for` – s jednořádkovou hlavičkou a odsazeným tělem příkazu –
12-
neměl by ti zápis funkce připadat nijak zvláštní:
1311

14-
```python
15-
def obvod_obdelnika(sirka, vyska):
16-
"Vrátí obvod obdélníka daných rozměrů"
17-
obvod = 2 * (sirka + vyska)
18-
return obvod
12+
## K čemu jsou funkce?
13+
14+
Často se stává, že kód, který dělá nějakou jednoduchou věc, není úplně
15+
jednoduchý.
16+
Jako příklad uvedu nám už známý kód, který v určitém řetězci zamění znak
17+
na dané pozici:
1918

20-
print(obvod_obdelnika(4, 2))
19+
```
20+
zacatek = slovo[:pozice]
21+
konec = slovo[pozice + 1:]
22+
nove_slovo = zacatek + novy_znak + konec
2123
```
2224

23-
Jak to funguje?
25+
Z takového kódu není na první pohled jasné, co přesně dělá.
26+
Zvlášť když kód použiješ ve složitějším programu.
27+
28+
Dá se to vyřešit komentářem: ten, kdo bude program číst, si může přečíst
29+
co to má dělat. Samotný složitější kód pak může ignorovat.
30+
31+
```
32+
# Ve slově `slovo` zaměnit znak na pozici `pozice` za `novy_znak`;
33+
# výsledek bude v proměnné `nove_slovo`.
34+
zacatek = slovo[:pozice]
35+
konec = slovo[pozice + 1:]
36+
nove_slovo = zacatek + novy_znak + konec
37+
```
38+
39+
Ještě lepší ale bude si vytvořit *funkci*, která tenhle složitější postup
40+
provede.
41+
Jakmile takovou funkci vytvoříš, ve složitějším programu pak můžeš místo kódu
42+
výše psát jen:
43+
44+
```
45+
nove_slovo = zamen(slovo, pozice, novy_znak)
46+
```
2447

48+
Podobně fungují funkce, které už znáš: můžeš zavolat `print(123)`, aniž bys
49+
potřeboval{{a}} znát jakékoli detaily postupu, kterým se číslo převede na
50+
jednotlivé číslice a ty se pak vykreslí na obrazovce.
51+
Nebo řekneš želvě `forward(100)` a nezatěžuješ se tím, jak si želva „pamatuje“
52+
svůj aktuální úhel natočení nebo jak se vlastně kreslí čára.
53+
54+
Funkce umožňuje *pojmenovat* nějaký kousek programu, který se pak dá
55+
použít pomocí jména bez detailních znalosti toho, jak to vevnitř funguje.
56+
57+
58+
## Definice funkce
59+
60+
Protože už znáš `if` a `for`, které mají jednořádkovou hlavičku a odsazené tělo
61+
příkazu, neměl by ti zápis funkce připadat příliš zvláštní:
62+
63+
```python
64+
def zamen(slovo, pozice, novy_znak):
65+
"V daném slově zamění znak na dané pozici za daný nový znak"
66+
zacatek = slovo[:pozice]
67+
konec = slovo[pozice + 1:]
68+
nove_slovo = zacatek + novy_znak + konec
69+
return nove_slovo
70+
71+
print(zamen('kočka', 1, 'a'))
72+
print(zamen('kačka', 2, 'p'))
73+
```
74+
75+
Jak to funguje?
2576

2677
Funkce se *definuje* příkazem `def`, za nějž napíšeš jméno funkce,
2778
pak do závorky seznam *parametrů*, které funkce bere, a pak dvojtečku.
@@ -31,6 +82,28 @@ Tělo může začít *dokumentačním řetězcem*, který popisuje, co funkce d
3182

3283
Příkazem `return` pak můžeš z funkce *vrátit* nějakou hodnotu.
3384

85+
Při volání funkce se hodnoty, se kterými funkci
86+
zavoláš, přiřadí jednotlivým parametrům.
87+
Takže když zavoláš třeba `zamen('kočka', 1, 'a')`,
88+
můžeš si představit, že se provede toto:
89+
90+
```python
91+
# Nastavení proměnných podle zadaných parametrů
92+
slovo = 'kočka'
93+
pozice = 1
94+
novy_znak = 'a'
95+
96+
# Samotné tělo funkce
97+
zacatek = slovo[:pozice]
98+
konec = slovo[pozice + 1:]
99+
nove_slovo = zacatek + novy_znak + konec
100+
return nove_slovo
101+
```
102+
103+
Už víš, že volání `zamen('kočka', 1, 'a')` je výraz.
104+
Aby ho Python vyhodnotil, udělá celý postup výše a jako hodnotu výrazu dosadí
105+
návratovou hodnotu – tedy to, co následuje po `return`.
106+
34107
Tělo funkce může mít více příkazů – včetně podmínek, cyklů a podobně.
35108
Následující procedura třeba vypíše skóre daného hráče a k tomu hlášku:
36109

@@ -54,27 +127,28 @@ napis_hlasku('Tvoje', 256)
54127
napis_hlasku('Protivníkovo', 5)
55128
```
56129

57-
Při volání funkce se hodnoty, se kterými funkci
58-
zavoláš, přiřadí jednotlivým parametrům.
59-
Takže když zavoláš třeba `napis_hlasku('Tvoje', 256)`,
60-
můžeš si představit, že funkce dělá následující:
130+
## Cvičení
131+
132+
Zkus napsat funkci, která vrátí obsah obdélníka daných rozměrů.
133+
Příslušný vzoreček je <var>S</var> = <var>a</var>×<var>b</var>,
134+
kde <var>a</var> a <var>b</var> jsou délky stran.
61135

136+
Funkci zavolej a výsledek vypiš.
137+
138+
{% filter solution %}
62139
```python
63-
# Nastavení proměnných podle parametrů
64-
nazev = 'Tvoje'
65-
skore = 256
140+
def obsah_obdelnika(a, b):
141+
return a * b
66142

67-
# Samotné tělo funkce
68-
print(nazev, 'skóre je', skore)
69-
if skore > 1000:
70-
print('Světový rekord!')
71-
elif skore > 100:
72-
... # atd.
143+
print('Obsah obdélníka se stranami 3 cm a 5 cm je', obsah_obdelnika(3, 5), 'cm2')
73144
```
74-
## Vracení
145+
{% endfilter %}
146+
75147

76-
Speciální příkaz `return`, který jde použít jenom ve funkcích,
77-
*ukončí* funkci a vrátí danou hodnotu ven z funkce.
148+
## Vracení ukončuje funkci
149+
150+
Speciální příkaz `return`, který jde použít jenom ve funkcích, vrátí danou
151+
návratovou hodnotu ven z funkce a zároveň *ukončí* provádění funkce.
78152

79153
Chová se tedy trochu jako `break`, jen místo cyklu opouští celou funkci.
80154

@@ -116,29 +190,23 @@ else:
116190
> Stejně jako `if` nebo `break` je `return` *příkaz*, ne funkce.
117191
> Kolem „své“ hodnoty nepotřebuje závorky.
118192
119-
Zkus napsat funkci, která vrátí obsah elipsy
120-
daných rozměrů.
121-
Příslušný vzoreček je <var>A</var> = π<var>a</var><var>b</var>,
122-
kde <var>a</var> a <var>b</var> jsou délky os.
123193

124-
Funkci zavolej a výsledek vypiš.
194+
### Vrátit nebo vypsat?
195+
196+
Podívejme se teď na následující program, který vypíše obsah elipsy:
125197

126-
{% filter solution %}
127198
```python
128199
from math import pi
129200

130201
def obsah_elipsy(a, b):
131202
return pi * a * b
132203

133-
print('Obsah elipsy s osami 3 cm a 5 cm je', obsah_elipsy(3, 5), 'cm2')
204+
print('Obsah elipsy s poloosami 3 a 5 je', obsah_elipsy(3, 5), 'cm2')
134205
```
135-
{% endfilter %}
136-
137-
138-
### Vrátit nebo vypsat?
139206

140-
Předchozí program se dá napsat i jako procedura, tedy funkce která nic nevrací.
141-
Výsledek může třeba vypsat na obrazovku:
207+
Takový program se teoreticky dá napsat i s procedurou, tedy funkcí která nic
208+
nevrací.
209+
Procedura může výsledek třeba vypsat na obrazovku:
142210

143211
```python
144212
from math import pi
@@ -152,7 +220,7 @@ obsah_elipsy(3, 5)
152220
Program takhle funguje, ale přichází o jednu z hlavních výhod funkcí:
153221
možnost vrácenou hodnotu použít i jinak jež jen v `print`.
154222

155-
Funkci, která vrací výsledek, můžeš použít v dalších výpočtech:
223+
Funkci, která *vrací* výsledek, můžeš použít v dalších výpočtech:
156224

157225
```python
158226
def objem_eliptickeho_valce(a, b, vyska):
@@ -162,8 +230,10 @@ print(objem_eliptickeho_valce(3, 5, 3))
162230
```
163231

164232
... ale s procedurou, která výsledek přímo vypíše, by to nešlo.
233+
Proto je dobré psát funkce, které spočítané hodnoty vrací,
234+
a zpracování výsledku (např. vypsání) nechat na kód mimo funkci.
165235

166-
Další důvod, proč hodnoty spíš vracet než vypisovat, je ten, že jedna funkce se
236+
Další důvod proč hodnoty spíš vracet než vypisovat je ten, že jedna funkce se
167237
dá použít v různých situacích.
168238
Proceduru s `print` by nešlo rozumně použít tehdy, když nás příkazová
169239
řádka vůbec nezajímá – třeba v grafické hře, webové aplikaci, nebo pro ovládání
@@ -173,8 +243,8 @@ Podobně je to se vstupem: když použiju v rámci své funkce `input`, bude se
173243
moje funkce dát použít jen v situacích, kdy je u počítače klávesnice a za ní
174244
člověk.
175245
Proto je lepší funkcím potřebné informace předávat jako argumenty
176-
a `input` (nebo textové políčko či měření z čidla robota) nemít ve funkci,
177-
ale vně:
246+
a volání `input` (nebo čtení textového políčka či měření čidlem robota)
247+
nemít ve funkci, ale vně, v kódu který funkci volá:
178248

179249
```python
180250
from math import pi
@@ -191,7 +261,8 @@ print('Obsah je', obsah_elipsy(x, y))
191261
```
192262

193263
Samozřejmě existují výjimky: procedura která přímo vytváří textový výpis
194-
může používat `print`; funkce která načítá textové informace zase `input`.
264+
(např. tabulku) může používat `print`; funkce která načítá textové informace
265+
(jako `ano_nebo_ne` výše) zase `input`.
195266
Když ale funkce něco *počítá*, nebo když si nejsi jist{{gnd('ý', 'á')}},
196267
je dobré ve funkci `print` ani `input` nemít.
197268

lessons/beginners/def/info.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
title: Vlastní funkce
1+
title: Definice funkcí
22
style: md
33
attribution: Pro PyLadies Brno napsal Petr Viktorin, 2014-2017.
44
license: cc-by-sa-40

lessons/beginners/local-variables/index.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,41 @@ pro ni.
4343
Když funkce `nastav_x` skončí, proměnná `x` přestane existovat.
4444

4545

46+
## Skrývání detailů
47+
48+
Podobně skončí s chybou i složitější program:
49+
50+
```python
51+
def zamen(slovo, pozice, novy_znak):
52+
"V daném slově zamění znak na dané pozici za daný nový znak"
53+
zacatek = slovo[:pozice]
54+
konec = slovo[pozice + 1:]
55+
nove_slovo = zacatek + novy_znak + konec
56+
return nove_slovo
57+
58+
print(zamen('kočka', 1, 'a'))
59+
print(zamen('kačka', 2, 'p'))
60+
61+
print(zacatek) # NameError
62+
```
63+
64+
Funkce `zamen` jsi napsal{{a}} proto, abys nemusel{{a}} pořád opakovat detaily
65+
záměny písmenka.
66+
Jakmile je jednu nadefinovaná, stačí ji zavolat. Důležité jsou jen jméno
67+
funkce, argumenty a návratová hodnota; na detaily kódu uvnitř můžeš zapomenout.
68+
A to i díky lokálním proměnným, které detaily ve vnitřku funkce trochu líp
69+
izolují od zbytku programu.
70+
71+
Ještě lépe je to vidět u funkcí, které jsi nenapsal{{a}} {{gnd('sám', 'sama')}}.
72+
Jak divné by bylo, kdyby po každém zavolání `print` byla najednou nastavená
73+
proměnná `i`, kterou `print` náhodou používá při procházení svých argumentů!
74+
75+
4676
## Přiřazení
4777

4878
To, co dělá lokální proměnnou, je *přiřazení*.
4979
Porovnej `nastav_x` s příkladem na `obsah_kruhu` výše: rozdíl mezi `pi` a `x`
50-
je v tom, že do `x` funkce přiřazuje.
80+
je v tom, že do `x` se v rámci funkce funkce přiřazuje.
5181

5282
Co je to přiřazení? Všechno, co *nastavuje* nějakou proměnnou. Například:
5383
* Klasika je přiřazovat pomocí `=`, např. `a = 3`.
@@ -93,7 +123,7 @@ Jmenují se stejně, ale jsou to dvě různé proměnné.
93123
## Lokální nebo globální?
94124

95125
Pojďme si to ukázat.
96-
Než spustíš tenhle program, zkus předpovědět, co bude dělat.
126+
Než spustíš tenhle program, zkus předpovědět co bude dělat.
97127
Pak ho pusť, a pokud dělal něco jiného, zkus vysvětlit proč.
98128
Pozor na chytáky!
99129

0 commit comments

Comments
 (0)