Search
Funkce (někdy též metoda) je uzavřený, znovupoužitelný blok kódu (příkazů), který umí splnit nějaký jasně definovaný dílčí úkol (například načtení a ošetření vstupu, vykreslení řádky, výpočet obsahu trojuhelníku, atd). Definovanou funkci pak můžeme kdekoliv v našem programu zavolat jedním příkazem, což nám ušetří psaní, usnadní hledání chyb a celkově zpřehlední kód. Definice funkcí se vyplatí zejména v případech, kdy dílčí úkol potřebujeme vykonávat na více různých místech programu.
Každá funkce má název, kterým funkci budeme později volat. Funkce může, nebo nemusí mít návratovou hodnotu (funkce na výpočet obsahu trojúhelníku ji mít bude, funkce sloužící pro opakovaný tisk textového řetězce ne). Vstupní argumenty (též proměnné, či parametry) jsou taková data (proměnné), se kterými funkce pracuje. Vstupních argumentů může mít funkce libovolné množství a mohou být libovolných datových typů.
Funkci v Pythonu definujeme pomocí klíčovího slova def, jménem funkce, kulatými závorkami obsahujícími argumenty a znakem :, například def jmeno_funkce():. Následují příkazy v těle funkce, které je v Pythonu podobně jako v případě cyklů nebo podmínek odsadit tabulátorem. Má-li funkce návratovou hodnotu, je funkce zakončena klíčovým slovem return následované výrazem nebo proměnnou, kterou má funkce vracet, například return 5. Níže si ukážeme příkady některých funkcí.
def
:
def jmeno_funkce():
return
return 5
Příklad funkce bez vstupních argumentů:
def pozdrav(): print("Hello Bootcamp!")
Příklad funkce bez vstupních argumentů, ale s návratovou hodnotou:
import math def pi(): return math.pi
Příklad funkce se vstupními parametry a návratovou hodnotou:
def pythagoras(a, b): c = math.sqrt(a*a + b*b) return c
Je možné vracet návratovou hodnotu na vícero místech:
def soucet_listu(l): if len(l) == 0: return 0 else: soucet = 0 for i in range(len(l)): soucet += l[i] return soucet
Následující kód:
import math def say_hello(): print("Dobry den, vitejte u vykladu funkci.") pythagoras() # skonci chybou def pythagoras(a, b): c = math.sqrt(a*a + b*b) return c say_hello() strana_a = 3 strana_b = 4 strana_c = pythagoras(strana_a, strana_b) print("Odvesna trojuhelniku se stranami " + str(strana_a) + " a " + str(strana_b) + " je " + str(strana_c))
vypíše:
Dobry den, vitejte u vykladu funkci. Odvesna trojuhelniku se stranami 3 a 4 je 5
Dekompozice nebo-li rozložení problému na podproblémy je základní princip, jak přistupovat ke složitějším úlohám v programování a dovednost, která usnadňuje řešení náročných úloh. Existují dva základní přístupy: od problému k jednotliým pod problémům (někdy označovaný jako shora-dolů) a od dílčích kroků k obecnému cíli (někdy označovaný jako zdola-nahoru). Oba přístupy se odlišují jak svou náročností, tak typem zadání, ke kterému jsou vhodné, proto si ukážeme, jak pomocí prvního analytického přístupu rozdělit úlohu na následující úlohu domečku na jednotlivé podproblémy.
Uvažujme následující zadání.
Úkol X. Načtěte na vstupu liché číslo N větší nebo rovno 5 a vypište na konzole domeček o odpovídající velikosti. Pokud číslo není liché nebo je menší než 5, vypište vhodnou chybovou hlášku. Vzorový výstup pro N=5:
N=5
X X X XXXXX X X X X x X XXXXX
Zamyslíme-li se nad samotným tvarem, vidíme na první pohled, že domeček se skládá ze zdí a ze střechy, na druhý, že zdi mají tvar čtverce. Pokud se podíváme na zadání, vidíme, že musíme načítat od uživatele nějaký vstup, kontrolovat, jestli je vstup platný a pak vykreslovat domeček. Spojením těchto dvou kategorií, dostáváme první nástřel dekompozice:
# 1. nacist vstup # 2. zkontrolovat vstup # '-> je-li chybne, vypsat hlasku # '-> je-li validni, pokracovat # 3. vykreslit domecek # 3.1 vykreslit strechu # 3.2 vykreslit steny
Nyní můžeme použít tyto kroky a rozhodnout, jaké kroky je vhodné zabalit do funkcí. Podobně jako v případě identifikace jednotlivých podúkolů, i zde může být více podobně vhodných způsobů, my ale zvolíme funkci pro každý číslovaný bod, čímž dostatneme následující funkce:
# nacte input od uzivatele a vrati ho def load_input(): pass # zkontroluje velikost (argument 'size'), # '-> je-li v poradku vrati True # '-> je-li špatně, informuje o tom uživatele vypisem a vrati False def check_size(size): pass # vykresli steny domecku o velikosti 'size' def print_walls(size): pass # vykresli strechu domecku o velikosti "size" def print_roof(size): pass # vykresli cely domecek def print_house(size): print_roof(size) print_walls(size)
pass
Hlavní část programu volající funkce pak bude vypadat takto:
# 1. nacist vstup size = load_input() # 2. zkontrolovat vstup # '-> je-li chybne, vypsat hlasku # '-> je-li validni, pokracovat is_size_valid = check_size(size) # 3. vykreslit domecek if is_size_valid: print_house(size)
Zaměřme se nyní na funkce tisknoucí domeček (print_roof(size) a print_walls(size)), ktereré mají pro vstup size=5 vytisknout:
print_roof(size)
print_walls(size)
size=5
X X X
XXXXX X X X X x X XXXXX
Budeme-li domeček rovnou tisknout, pak musíme tisknout jeden znak za druhý, řádek po řádku. Zaměříme-li se na jednotlivé řádky, uvidíme, že se skládají z opakujících se znaků (velmi dobře viditelné v případě stěn) a že by se nám mohla hodit funkce, která vytiskne znak c několikrát za sebe, přidáme ji tedy do funkcí k implementaci:
c
def repeat_char_n_times(c, n): pass
S těmito funkcemi máme jasně dané konkrétní kroky, které musíme učinit, abychom byli schopni vykreslit domeček; každý krok je jasně vymezený a reltivně přímočarý, takže teď je na vás takto předkrájeného slona sníst a dokončit jednotlivé funkce.
Řešení
Definujte dvě funkce sloužící k výpočtu a posouzení hodnoty BMI (body mass index).
Zkombinujte obě funkce tak, že uživatel je nejprve dotázán na hmotnost a výšku a následně je vypsána hodnota BMI a kategorie, do níž BMI spadá.
Vytvořte funkci swap(), které je předán jako parametr seznam čísel a dva číselné indexy. Funkce v seznamu prohodí čísla na zadaných pozicích.
swap()
Například:
numbers = [5, 7, 6, 8] swap(numbers, 1, 2) print(numbers)
[5, 6, 7, 8]
Vytvořte funkci smallest_number(), které je předán jako parametr seznam čísel. Funkce v seznamu nalezne nejmenší číslo a vrátí jeho index (pozici). Předpokládejme, že nejmenší říslo se v seznamu nachází pouze jednou.
smallest_number()
numbers = [7, 6, 5, 8] i = smallest_number(numbers) print(i)
2
Použijte funkci smallest_number() z předchozího úkolu a vytvořte funkci sort_list(), které je předán jako parametr seznam čísel. Funkce čísla v seznamu seřadí od nejmenšího po největší.
sort_list()
pop(i)
Vytvořte knihovnu funkcí (modul) jednoduché pokladny.
V souboru pokladna.py definujte následující funkce:
pokladna.py
read_input()
get_sum(array)
get_avg(array)
print_receipt(array)
serve_custormer()
Abychom si vyzkoušeli vyzkoušeli pracovat i s funkcemi vlastního modulu, vytvořte ve stejné složce, kde je uložený soubor pokladna.py, jiný soubor (například main.py).
main.py
Import modulu můžeme provést několika způsoby:
První (a preferovaná možnost) je importovat modul jako celek se všemi funkcemi:
import pokladna bill = pokladna.read_input()
Jak vidíte, pokud chcete zavolat nějakou funkci z modulu, použitjeme příkazem ve tvaru nazev_modulu.nazev_funkce(parametry).
nazev_modulu.nazev_funkce(parametry)
Druhá možnost je importovat z modulu přímo některé konkrétní funkci, ne celý modul. Kupříkladu pouze funkci read_input():
from pokladna import read_input bill = read_input()
V tomto případě při volání funkce neuvádíme název modulu, v němž je funkce definována, což může v případě, že importujeme více modulů s funkcemi stejného jména, vést k nepříjemným situacím.
*
from pokladna import * bill = read_input
Řešení (včetně rozšíření)
Rozšiřte knihovnu pokladna.py o následující funkce:
get_max(array)
get_min(array)
array_contains(array, number)
Nezapomeňte příslušně opravit i funkci print_receipt(array), aby brala v potaz nové funkce.
Napište program, který se uživatele dotáže na délku vektorů, následně náhohodně vygeneruje dva vektory danné délky a spočítá jejich skalární součin, oba vygenerované vektory i výsledek následně vypíše.
$\vec{a} \cdot \vec{b} = \left[ a_1, a_2, \dots, a_N \right] \cdot \left[ b_1, b_2, \dots, b_N \right] = a_1 \cdot b_1 + a_2 \cdot b_2 + \dots + \ a_N \cdot b_N $
tedy například:
$\left[1, 2, 4 \right] \cdot \left[ 3, 2, -1 \right] = 1 \cdot 3 + 2 \cdot 2 + 4 \cdot (-1) = 3 + 4 - 4 = 3$
printf("Cislo x na dve desetinna mista: {:.2f}".format(x))
Pokud navíc chcete, fixní celkovou délku čísla x, například na 5 znaků (2 za desetinnou čárkou, 1 jako desetinná tečka, a zbývajících 5-(2+1)=2 před desetinnou čárkou), můžete použít:
x
5
1
5-(2+1)=2
printf("{:5.2f}".format(x))
Další informace o formátování výpisu v dokumentaci vstupu/výstupu (en) anebo dokumentaci k formátování (en) .
Například pro N=2 může program vypsat:
N=2
[ -3.51 9.04 ] . [ 8.90 2.29 ] = -10.53
Upravte program tak, aby namísto generování dvou náhodných vektorů umožnil uživateli postupně načíst oba vektory (a případně ošetřil jejich různou délku).
Napište program, který se uživatele dotáže na velikost čtvercových matic, následně náhohodně vygeneruje dvě matice příslušné velikosti a spočítá jejich maticový součet, obě vygenerované matice i výsledek následně vypíše.
\begin{equation*} A + B = \begin{bmatrix} a_{1,1} & a_{1,2} \\ a_{2,1} & a_{2,2} \end{bmatrix} + \begin{bmatrix} b_{1,1} & b_{1,2} \\ b_{2,1} & b_{2,2} \end{bmatrix} = \begin{bmatrix} a_{1,1}+b_{1,1} & a_{1,2}+b_{1,2} \\ a_{2,1}+b_{2,1} & a_{2,2}+b_{2,2} \end{bmatrix} \end{equation*}
Například pro velikost matic N=2 může program vypsat:
-2.80 7.42 9.10 6.66 + 1.08 -4.47 6.29 -5.22 = -1.71 2.95 15.40 1.44
Upravte program tak aby kromě maticového sčítání provedl i maticové odčítání.
\begin{equation*} A - B = \begin{bmatrix} a_{1,1} & a_{1,2} \\ a_{2,1} & a_{2,2} \end{bmatrix} - \begin{bmatrix} b_{1,1} & b_{1,2} \\ b_{2,1} & b_{2,2} \end{bmatrix} = \begin{bmatrix} a_{1,1}-b_{1,1} & a_{1,2}-b_{1,2} \\ a_{2,1}-b_{2,1} & a_{2,2}-b_{2,2} \end{bmatrix} \end{equation*}
4.73 -8.12 -2.89 9.45 - -6.29 -7.93 4.86 4.04 = 11.02 -0.19 -7.75 5.41
Upravte program tak aby kromě maticového sčítání a odčítání provedl i násobení prvků matice číslem.
\begin{equation*} k \cdot A = k \cdot \begin{bmatrix} a_{1,1} & a_{1,2} \\ a_{2,1} & a_{2,2} \end{bmatrix} = \begin{bmatrix} k \cdot a_{1,1} & k \cdot a_{1,2} \\ k \cdot a_{2,1} & k \cdot a_{2,2} \end{bmatrix} \end{equation*}
0.45 * 9.18 -7.09 5.33 5.66 = 4.11 -3.18 2.39 2.54
Spojte předchozí operace a vytvořte maticovou kalkulačku, která se nejprve uživatele dotáže na velikost matice a následně na operaci (+/-/*).
+
-
Příklad průběhu programu:
Zadej velikost matice: 2 Zadejte operaci (+/-/*): * 0.63 * 2.82 -1.19 0.48 2.90 = 1.77 -0.75 0.30 1.82
Upravte program tak, aby uživatel mohl po specifikaci velikosti a operace jednotlivé matice přímo zadat.
Dobře zmámá funkce sort() seřadí prvky seznamu vzestupně podle velikosti. Napište funkci selection_sort(), která pomocí algoritmu Selection sort (viz výklad na cvičení) seznam seřadí danný seznam. Vaše funkce nemůže používat funkcisort(), ale můžete ji použít ke kontrole správnosti vašeho řešení.
sort()
selection_sort()
Vytvořte program, který který od uživatele zjistí velikost N a následně vypíše do konzole Pascalův trojúhelník (Různé algoritmy výpočtu najdete na Wikipedii).
N
Například pro N=5 program vypíše:
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
Upravte program tak, aby výstup tvořil obvyklou pyramidu, tedy například pro N=7, program vypíše:
N=7
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1
(L. Peter Deutsch)´
Nejjednodušší případ rekurzivní funkce, je taková funkce, která musí k vypočítání výsledku zavolat sebe sama. Například:
def odecitej(x): return odecitej(x-1)
Funkce odecitej má ale jednu malou vadu. Nikdy nevrátí výsledek. Proto je potřeba mít v každé rekurzivní funkci takzvaný “base case”, který ukončí rekurzivní volání.
def odecitej_do_nuly(x): if x == 0: # base case return 0 # konec rekurze return odecitej_do_nuly(x-1)
Funkce odecitej_do_nuly má stále ještě jeden problém. Odhalíte jaký?
Vytvořte pole obsahujicí deset náhodných čísel pomocí rekurze.
Naimplementujte funkci faktorial(x), která vypočítá x! pomocí rekurze.
Napiště funkci fibonacci(x), která vrátí x-tý prvek fibonacciho posloupnosti.
Vytvořte matici (2D pole) 5×5.
matice = [ # matice 2x2 [1,2], [3,4], ] matice[1][1] # vrati 4 matice[0][1] # vrati 2
Vyplňte tuto matici čísly od 24 do 0 funkcí jméno_funkce(matice), a poté vypište matici na standartní výstup.
[[24, 23, 22, 21, 20], [19, 18, 17, 16, 15], [14, 13, 12, 11, 10], [9, 8, 7, 6, 5], [4, 3, 2, 1, 0]]
Máte šachové pole 9×9 a figurku jezdce na pozici (4,4). Označte všechny políčka šachovnice, na které jezdec může doskákat do tří tahů, hodnotou 1 a ostatní políčka hodnotou nula. Vypiště šachovnici na standartní výstup.
Výstup programu:
001010100 010101010 100111001 011101110 101010101 011101110 100111001 010101010 001010100
Stav sachovnice po jednotlivých tazích (namísto 0 a 1 jsou zde kvůli názornosti použité mezery a znak 'X'):
# prvni tah # druhy tah # treti tah | | | | | X X X | | | | | | X X X X | | | | X X | |X XXX X| | | | X X | | XXX XXX | | X | -> | X | -> |X X X X X| | | | X X | | XXX XXX | | | | X X | |X XXX X| | | | | | X X X X | | | | | | X X X |
Choose you favourite Computer Quote