Pouze tento týden sleva až 80 % na e-learning týkající se JavaScriptu
Aktuálně: Postihly zákazy tvou profesi? Poptávka po ajťácích prudce roste, využij slevové akce 30% výuky zdarma!
JavaScript týden

Lekce 8 - Funkce a výjimky v Pythonu

V předešlém cvičení, Řešené úlohy k 6. a 7. lekci Pythonu, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

V tomto tutoriálu se naučíme používat funkce a funkcionální styl programování. Dále se naučíme jednoduché ošetřování chyb programu. Vylepšíme si naši kalkulačku a uděláme z ní první chybám odolný program.

Funkce

Doteď jsme programy psali imperativně - proveď tento příkaz, potom tamten atd. Tímto způsobem lze psát jednoduché a krátké programy. Větší programy by však byly velmi nepřehledné. Proto přejdeme na další programovací paradigma (způsob jak něco naprogramovat) - funkcionální styl programování. Náš program si rozdělíme na menší části (podproblémy), které řešíme samostatně. Jednotlivé podproblémy řeší funkce. Pro funkcionální styl programování můžeme použít vše, co jsme se naučili doposud.

Funkce obvykle přijímá argumenty (data, která zpracuje) a něco vrací - nějakou výslednou hodnotu apod. (ale taky nemusí vracet nic jako např. funkce print()).

Základní syntaxe funkce

Funkce mají syntaxi podobnou větvícím příkazům (if, elif, else). Funkce se definuje pomocí klíčového slova def a výslednou hodnotu vrací klíčovým slovem return. Za def se píše mezera a poté název funkce. Za název funkce se dávají jednoduché závorky, do kterých se píší názvy jednotlivých argumentů. Funkce může být i bez argumentů. Při volání funkce se do nich dosazují hodnoty argumentů. Na konci prvního řádku se píše dvojtečka. Tělo funkce se standardně odsazuje.

Příklad:

def mocnina(cislo):
    cislo = cislo ** 2
    return cislo

Takto vytvořená funkce mocnina vrací číslo umocněné na druhou. Například při zavolání mocnina(1) vrátí 1, při zavolání mocnina(2) vrátí 4 atd.

V praxi:

def mocnina(cislo):
    cislo = cislo ** 2
    return cislo
prvni_cislo = mocnina(2)
print(prvni_cislo)

Argumentů samozřejmě může být i více např:

def soucin(prvni_cislo, druhe_cislo, treti_cislo):
    cislo = prvni_cislo * druhe_cislo * treti_cislo
    return cislo
priklad = soucin(2, 3, 4)
print(priklad)

Argumenty

Argumentů jsou dva druhy - poziční a klíčové.

Poziční argumenty jsme viděli výše. Na jejich pozici se dosadí argument na stejné pozici při volání funkce. Tyto argumenty nemají dánu základní hodnotu.

Syntaxe: název_argumentu

Klíčové argumenty mají již předem nastavenou hodnotu, kterou lze změnit. Na rozdíl od argumentů pozičních jsou označeny klíčovým slovem (mají svůj název). Tyto argumenty mají dánu výchozí hodnotu a nemusí být při volání funkce zadány v tom pořadí, v jakém jsou deklarovány. Navíc je nemusíme při volání funkce inicializovat (určit jejich hodnotu), v tom případě se použije je základní hodnota.

Syntaxe: název_argumentu=hodnota

Všechny poziční argumenty musí být deklarovány před klíčovými!

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Nyní příklad - vylepšená verze funkce mocnina:

def mocnina(cislo, exponent=2):
    cislo = cislo ** exponent
    return cislo

První argument je poziční, druhý je klíčový. Nyní můžeme volat mocnina(1) nebo mocnina(1, exponent=2), a dostaneme stejný výsledek. Navíc třeba můžeme umocnit 3 na 4 - mocnina(3, exponent=4).

Operátor *

Můžeme použít i operátor *. Ten nám umožní dělat zajímavější věci.

Např.:

nejaka_funkce(*pozicni_argumenty)

Obecně se poziční argumenty zapisují jako args a klíčové argumenty jako kwargs.

Díky tomuto zápisu se všechny zadané poziční argumenty vloží do n-tice (něco jako seznam) s názvem pozicni_argumenty. Tu poté můžeme například projíždět cyklem for..in.

Chceme-li to samé pro klíčové argumenty napíšeme dvě hvězdičky.

Příklad:

def soucin(*cisla):
    vysledek = 1
    for cislo in cisla:
        vysledek = vysledek * cislo
    return vysledek
priklad = soucin(2, 3, 4, 5)
print(priklad)

Pro zájemce - můžeme použít chuťovku typu:

funkce(*, prvni_klicovy_arg=1, druhy_klicovy_arg=1)

Přičemž nám funkce nedovolí použít poziční argumenty.

Rekurze

Rekurze označuje když funkce volá sama sebe. Lze ji použít například na výpočet faktoriálu.

Příklad:

def faktorial(cislo):
    if cislo > 0:
        return faktorial(cislo - 1) * cislo
    else:
        return 1

Při rekurzi si musíte dát pozor, aby se někdy ukončila. Jinak program upadne na přetečení zásobníku. Rekurze je pro zájemce podrobně vysvětlena u algoritmu faktoriálu.

print()

Jak jsem kdysi slíbil, tak se naučíme upravit si funkci print(). Nyní se podíváme na její dva klíčové argumenty:

  • sep - mezery mezi jednotlivými prvky (pozičními argumenty) - normálně nastaveno na mezeru (" ")
  • end - čím se zápis ukončí - normálně znak nového řádku ("\n")

Příklady:

print(1, 2, 3, "a", sep="-")

print("Žádná nová řádka!", end=" ")

Ošetření chyb

Ve většině programů, co jsme dosud vytvořili, byla chyba při vstupu čísla. Pokud jsme zadali místo čísla např. písmeno, tak program spadl.

Nyní si ukážeme, jak takovéto chyby ošetřit. Ošetření se provádí pomocí bloku try-except.

Syntaxe:

try:
    #blok příkazů
except jmeno_prvni_vyjimky:
    #blok příkazů
except jmeno_dalsi_vyjimky:
    #blok příkazů
#zde je buď konec, nebo zachycení dalších výjimek

Pokud chceme zachytit i chybovou zprávu - musíme napsat:

except jmeno_vyjimky as chyba:
    #text vyjímky se uloží do proměnné chyba

Chybám se v Pythonu (a v objektových jazycích obecně) říká výjimky. Ty základní jsou následující:

  • SyntaxError - chyba ve zdrojovém kódu
  • ZeroDivisionError - dělení nulou
  • TypeError - nesprávné použití datových typů - např. sčítání řetězce a čísla apod.
  • ValueError - nesprávná hodnota

Více výjimek zde (AJ): https://docs.python.org/…eptions.html

A nyní si ještě jednou vylepšíme naši kalkulačku:

print("Kalkulačka\n")
pokracovat = True
while pokracovat:
    prvni_cislo = int(input("Zadejte první číslo: "))
    druhe_cislo = int(input("Zadejte druhé číslo: "))
    print("1 - sčítání")
    print("2 - odčítání")
    print("3 - násobení")
    print("4 - dělení")
    print("5 - umocňování")
    cislo_operace = int(input("Zadejte číslo operace: "))
    if cislo_operace == 1:
        print("Jejich součet je:", prvni_cislo + druhe_cislo)
    elif cislo_operace == 2:
        print("Jejich rozdíl je:", prvni_cislo - druhe_cislo)
    elif cislo_operace == 3:
        print("Jejich součin je:", prvni_cislo * druhe_cislo)
    elif cislo_operace == 4:
        print("Jejich podíl je:", prvni_cislo / druhe_cislo)
    elif cislo_operace == 5:
        print(prvni_cislo, "na", druhe_cislo, "je:", prvni_cislo ** druhe_cislo)
    else:
        print("Neplatná volba!")
    nezadano = True
    while nezadano:
        odpoved = input("\nPřejete si zadat další příklad? y / n: ")
        if (odpoved == "y" or odpoved == "Y"):
            nezadano = False
        elif (odpoved == "n" or odpoved == "n"):
            nezadano = False
            pokracovat = False
        else:
            pass
input("\nStiskněte libovolnou klávesu...")

Nejprve vyrobíme funkci na získání čísla ze vstupu od uživatele:

def nacti_cislo(text_zadani, text_chyba):
    spatne = True
    while spatne:
        try:
            cislo = float(input(text_zadani))
            spatne = False
        except ValueError:
            print(text_chyba)
        else:
            return cislo

Program se opakuje v cyklu, dokud nezadáme správný vstup. Řádek s float() převede řetězec na desetinné číslo.

Dále vyrobíme funkci na vstup "y" nebo "n":

def dalsi_priklad():
    nezadano = True
    while nezadano:
        odpoved = input("\nPřejete si zadat další příklad? y / n: ")
        if (odpoved == "y" or odpoved == "Y"):
            return True
        elif (odpoved == "n" or odpoved == "N"):
            return False
        else:
            pass

Skoro to samé...

Další na řadě je volba:

def volba(prvni_cislo, druhe_cislo):
    print("1 - sčítání")
    print("2 - odčítání")
    print("3 - násobení")
    print("4 - dělení")
    print("5 - umocňování")
    cislo_operace = nacti_cislo("Zadej volbu: ", "Neplatné zadání!\n")
    if cislo_operace == 1:
        print("Jejich součet je:", prvni_cislo + druhe_cislo)
    elif cislo_operace == 2:
        print("Jejich rozdíl je:", prvni_cislo - druhe_cislo)
    elif cislo_operace == 3:
        print("Jejich součin je:", prvni_cislo * druhe_cislo)
    elif cislo_operace == 4:
        mezivysledek = 0
        try:
            mezivysledek = prvni_cislo / druhe_cislo
            print("Jejich podíl je:", mezivysledek)
        except ZeroDivisionError:
            print("Dělení nulou!")
    elif cislo_operace == 5:
        print(prvni_cislo, "na", druhe_cislo, "je:", prvni_cislo ** druhe_cislo)
    else:
        print("Neplatná volba!")

A ošetření dělení nulou. Šlo by i jen kontrolovat, zdali je druhé číslo 0.

A nyní hlavní cyklus:

def main():
    print("Kalkulačka\n")
    pokracovat = True
    while pokracovat:
        prvni_cislo = nacti_cislo("Zadej číslo: ", "Neplatné číslo!\n")
        druhe_cislo = nacti_cislo("Zadej číslo: ", "Neplatné číslo!\n")
        volba(prvni_cislo, druhe_cislo)
        if dalsi_priklad():
            pass
        else:
            pokracovat = False
    input("\nStiskněte libovolnou klávesu...")
main()

Kompletní kód kalkulačky je k dispozici níže ke stažení.

V příští lekci, Vícerozměrná pole v Pythonu, se podíváme na dvourozměrná 2D pole a vícerozměrná pole obecně, včetně příkladů a polí "zubatých".


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 738x (1.96 kB)
Aplikace je včetně zdrojových kódů v jazyce python

 

Předchozí článek
Řešené úlohy k 6. a 7. lekci Pythonu
Všechny články v sekci
Základní konstrukce jazyka Python
Článek pro vás napsal gcx11
Avatar
Jak se ti líbí článek?
24 hlasů
(^_^)
Aktivity (12)

 

 

Komentáře
Zobrazit starší komentáře (22)

Avatar
Adam Šima
Člen
Avatar
Adam Šima:18.1.2019 19:34

Zdravím,
mohl by mi prosím někdo jednoduše vysvětlit proč je funkce main až na posledních řádcích a pomocí čeho je propojená s funkcí nacti_cislo? Tak nějak bych čekal propojení skrz proměnou nebo něco takovýho, což tam nevidím. Trochu jsem se do těch funkcí zamotal a už jsem ztratil skoro 2 hodiny louskáním textu stále dokola, začínám být malinko zoufalý :)

 
Odpovědět
18.1.2019 19:34
Avatar
Martin Gregor:1.3.2019 20:33

neviem ci to napisem spravne ale main() musi byt posledna lebo v nej sa vuzivaju vsetky ostane funkcie tak tie musia byt najprv definovane ... neviem ci je to takto definovane aj v pythone ... ale odhadujem ze ano ...
a prepojenie je tam vykonane tak ze vo vnutri funkcii main sa vola funkcia nacti_cislo. Cize po spusteni programu sa vola funkcia main() a v nej funckiou nacti_cislo sa vykona nacitanie cisel z klavesnice, nasledne volba matematickej operacia a nakoniec opakovanie prikladu
neviem ci to ma este zmysel pisat to tu kedze otazka je mesiac stara ale tak mozno pre druhych ak budu mat rovnaku otazkz ...
dufam ze som to napisal dobre, nie som zrovna znaly v pythone.. :)

 
Odpovědět
1.3.2019 20:33
Avatar
Aleš Fiala
Člen
Avatar
Aleš Fiala:28.7.2019 21:00

Začalo mi při Run module vyskakovat tohle. Co mám špatně?

 
Odpovědět
28.7.2019 21:00
Avatar
Daniel Klement:24.9.2020 10:21

ten jeden krok navic je celkem zanedbatelny

Editováno 24.9.2020 10:21
Odpovědět
24.9.2020 10:21
Jestliže vím, že znám málo, dosáhnu toho, že budu znát více.
Avatar
Filip Širůček:6.10.2020 16:23

Měl bych drobnou připomínku k vysvětlení ošetření chyb v bloku try except a obecně pasivní a aktivní ošetření chyb atd. Není to kritika, protože je vůbec super že nějaké takové naučné weby jsou. Takže návrh na zlepšení. Není zde totiž moc vysvětleno proč a jak to funguje obecně ten blok a vysvětlení pasivní / aktivní ošetření atd. Ale dobře je to naopak vysvětleno až v kapitole práce se soubory. Takže pokud bychom jeli chronologicky bylo by asi lepší kdyby to vysvětlení bylo už zde a pak už se to nemusí rozebírat tak detailně (princip) v kapitole Práce se soubory...

 
Odpovědět
6.10.2020 16:23
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Filip Širůček:6.10.2020 19:39

Zdravím rozumím tomuto zápisu 1) :
except jmeno_vyjimky as chyba (Tzn do proměnné chyba se uloží systémová hláška vyjímky)
ale nerozumím tomuto zápisu 2):
except ValueError:
print(text_chyba)
Jak se tady něco může vytisknout / zobrazit když nemám předtím uloženou hodnotu do proměnné text_chyba tzn předtím mně chybí něco jako: ValueError as text_chyba nebo text_chyba = ValueError.

 
Odpovědět
6.10.2020 19:39
Avatar
Filip Širůček:7.10.2020 20:46

Super dobrý, komplexní a praktický cvičení. Už si připadám jak velkej programátor. Ale hádám že tohle stačit nebude k získání dobré práce ale i tak z toho má radost. Je fajn když něco vytvoříte a ono to funguje :-)

 
Odpovědět
7.10.2020 20:46
Avatar
Jarda Antoš
Člen
Avatar
Jarda Antoš:21. ledna 9:59

Osetreni vyjimek mi zde prijde celkem slabe vysvetlene. Ocekaval bych, ze tam bude vice prikladu. Navic v odstavci s osetrovanim vyjimek neni ani zminka o 'else' ale v prikladu s kalkulackou, kterou nasledne upravujeme, je.

Take by se hodili doplnit informace u vysvetleni funkci. Chybi mi tu, jestli mohu vynechat klicove slovo 'return' a mit jen funkci, co nic nevraci. Take se sem hodi zminka o globalnosti a lokalnosti promennych, pokud takovy problem v Python tedy je. A jeste by se hodila jmenna konvence pro python.

Celkove mam ze zakladniho kurzu Python rozporuplne pocity. Kurz opravdu projednava zaklady, ale prijde mi, ze je dost natukava a nedoda dalsi dulezite informace. Neni to jen z teto kapitoly, ale i u predchozich jsem tento pocit mel. Absolvoval jsem zde jiz kurz zakladu C# a ten je podle meho nazoru na vyssi urovni. Latka je tam vysvetlena podrobneji a dava se vetsi pozor na veci, ktere programatora mohou prekvapit. Pokud je neco nejednoznacne, tak je to tam vysvetleno. V tomhle ohledu mi to prijde jako skoda, kdyz se Python bere i jako dobry vstupni jazyk do sveta programovani, ze si musim hodne zakladnich veci dohledavat i na jinych strankach.

 
Odpovědět
21. ledna 9:59
Avatar
Kristián Lörincz:13. února 15:44

Ahoj, v podstatě jsem chtěl napsat něco podobnýho, jako nade mnou Jarda Antoš. Docela mi v tomto tutoriálu chybí "blbuvzdorné" vysvětlování pod každým příkladem, jaké je v článcích od Davida Čápky.

 
Odpovědět
13. února 15:44
Avatar
Jan Svoboda
Člen
Avatar
Jan Svoboda:16. února 20:55

Asi bych také souhlasil s kolegy nade mnou. Podrobnější vysvětlení by bylo dobré.

Editováno 16. února 20:56
 
Odpovědět
16. února 20:55
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 32. Zobrazit vše