Nauč se Python > Kurzy > Začátečnický kurz PyLadies > Vlastní funkce, Git a spolupráce > Vlastní funkce

Funkce

Dříve jsme volaly funkce, které napsal někdo jiný:

print('Ahoj světe!')

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

Není to tak složité:

def obvod_obdelnika(sirka, vyska):
    "Vrátí obvod obdélníka daných rozměrů"
    return 2 * (sirka + vyska)

print(obvod_obdelnika(4, 2))

Jak to funguje?

Funkce se definuje příkazem def, za nějž napíšeš jméno funkce, pak do závorky seznam argumentů, které funkce bere, a pak dvojtečku.

Potom následuje odsazené tělo funkce – příkazy, které funkce provádí. Tělo může začít dokumentačním řetězcem, který popisuje, co funkce dělá.

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

Tělo funkce může mít více příkazů, včetně podmínek, cyklů a podobně:

def napis_hlasku(nazev, skore):
    "Popíše skóre. Název má být přivlastňovací přídavné jméno."

    print(nazev, 'skóre je', skore)
    if skore > 1000:
        print('Světový rekord!')
    elif skore > 100:
        print('Skvělé!')
    elif skore > 10:
        print('Ucházející.')
    elif skore > 1:
        print('Aspoň něco')
    else:
        print('Snad příště.')

napis_hlasku('Tvoje', 256)
napis_hlasku('Protivníkovo', 5)

Při volání funkce se hodnoty, se kterými funkci zavoláš, přiřadí jednotlivým argumentům. Takže když zavoláš třeba napis_hlasku('Tvoje', 256), můžeš si představit, že funkce dělá následující:

nazev = 'Tvoje'
skore = 256

print(nazev, 'skóre je', skore)
if skore > 1000:
    ... # atd.

Vracení

Speciální příkaz return, který jde použít jenom ve funkcích, ukončí funkci a vrátí danou hodnotu ven z funkce.

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

def ano_nebo_ne(otazka):
    "Vrátí True nebo False, podle odpovědi uživatele"
    while True:
        odpoved = input(otazka)
        if odpoved == 'ano':
            return True
        elif odpoved == 'ne':
            return False
        else:
            print('Nerozumím! Odpověz "ano" nebo "ne".')

if ano_nebo_ne('Chceš si zahrát hru? '):
    print('OK! Ale napřed si ji musíš naprogramovat.')
else:
    print('Škoda.')

Stejně jako if nebo break je return příkaz, ne funkce. Kolem „své“ hodnoty nepotřebuje závorky.

Zkus napsat funkci, která vrátí obsah elipsy daných rozměrů. Příslušný vzoreček je A = πab, kde a a b jsou délky os.

Funkci zavolej a výsledek vypiš.

Řešení

Vrátit nebo vypsat?

Předchozí program se dá napsat i takto:

from math import pi

def obsah_elipsy(a, b):
    print('Obsah je', pi * a * b)  # Pozor, `print` místo `return`!

obsah_elipsy(3, 5)

Program takhle funguje, ale přichází o jednu z hlavních výhod funkcí: možnost vrácenou hodnotu použít i jinak jež jen v print.

Funkci, která výsledek vrací, můžeš použít v dalších výpočtech:

def objem_eliptickeho_valce(a, b, vyska):
    return obsah_elipsy(a, b) * vyska

print(objem_eliptickeho_valce(3, 5, 3))

... ale kdyby výsledek přímo vypsala, nešlo by to.

Další důvod, proč hodnoty spíš vracet než vypisovat, je ten, že jedna funkce se dá použít v různých situacích. Funkci s print by nešlo rozumně použít tehdy, když nás příkazová řádka vůbec nezajímá. Třeba v grafické hře, webové aplikaci, nebo pro ovládání robota.

Podobně je to se vstupem: když použiju v rámci své funkce input, bude se moje funkce dát použít jen v situacích, kdy je u počítače klávesnice a za ní člověk. Proto je lepší funkcím potřebné informace předávat jako argumenty a input (nebo textové políčko či měření z čidla robota) nemít ve funkci, ale vně:

from math import pi

def obsah_elipsy(a, b):
    """Vrátí obsah elipsy s poloosami daných délek"""
    # Jen samotný výpočet:
    return pi * a * b

# print a input jsou "venku":
x = float(input('Zadej délku poloosy 1: '))
y = float(input('Zadej délku poloosy 2: '))
print('Obsah je', obsah_elipsy(x, y))

Samozřejmě existují výjimky: funkce která přímo vytváří textový výpis, může používat print; funkce která načítá textové informace zase input. Když ale funkce něco počítá, je dobré v ní print ani input nemít.

None

Když funkce neskončí příkazem return, automaticky se vrátí hodnota None.

Je to hodnota zabudovaná přímo do Pythonu, podobně jako True nebo False, a znamená „nic“.

def nic():
    "Tahle funkce nic nedělá"

print(nic())

Lokální proměnné

Gratuluji, umíš definovat vlastní funkce! Zbývá ještě vysvětlit jednu věc: lokální a globální proměnné.

Funkce může používat proměnné „zvnějšku“:

pi = 3.1415926

def obsah_kruhu(polomer):
    return pi * polomer ** 2

print(obsah_kruhu(100))

Ale všechny argumenty a všechny proměnné, do kterých funkce přiřazuje, jsou úplně nové proměnné, které nemají nic společného s tím, co je „venku“ kolem funkce.

Těm úplně novým proměnným se říká lokální proměnné (angl. local variables), protože existují jen místně, v rámci volání jedné jediné funkce. Takže tohle nebude fungovat tak, jak se zdá:

x = 0

def nastav_x(hodnota):
    x = hodnota  # Přiřazení do lokální proměnné!

nastav_x(40)
print(x)

Proměnné, které nejsou lokální, jsou globální – ty existují v celém programu. (Jen ve funkcích, které mají náhodou lokální proměnnou stejného jména, „nejsou vidět“ – to jméno označuje lokální proměnnou.)

Pojďme si to ukázat. Než spustíš tenhle program, zkus předpovědět, co bude dělat. Pak ho pusť, a pokud dělal něco jiného, zkus vysvětlit proč. Pozor, je tam chyták!

from math import pi
obsah = 0
a = 30

def obsah_elipsy(a, b):
    obsah = pi * a * b  # Přiřazení do `obsah`
    a = a + 3  # Přiřazení do `a`
    return obsah

print(obsah_elipsy(a, 20))
print(obsah)
print(a)

Zkus odpovědět na tyto otázky:

  • Je proměnná pi lokální, nebo globální?
  • Je proměnná obsah lokální, nebo globální?
  • Je proměnná a lokální, nebo globální?
  • Je proměnná b lokální, nebo globální?

Řešení

Jestli ti to celé připadá zmatené a složité, dá se tomu zatím vyhnout dodržováním jednoho pravidla: nepřiřazuj ve funkcích do proměnných, které existují i vně funkce. (Parametr funkce se počítá jako přiřazení.)

Domácí úkol

Přepiš program na kontrolu rodného čísla tak, aby odpovídal následujícímu zadání. Chování programu z pohledu uživatele by mělo zůstat stejné, změní se jenom zápis kódu uvnitř.

Napiš tyto funkce. Každá z nich dostane jako argument řetězec s rodným číslem a nějak ho zanalyzuje:

  • (a) Je ve správném formátu: 6 číslice, lomítko, 4 číslice? (vrací True nebo False)
  • (b) Je dělitelné jedenácti? (vrací True nebo False)
  • (c) Jaké datum narození je v čísle zakódováno? (vrací trojici čísel – den, měsíc, rok)
  • (d) Jaké pohlaví je v čísle zakódováno? (vrací 'muž' nebo 'žena')

Pro účely úkolu stačí, když bude program umět zpracovat čísla vydávaná od roku 1985. Reálná rodná čísla můžou být složitější :)

Napiš program který se uživatele zeptá na rodné číslo a vypíše výsledky.


Toto je stránka lekce z kurzu, který probíhá nebo proběhl naživo s instruktorem. Přejít na stejnou lekci v kurzu pro samouky.