Cvičení č. 8 rozšířené o poznámky ze cvičení a řešení některých příkladů (ZS 2025/26)¶
V minulém díle jste viděli...¶
Příkaz def slouží k definici funkce s daným názvem a seznamem parametrů v kulatých závorkách:
def print_demo2(param1, param2):
print("Hodnota prvního parametru je", param1)
print("Hodnota druhého parametru je", param2)
x = print_demo2(1, "x")
prx = print_demo2(1, "x")
print(x)int(x)
<function print_demo2 at 0x739d20632840>
Pokud není řečeno jinak, výsledkem funkce je prázdná hodnota None.
Jiné výsledné hodnoty můžeme vrátit pomocí příkazu return, který okamžitě ukončí vykonávání funkce a vrátí výsledek:
def polynom(x):
y = 7
min = 8
print(y, min)
if x < 0:
print("Definiční obor této funkce nezahrnuje záporná čísla.")
return
return x ** 2 - 3 * x + 1
y = 6
vysledek = polynom(1)
print(vysledek)
min(8, 9)
# ukázka pytutor
7 8 -1
8
Proměnné definované uvnitř funkce jsou lokální a jejich rozsah je omezen na tělo příslušné funkce, po skončení funkce přestanou její lokální proměnné existovat. Platí to i pro proměnné se stejným názvem, jako objekty definované mimo funkci!
Další vlastnosti funkcí¶
Parametry s výchozí hodnotou¶
Jazyk Python umožňuje při definici funkce zadat výchozí (defaultní) hodnoty pro parametry, které se použijí v případě, že programátor při volání funkce nepředá jiné hodnoty. To se hodí, pokud se domníváte, že funkce bude často používána s jednou konkrétní hodnotou pro určitý parametr, ale pro speciální případy chcete umožnit jeho změnu. Základní demonstrační příklad takové funkce je:
def demo_funkce_s_mnoha_parametry(param1, param2, param3=10, param4=None):
print("param1 je", param1)
print("param2 je", param2)
print("param3 je", param3)
print("param4 je", param4)
Všimněte si, že parametry s výchozí hodnotou musí být v seznamu parametrů za všemi parametry bez výchozí hodnoty.
Nelze tedy např. definovat výchozí hodnotu pro param1, ale ne pro param2.
Funkci demo_funkce_s_mnoha_parametry teď můžeme použít se dvěma, třemi nebo čtyřmi argumenty:
demo_funkce_s_mnoha_parametry(1, 2)
param1 je 1 param2 je 2 param3 je 10 param4 je None
demo_funkce_s_mnoha_parametry(1, 2, 3)
param1 je 1 param2 je 2 param3 je 3 param4 je None
demo_funkce_s_mnoha_parametry(1, 2, 3, 4)
param1 je 1 param2 je 2 param3 je 3 param4 je 4
# ukázka: funkce round + Show Contextual Help
round(7.821)
8
round(7.821, 2)
7.82
Poziční vs. pojmenované argumenty¶
V předchozích příkladech jsme zatím vždy používali tzv. poziční způsob předávání argumentů, kde se jednotlivé hodnoty přiřazují definovaným parametrům dle jejich pořadí v kulatých závorkách. Tento způsob může být značně nepřehledný, pokud má funkce velké množství parametrů. Proto jazyk Python umožňuje také předávání tzv. pojmenovaných argumentů (anglicky keyword arguments), kde na pořadí nezáleží a hodnoty se parametrům přiřadí dle jména (jméno argumentu musí odpovídat jménu parametru).
V předchozím příkladu tedy místo demo_funkce_s_mnoha_parametry(1, 2, 3, 4) můžeme ekvivalentně použít např. libovolné z těchto volání:
demo_funkce_s_mnoha_parametry(param1=1, param2=2, param3=3, param4=4)
param1 je 1 param2 je 2 param3 je 3 param4 je 4
demo_funkce_s_mnoha_parametry(param2=2, param1=1, param4=4, param3=3)
param1 je 1 param2 je 2 param3 je 3 param4 je 4
demo_funkce_s_mnoha_parametry(param4=4, param3=3, param2=2, param1=1)
param1 je 1 param2 je 2 param3 je 3 param4 je 4
Oba způsoby předávání pozičních a pojmenovaných argumentů můžeme i kombinovat, jenom musíme dbát na to, aby všechny pojmenované argumenty byly zadány až za všemi pozičními argumenty. To umožňuje např. vynechat argumenty, které mají výchozí hodnotu, které bychom při pozičním způsobu byli nuceni zadat:
demo_funkce_s_mnoha_parametry(1, 2, param4=4)
param1 je 1 param2 je 2 param3 je 10 param4 je 4
Tip: Předávání pojmenovaných argumentů je nezávislé na parametrech s výchozí hodnotou – dá se použít pro parametry s výchozí hodnotou i bez výchozí hodnoty. Nejčastěji se ale používá právě pro parametry s výchozí hodnotou.
Tip: Jazyk Python umožňuje při definici funkce vynutit, aby určité parametry bylo možné zadat pouze pozičním způsobem a jiné jen pojmenovaným způsobem. Možná se s tímto případem brzy setkáme při používání funkcí ze standardní knihovny.
# ukázka: funkce print a pojmenované argumenty + Show Contextual Help
print("ahoj")
print(2, 3, 4)
ahoj 2 3 4
print(2, 3, 4, end = ";", sep = ", ")
print("ahoj")
2, 3, 4;ahoj
Funkce jako proměnné¶
Definice funkce pomocí příkazu def je speciální forma přiřazení, při kterém se provede několik věcí:
- Vytvoří se objekt, který reprezentuje danou funkci a obsahuje kód definovaný v těle funkce.
- Vytvoří se proměnná s názvem dané funkce a do ní se uloží odkaz na vytvořený objekt.
V principu tedy s názvy funkcí pracujeme stejně jako s názvy proměnných. To nám umožňuje např. "přejmenovávat" funkce po jejich definici nebo používat názvy funkcí pro pojmenování hodnot. Pokud se jedná o lokální proměnné a tyto funkce, jejichž názvy jsme použili, na lokální úrovni nebudeme potřebovat, tak tato shoda názvů ničemu nevadí:
def demo1():
f = max
g = min
v = f(f(2, g(1, 3)), 4)
print("v =", v)
def demo2():
min = 1
max = 5
for i in range(min, max + 1):
print(i)
demo1()
demo2()
v = 4 1 2 3 4 5
Definice funkce je navíc obyčejný složený příkaz, který můžeme použít všude tam, kde se smí použít příkaz. Funkce tedy můžeme definovat i uvnitř jiné funkce, můžeme funkce předávat jako argument nějaké funkci a funkce může představovat návratovou hodnotu jiné funkce. Tyto vlastnosti umožňují použít Python pro práci s funkcemi vyšších řádů a pro funkcionální programování. To je ale nad rámec předmětu ZPRO a podrobnostmi vás teď nebudeme zatěžovat.
Docstring a nápověda¶
Poslední věc, kterou si dnes ukážeme, nesouvisí s vykonáváním kódu, ale velmi se hodí pro podrobný popis toho, jak určitá funkce funguje a jak by se měla používat. Při definici funkce můžeme přidat tzv. docstring, neboli dokumentační řetězec:
def demo():
""" Toto je docstring. Slouží jako místo k umístění dokumentace pro danou funkci.
Docstring typicky obsahuje:
- popis všech parametrů a jejich vliv na chování funkce
- popis návratové hodnoty
- popis případných chyb, které mohou nastat při vykonávání funkce
"""
return
Docstring je formálně libovolný textový řetězec, který je vložen v těle funkce jako první příkaz (bez přiřazení proměnné!) se správným odsazením.
V předchozím příkladu jsme místo párových dvojitých uvozovek ("...") použili párovou trojici dvojitých uvozovek ("""..."""), která umožňuje zadat v kódu víceřádkový string.
Jak jsme viděli v předchozí sekci, jazyk Python umožňuje dynamickým způsobem pracovat s objekty a jejich názvy.
Existuje jednoduchý způsob, jak se jednoduchým způsobem dostat k docstringu nějakého objektu, se kterým si při programování nevíme rady.
Např. docstring výše definované funkce demo můžeme zobrazit pomocí funkce help nebo přímo v prostředí Jupyter (v menu po kliknutí pravým tlačítkem na kód buňky vybereme Show Contextual Help):
help(demo)
demo
Help on function demo in module __main__:
demo()
Toto je docstring. Slouží jako místo k umístění dokumentace pro danou funkci.
Docstring typicky obsahuje:
- popis všech parametrů a jejich vliv na chování funkce
- popis návratové hodnoty
- popis případných chyb, které mohou nastat při vykonávání funkce
Objekty poskytované prostředím jazyka Python, případně jinými balíčky, mají také svou dokumentaci vytvořenou pomocí docstringů.
Např. dokumentace pro funkci print vypadá takto:
help(print)
Help on built-in function print in module builtins:
print(*args, sep=' ', end='\n', file=None, flush=False)
Prints the values to a stream, or to sys.stdout by default.
sep
string inserted between values, default a space.
end
string appended after the last value, default a newline.
file
a file-like object (stream); defaults to the current sys.stdout.
flush
whether to forcibly flush the stream.
Všimněte si, jakým způsobem jsou popsané jednotlivé parametry a chování funkce. Pokud budete psát vlastní dokumentaci, je dobré se inspirovat stylem použitým ve standardní knihovně. Pro úplnost dodejme, že dokumentace standardní knihovny jazyka Python je k dispozici online na stránce https://docs.python.org/. Až budeme vědět více o jejích modulech, tak si ukážeme, kde potřebné informace najít.
Příklady¶
Pro každou funkci v následujících příkladech napište vhodný docstring.
Ano/ne¶
- Napište funkci
ano_ne(otázka), která uživateli položí zadanou otázku a zeptá se ho na odpověď "ano" nebo "ne". Pokud je odpověď "ano", funkce vrátíTrue, pokud je odpověď "ne", funkce vrátíFalse. Pokud je odpověď něco jiného, program vypíše chybu a zeptá se znovu (uvnitř cyklu).
# jednodušší příklad:
def ano_ne(otazka):
return True
vysledek1 = ano_ne("Mas rad programovani?")
vysledek2 = ano_ne("Mas rad matematiku?")
print(vysledek1, vysledek2)
True True
# jednodušší příklad:
def ano_ne(otazka):
odpoved = input(otazka)
if odpoved == "ne":
return False
elif odpoved == "ano":
return True
else:
print("Chyba: Zadej pouze 'ano' nebo 'ne'.")
vysledek1 = ano_ne("Mas rad programovani?")
vysledek2 = ano_ne("Mas rad matematiku?")
vysledek3 = ano_ne("Mas rad fyziku?")
print(vysledek1, vysledek2, vysledek3)
Chyba: Zadej pouze 'ano' nebo 'ne'. True False None
def ano_ne(otazka):
"""
Funkce položí uživateli otázku `otazka`, a zeptá se na odpověď.
Pokud je odpověď "ano", funkce vrátí True, pokud je odpověď "ne",
funkce vrátí False. Pokud je odpověď něco jiného, program vypíše chybu
a zeptá se znovu
otazka
Textový řetězec s otázkou, např. "Je ti více než 18 let?"
ruturn
True (pro odpověď "ano") / False (pro odpověď "ne")
"""
while True:
odpoved = input(otazka)
if odpoved == "ne":
return False
elif odpoved == "ano":
return True
else:
print("Chyba: Zadej pouze 'ano' nebo 'ne'.")
vysledek1 = ano_ne("Mas rad programovani?")
vysledek2 = ano_ne("Mas rad matematiku?")
print(vysledek1, vysledek2)
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'.
True False
- Upravte předchozí funkci do tvaru
ano_ne(otázka, počet_pokusů), kde číslopočet_pokusůomezí maximální počet opakování cyklu.
def ano_ne(otazka, pocet_pokusu):
return True
vysledek1 = ano_ne("Mas rad programovani?", 10)
vysledek2 = ano_ne("Mas rad matematiku?", 3)
print(vysledek1, vysledek2)
True True
def ano_ne(otazka, pocet_pokusu):
for pokus in range(pocet_pokusu):
odpoved = input(otazka)
if odpoved == "ano" :
return True
elif odpoved == "ne":
return False
elif pocet_pokusu > 1:
print("Chyba: Zadej pouze 'ano' nebo 'ne'.")
print("Nedal jsi jednoznačnou odpověď.")
vysledek1 = ano_ne("Mas rad programovani?", 1)
vysledek2 = ano_ne("Mas rad matematiku?", 3)
print(vysledek1, vysledek2)
Nedal jsi jednoznačnou odpověď.
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'. Nedal jsi jednoznačnou odpověď. None None
def ano_ne(otazka, pocet_pokusu):
while pocet_pokusu > 0:
odpoved = input(otazka)
if odpoved == "ano" :
return True
elif odpoved == "ne":
return False
elif pocet_pokusu > 1:
print("Chyba: Zadej pouze 'ano' nebo 'ne'.")
pocet_pokusu = pocet_pokusu-1
print("Nedal jsi jednoznačnou odpověď.")
vysledek1 = ano_ne("Mas rad programovani?", 1)
vysledek2 = ano_ne("Mas rad matematiku?", 3)
print(vysledek1, vysledek2)
Nedal jsi jednoznačnou odpověď.
Chyba: Zadej pouze 'ano' nebo 'ne'.
None True
def ano_ne(otazka, pocet_pokusu=3):
while pocet_pokusu > 0:
odpoved = input(otazka)
if odpoved == "ano" :
return True
elif odpoved == "ne":
return False
elif pocet_pokusu > 1:
print("Chyba: Zadej pouze 'ano' nebo 'ne'.")
pocet_pokusu = pocet_pokusu-1
print("Nedal jsi jednoznačnou odpověď.")
vysledek1 = ano_ne("Mas rad programovani?", 1)
vysledek2 = ano_ne("Mas rad matematiku?")
print(vysledek1, vysledek2)
Nedal jsi jednoznačnou odpověď.
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'.
Nedal jsi jednoznačnou odpověď. None None
- Upravte předchozí funkci tak, aby parametr
počet_pokusůbyl volitelný a pokud při použití funkce není zadaný, tak opakování může probíhat nekonečně dlouho.
def ano_ne(otazka, pocet_pokusu = -1): # -1, None, math.inf
while pocet_pokusu != 0:
odpoved = input(otazka)
if odpoved == "ano" :
return True
elif odpoved == "ne":
return False
elif pocet_pokusu > 1:
print("Chyba: Zadej pouze 'ano' nebo 'ne'.")
pocet_pokusu = pocet_pokusu-1
print("Nedal jsi jednoznačnou odpověď.")
vysledek1 = ano_ne("Mas rad programovani?", 2)
vysledek2 = ano_ne("Mas rad matematiku?")
print(vysledek1, vysledek2)
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'. Nedal jsi jednoznačnou odpověď.
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'.
None True
from math import inf
def ano_ne(otazka, pocet_pokusu = inf): # -1, None, math.inf
while pocet_pokusu > 0:
odpoved = input(otazka)
if odpoved == "ano" :
return True
elif odpoved == "ne":
return False
elif pocet_pokusu > 1:
print("Chyba: Zadej pouze 'ano' nebo 'ne'.")
pocet_pokusu = pocet_pokusu-1
print("Nedal jsi jednoznačnou odpověď.")
vysledek1 = ano_ne("Mas rad programovani?", 2)
vysledek2 = ano_ne("Mas rad matematiku?")
print(vysledek1, vysledek2)
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'.
Chyba: Zadej pouze 'ano' nebo 'ne'.
True True
Dělitelé¶
- Napište funkci
prvociselny_rozklad(n), která vypíše prvočíselný rozklad přirozeného číslan.
# ukázat myšlenku
def prvociselny_rozklad(n):
d = 2
while n > 1:
while n % d == 0:
print(d, end = " ")
n = n // d
d = d + 1
prvociselny_rozklad(17)
print("")
prvociselny_rozklad(30)
print("")
prvociselny_rozklad(36*49)
print("")
prvociselny_rozklad(8*9*17)
17 2 3 5 2 2 3 3 7 7 2 2 2 3 3 17
def prvociselny_rozklad(n):
d = 2
while n > 1:
if n % d == 0:
print(d, end = " ")
n = n // d
else:
d = d + 1
prvociselny_rozklad(17)
print("")
prvociselny_rozklad(30)
print("")
prvociselny_rozklad(36*49)
print("")
prvociselny_rozklad(8*9*17)
17 2 3 5 2 2 3 3 7 7 2 2 2 3 3 17
- Napište funkci
je_prvocislo(n), která vrátíTrue, pokud přirozené číslonje prvočíslo. Jinak vrátíFalse.
# bylo na hodině, ale sem nedávám, protože je za domácí úkol :)
True True False False
- Napište funkci
vypis_prvocisla(n), která vypíše všechna prvočísla menší než přirozené číslon.
2 3 5 7 11 13 17 19 23
- Napište funkci
kte_prvocislo(k), která spočítá a vrátík-té prvočíslo.
1 : 2 2 : 3 3 : 5 4 : 7 5 : 11 6 : 13 7 : 17 8 : 19 9 : 23
- Napište funkci
nsn(a, b), která spočítá a vrátí nejmenší společný násobek přirozených číselaab.
Odhady, aproximace¶
- Napište funkci
eulerovo_cislo(n), která spočítá a vrátí odhad Eulerova čísla $e$ pomocí $n$-tého členu posloupnosti $(1 + \frac{1}{n})^n$. Pomocí srovnání s hodnotoumath.exp(1)zhodnoťte, na kolik desetinných míst je výsledek přesný.
2.7182682371922975 2.718281828459045 1.359126674760347e-05
Číslo $\sqrt{2}$ lze zapsat pomocí nekonečného řetězového zlomku:
$$ \sqrt{2} = 1 + \cfrac{1}{2 + \cfrac{1}{2 + \cfrac{1}{2 + \ddots}}} $$
Napište funkci
odmocnina_2(n), která spočítá odhad čísla $\sqrt{2}$ pomocí řetězového zlomku s $n$ jmenovateli. Zhodnoťte, na kolik desetinných míst je výsledek přesný.
1.5 1.4 1.4166666666666667 1.4142135516460548 1.4142135623730951 1.0727040367086715e-08
Napište funkci
zlatý_řez(n), která spočítá odhad zlatého řezu $\varphi$ pomocí řetězového zlomku s $n$ jmenovateli. Také zhodnoťte, na kolik desetinných míst je výsledek přesný.Zlatý řez:
$$ \varphi = \cfrac{1 + \sqrt{5}}{2} = 1 + \cfrac{1}{1 + \cfrac{1}{1 + \cfrac{1}{1 + \ddots}}} $$
- Napište funkci
ludolfovo_číslo(n), která spočítá a vrátí odhad Ludolfova čísla) $\pi$ pomocí součtu prvních $n$ členů Leibnizovy řady. Zhodnoťte, na kolik desetinných míst je výsledek přesný.
$$ \pi = 4\sum^\infty_{k=0} \frac{(-1)^k}{2k+1} = \frac{4}{1}-\frac{4}{3}+\frac{4}{5}-\frac{4}{7}+\frac{4}{9}-\cdots $$