comment up next how to end end

3. Funkce

  1. Definice a použití
  2. Průběh výpočtu
  3. Parametry a argumenty I
  4. Parametry a argumenty II
  5. Funkce 'print'
  6. Vytváření a import modulů
  7. Čisté funkce a modifikátory I
  8. Složené funkce
  9. Funkce jako argument
  10. Lokální proměnné a parametry
  11. Dokumentační řetězce
  12. Glosář
  13. Cvičení

S pojmem funkce jsme se v předchozí kapitole již několikrát setkali, dokonce jsme některé již používali (str, int, type, ...). Jednalo se o tak zvané vestavěné (built-in) funkce, které jsou součástí programového jádra Pythonu.


3.1 Definice a použití

V souvislosti s programováním je funkce pevně určené pořadí příkazů, které provádějí požadovanou operaci. Tato operace je deklarována v definici funkce. Syntaxe pro definování funkce je tato:

def jméno_funkce(výčet parametrů):
    příkazy, neboli tělo funkce

Jméno funkce může být libovolné, kromě klíčového slova Pythonu. Výčet parametrů je výčet informací, které musíme funkci poskytnout. Tento výčet může být i prázdný ().

Uvnitř funkce může být libovolný počet příkazů, ale všechny musí být odsazeny od levého okraje. Doporučovány jsou 4 mezery, nedoporučuje se použití tabulátoru.

Definice funkce je jedním ze složených příkazů (if, while, for, with, try, funkce a třída), s kterými se postupně seznámíme. Všechy mají společný vzor:

  1. Záhlaví, které začíná klíčovým slovem a končí dvojtečkou.
  2. Tělo, skládající se z jednoho či více stejně či různě odsazených příkazů.
Klíčovým slovem v záhlaví funkce je def, které je následováno jménem funkce a v závorkách uzavřeným výčtem parametrů. Závorky jsou požadovány, i když je výčet prázdný.

Zde je příklad funkce bez parametrů:

def novy_riadok():
    print()

Tato funkce se jmenuje novy_riadok. Prázdné závorky udávají, že je bez parametru. Její tělo obsahuje jediný příkaz, jehož výstupem je prázdný řádek.

Definování nové funkce ještě nespustí její provádění. K tomu musíme funkci volat. Při volání funkce zadáváme její jméno a výčet hodnot, kterým v tomto případě říkáme argumenty. Ty jsou přiřazeny k definovaným parametrům funkce. Naše první příklady funkcí parametry nemají, tudíž se při jejich volání nezadávají žádné argumenty. Závorky jsou ovšem povinné:

print("First Line")
novy_riadok()
print("Second Line")
Výstupen tohoto programu je:
>>>
First Line
Second Line >>>

Mezera mezi řádky je výsledek volání funkce novy_riadok. Kdybychom chtěli více místa mezi řádky, můžeme volat funkci opakovaně nebo si napsat funkci nazvanou tri_riadky, která vytiskne tři nové řádky:

def tri_riadky():
    novy_riadok()
    novy_riadok()
    novy_riadok()

print("First Line")
tri_riadky()
print("Second Line")

Tato funkce obsahuje tři příkazy odsazené o čtyři mezery vpravo. Protože další příkaz není odsazen, Python pozná, že ten již není součástí definované funkce.
Funkce tri_riadky() je náhodným případem složené funkce, o nichž budeme hovořit v odst. 3.8.


3.2 Průběh výpočtu

Provádění vždy začíná prvním příkazem programu. Příkazy jsou prováděny jeden za druhým, většinou od shora dolů ale první příkaz nemusí být vždy na prvním řádku.

Volání funkce při běhu programu je jako příkaz k objížďce. Místo přechodu k následujícímu příkazu přeskočí průběh k prvnímu řádku volané funkce, provede tam všechny příkazy a vrátí se tam, kde odbočil.

To zní docela prostě, dokud si neuvědomíme, že jedna funkce může volat druhou. Nacházejíce se uvnitř jedné funkce, může mít program přikázáno provést příkaz v jiné funkci. Provádějíc příkaz v oné jiné funkci, může přijít přikaz k přechodu do ještě jiné funkce ... !

Naštěstí si Python důkladně zaznamenává, kudy při provádění programu prochází, takže se vždy správně vrací tam, odkud při volání funkce vyšel a to tak dlouho, dokud nedojde na konec programu.

Jaké je poučení z tohoto podivného příběhu? Čteme-li program, nečteme jej nutně shora dolů, nýbrž sledujeme průběh jeho provádění (výpočtu, exekuce).


3.3 Parametry a argumenty I

Většina funkcí je navrhována pro použití jedné nebo více vstupních hodnot. Hodnotám, které zadáváme při volání funkce, říkáme argumenty. Zadané hodnoty jsou uvnitř funkce přiřazeny proměnným v závorce, jež souhrnně označujeme jako parametry.

Chceme-li například nalézt absolutní hodnotu čísla 5, můžeme použít vestavěnou funkci abs(n):

>>> abs(5)
5
>>> abs(-5)
5

V tomto příkladě jsou čísla 5 a -5 argumenty funkce abs(n) .

Vestavěná funkce max vrátí největší ze zadaných argumentů.

>>> max(7, 11)
11
>>> max("abakus")
'u'
>>> max(3*11, 5**3, 512-9, 1024*0)
503

U vestavěné funkce pow(x,y), se dvěma jednoduchými parametry, si musíme dávat pozor na pořadí zadávaných hodnot, neboť se v tomto případě jedná o tak zvané poziční parametry, případně argumenty:

>>> pow(2, 3)
8
>>> pow(3, 2)
9

Z pilné lenosti si ale můžeme vytvořit obdobnou funkci vlastní, u které přiřadíme počáteční hodnotu jednomu nebo oběma parametrům. Parametrům ve formátu jméno = hodnota se říká klíčové (keyword) parametry, respektive argumenty, případně parametry s počáteční hodnotou:

def mocnina(m, n=3):
    print(m**n)

Přednastavenou hodnotu nemusíme při volání funkce uvádět, můžeme ji ale kdykoliv změnit:

>>> mocnina(2)
8
>>> mocnina(3, 2)
9
>>>

3.4 Parametry a argumenty II

(Jen pro zvídavé)

Jak již bylo řečeno, názvům v závorce záhlaví funkce říkáme parametry, zatímco zadávaným hodnotám při volání funkce říkáme argumenty.

Kromě jednoduchých parametrů (např. x, y), použitých v předchozím odstavci, existují ještě parametry s přiřazenými počátečními hodnotami, které se nazývají keyword parametry (např. n = 3)  a posléze sběrné parametry *args a **kwargs.

Parametry *args jsou určeny ke sběru enticových hodnot, neboli pozičních argumentů. Délka očekávané entice není předem určena.

Parametry **kwargs jsou určeny ke sběru slovníkových párových hodnot, neboli klíčových argumentů. Délka očekávaného slovníku rovněž není předem určena.

Aby se překladač Pythonu v této přehršli možných parametrů vyznal, je nezbytné dodržovat jistá pravidla. Cílem těchto pravidel je zajistit aby se při volání funkce množina argumentů řádně přiřadila k definované množině parametrů.

Pro aplikaci pravidel je zapotřebí provést terminologické rozlišení i u argumentů:

  1. Poziční argumenty jsou ty, pro jejichž přiřazení k parametrům neexistuje jiná informace než jejich pořadí
  2. Keyword (klíčové) argumenty (např. a=12) jsou ty, pro jejichž přiřazení k parametrům lze využít jejich názvu

Zde je výtah z pravidel, uvedených v PEP 3102:

  1. Vězme, že každý parametr má "slot", který může být prázdný nebo obsahovat hodnotu příslušného argumentu - na počátku jsou všechny sloty prázdné
  2. Nejprve jsou obsazovány sloty (zleva doprava) pozičních parametrů, posléze sloty keyword parametrů.
  3. Patří-li následující prázdný slot enticovému parametru, zaplní se zbývajícími pozičními argumenty.
  4. Hodnoty keyword argumentů zaplňují sloty stejnojmenných keyword parametrů.
  5. Sloty keyword parametrů se obsadí definovanými hodnotami, pokud zadávané keyword argumenty neurčují hodnoty jiné nebo pokud příslušný argument není uveden.
  6. Náležitě zařazené keyword argumenty mohou obsadit slot slovníkového parametru.

Uvedená pravidla mohou být zdrojem nekonečné zábavy. Zapište si funkci, kterou budete opakovaně volat pro různé argumenty:

 def hark(alfa, pi=3.14, *tup, **lib):
     print("Volné poziční argumenty: ", alfa)
     print("Keyword argumenty: ", pi)
     print("Poziční arg. entice: ", tup)
     print("Keyword arg. slovníku: ", lib)

Vyzkoušejte si sami volání například pro tyto argumenty:

hark(5)
hark(5, 4, 3, fi=8)
hark(5, a=8, b=5)
hark(5, pi)

Porovnávejte výsledky s uvedenými pravidly a čtěte případná chybová hlášení. Velice vhodný pro tuto aktivitu je editor s překladačem PyScripter.

pyscripter

Hvězdička (*) ve výčtu parametrů přikazuje, aby všechny parametry, které za ní následují, přijímaly pouze argumenty ve formátu "keyword". Stejnou účinnost má i parametr *args:

def foo(a, b, *, c, d):
    print(a, b, c, d)
>>> foo(2, 4, c="jin", d="jan")
2 4 jin jan

Sběrné parametry mohou posloužit jako šikovný 'vysavač' pro nadbytečně zadané argumenty:

def eta(a, b, *c, **d):
     print(a + b)
>>> eta(2, 3, 4, 6)
5

Případně lze použít pouze prvky sběrného parametru:

def sum_not_first(a, *bs):
    temp = sum(bs)
    print("sum is: ", temp)
>>> sum_not_first(1, 2, 3, 4)
sum is: 9

Sběrný formát lze použít i při obsazování pozičních parametrů:

def test_args(a, b, c):
     print("Virbl: ", (b + c)*a)
>>> slova=("abra", "kadabra")
>>> test_args(2,*slova)   # rozbalování argumentů z entice
Virbl: abrakadabraabrakadabra

Případně:

>>> pairs={"hola": "b", "hej": "c"}
>>> test_args(2, **pairs)  # rozbalování argumentů ze slovníku
Virbl: holahejholahej

Počet hodnot v zadávaných sekvencích musí být stejný jako počet pozičních parametrů. Jako sekvenci jednoduchých argumentů lze použít i seznam.


3.5 Funkce print()

Funkce print() se všemi svými parametry má tento tvar:

print(*objekty, sep="", end="\n", file=sys.stdout, flush=False)

Kdo si přečetl odstavec 3.4 Parametry a argumenty II, ví že parametr *objekty je sběrný enticový parametr a všechny ostatní parametry lze ignorovat, neboť to jsou parametry s počáteční hodnotou.
Takže se nám povinný tvar volání funkce smrskne na

print(*objekty)
přičemž i tento parametr lze vynechat a v tom případě nám funkce vytisne prázdný řádek.

Keyword argumenty file=sys.stdout a flush=False zajišťují výstup tisku do okna konzoly.
Změnou argumentu end="\n" na end="" lze zajistit pokračování tisku na témže řádku, přičemž rozestupem uvozovek lze ovlivnit rozestup mezi jednotlivými hodnotami výstupu.
Změnou argumentu sep="" lze přikázat typ oddělovače, případně vzdálenost mezi prvky entice.

3.6 Vytváření a import modulů

Velké množství užitečných příkazů a funkcí je uloženo v tak zvaných modulech, které jsou buď prostými soubory s příponou .py, nebo složkami těchto souborů.

Příkladem vestavěných modulů, které jsou součástí instalace Pythonu, jsou moduly math, random, sys ,   se kterými se postupně seznámíme.

K vytvoření vlastního modulu nám stačí textový soubor s příponou .py, například:

#  mojevoje.py
#
def mocnina(m, n=3):
    print(m**n)

def print_twice(bruce):
     print(bruce, bruce)

Náš modul můžeme nyní používat jak ve skriptech, tak v interaktivním rozhraní. Nejprve musíme modul importovat. Přesto, že přípona .py je součástí jména, při importu modulu ji neuvádíme, neboť si ji Python přečte sám.

Import modulu lze provést trojím způsobem:

a)
>>> from mojevoje import mocnina
>>> mocnina(5)
125
b)
>>> from mojevoje import *
>>> mocnina(5, 2)
25
>>> print_twice("koleso")
('koleso', 'koleso')
c)
>>> import mojevoje
>>> mojevoje.mocnina(4)
64

V prvním příkladě je importována pouze funkce mocnina a tuto funkci můžeme přímo v dalším kódu použít .

V druhém případě jsme importovali vše z označeného modulu. Tento způsob nebývá doporučován, protože může vést ke kolizi jmen - viz 10.4.

Ve třetím příkladě jsme importovali celý, nerozbalený objekt modulu a pro použití některého jeho atributu (zde funkce) musíme uplatnit tak zvanou tečkovou notaci (viz odstavec 10.5).

Použití modulů umožňuje rozložení velkých programů na zvládnutelné malé části a souvislé části ukládat pohromadě.

Mohlo by nás také napadnout, že by se nám hodilo, kdybychom se o importované funkci mohli něco dovědět. Taková možnost existuje a jmenuje se dokumentační řetězec - viz 3.11.

3.7 Čisté funkce a modifikátory

Vestavěné funkce, které jsme zatím používali, jako abs, pow a max nám vracely konkretní číselné výsledky. Volání každé z těchto funkcí generuje hodnotu, kterou obvykle přiřadíme k proměnné nebo použijeme jako součást výrazu:

biggest = max(3, 7, 2, 5)
x = abs(3 - 11) + 10

Ve vlastních funkcích jsme vesměs používali vestavěnou funkci print, která nám vracela různá sdělení, jímž však mohl být i výsledek výpočtu, například

def area(rad):  
   print(3.14*rad**2)    # area(10) -->> 314.0 

Pokusíme-li se však tohoto výsledku použít v jiné funkci, například:

def suma(rad, b):
   print(area(rad) + b)     # TypeError: NoneType + int 

Dostáváme chybové hlášení, že se pokoušíme sečíst nesourodé operandy. Nahradíme-li však v první funkci volání print příkazem return, budeme moci její výstup v další funkci použít:

def area(rad):  
   return  3.14*rad**2   # area(10) -->> 314.0

def suma(rad, b):
   print(area(rad) + b)    # suma(10,100) -->> 414.0

Příkaz return nejenom vrací dále použitelnou hodnotu (pokud taková existuje) ale také ukončí provádění funkce v místě svého výskytu, jak uvidíme například v odstavci 4.3.

Funkce, které vracejí hodnotu prostřednictvím příkazu return, označují autoři originálu jako funkce produkční (fruitfull). Alternativní označení pro tento typ funkcí je funkce 'čistá'.

Čistá funkce vrací hodnotu prostřednictvím příkazu return, přičemž nemění hodnotu zadaných argumentů a nemá vedlejší účinky, za něž je také považováno použití uživatelského vstupu input a použití funkce print.

Funkce, která mění vstupní hodnoty je označována jako funkce 'modifikační' neboli modifikátor. Dělení funkcí na čisté a modifikační nemá v Pythonu valný význam.


3.8 Složené funkce

Stejně jako u matematických funkcí i funkce Pythonu lze skládat, to jest použít výstup z jedné funkce jako argument pro funkci druhou.

Jako příklad si napíšeme funkci, která pro zadané dva body (střed kružnice a bod na obvodu) vypočítá plochu kruhu.

Střed kružnice uložíme do proměnných xc,yc, bod obvodu do xp,yp.
Prvním krokem bude určení poloměru kružnice, což je vzdálenost mezi oběma body.
Dalším krokem bude výpočet plochy.

Pro určení vzdálenosti dvou bodů si napíšeme funkci distance (podrobný rozvoj této funkce viz kap. 4.5), pro určení plochy si napíšeme funkci area, přičemž použijeme importovanou funkci sqrt (square root) a konstantu pi z modulu math :

import math
def distance(x1,y1, x2,y2):
    return math.sqrt((x2-x1)**2 + (y2-y1)**2)
	
def area(rad):
    print(math.pi*rad**2) 

Pro další výpočet si vytvoříme dočasné proměnné,:

radius = distance(xc,yc, xp,yp)
result = area(radius)  

které vložíme do další funkce:

def area2(xc, yc, xp, yp):
    radius = distance(xc, yc, xp, yp)
    result = area(radius)
    return result

Funkci jsme pojmenovali area2, abychom ji odlišili od funkce area, definované dříve. V jednom modulu (zde skriptu) můžeme mít jenom jednu funkci daného jména.

Dočasné proměnné radius a result jsou užitečné jenom pro rozvoj programu a vychytání chyb. Jakmile nám program pracuje správně, můžeme jej zestručnit spojením funkcí.

def area2(xc, yc, xp, yp):
  return area(distance(xc, yc, xp, yp))

Výsledkem je funkce s dvěma dalšími do sebe vnořenými funkcemi.


3.9 Funkce jako argument

Funkce je dalším typem Pythonu, jako dosud poznané typy int, float, str, bool  a  NoneType.

>>> def hale():
...   print("haleluja")
... 
>>> type(hale)
<class 'function'>
>>>

Stejně jako ostatní typy i funkce mohou být zadány jako argumenty jiným funkcím.

def f(n):
  return 3*n - 6
def g(n):
  return 5*n + 2
def h(n):
  return -2*n + 17
def doto(value, fun):
  return fun(value)

print(doto(7, f))
print(doto(7, g))
print(doto(7, h))

Funkce doto je volána třikrát pro stejný číselný argument a pro tři různá jména funkcí. V těle fce doto se říká, co má být jejím výstupem. Na konci skriptu jsou tři volání fce doto. Výstupem bude toto:

>>>
15
37
3
>>>

Co se stane, když jméno parametru fun nahradíme vlastním křestním jménem?


3.10 Lokální proměnné a parametry

Vytvoříme-li proměnnou uvnitř funkce, má platnost pouze uvnitř této funkce a mimo ní ji nelze použít. Říkáme, že je to lokální proměnná. Například:

def cat_twice(part1, part2):
    cat = part1 + part2
    print_twice(cat)

Tato funkce přijímá dva argumenty, zřetězí je (viz 7.5) a posléze je dvakrát vytiskne. Použijeme dva řetězce:

>>> chant1 = "Pie Jesu domine, "
>>> chant2 = "Dona eis requiem."
>>> cat_twice(chant1, chant2)
 Pie Jesu domine, Dona eis requiem. Pie Jesu domine,
Dona eis requiem.

Proměnná cat je zničena po ukončení funkce cat_twice. Pokusíme-li se ji vytisknout, dostaneme chybové hlášení:

>>> print(cat)
NameError: name 'cat' is not defined

Parametry jsou také lokální. Mimo funkci cat_twice nelze uplatni jména part1 a part2. Pokusíme-li se o to, bude si Python stěžovat.


3.11 Dokumentační řetězce

Kromě jednoduchých a dvojitých uvozovek zná Python také řetězce s trojitými uvozovkami, tvořenými jednoduchými i dvojitými znaky. Řetězce mohou procházet přes více řádků.

>>> """Toto je jedna možnost."""

>>> '''Toto je druhá možnost.'''

Uvnitř řetězce s trojitými uvozovkami mohou být uvozovky jednoduché i dvojité:

>>> ''' "Ach ne", zvolala, "Benovo kolo je rozbité" '''
' "Ach ne", zvolala, "Benovo kolo je rozbité" '
>>> 

Trojité uvozovky se používají pro dokumentační řetězce (docstrings). Docstring je řetězec, umístěný jako první příkaz v modulu, funkci, třídě nebo v definici metody:

def mocnina(m, n=3):
    '''
    Funkce počítá n-tou mocninu s pevně
    nastaveným exponentem n=3; lze jej změnit
    '''
    print(m**n)

Informaci o funkci získáme evokací (voláním, neboli také "aplikací") vestavěné metody .__doc__ pro objekt funkce:

>>> print(mocnina.__doc__)
Funkce počítá n-tou mocninu s pevně
nastaveným exponentem n=3; lze jej změnit
>>> 

3.12 Glosář

funkce (function)
Pojmenovaný sled příkazů, který provede nějakou užitečnou operaci. Funkce mohou nebo nemusí mít parametry a mohou nebo nemusí produkovat výsledek.
definice funkce (function definition)
Příkaz, který pro novou funkci určí jméno, parametry a příkazy, jež má provádět.
složený příkaz (compound statement)
Příkaz, který se skládá ze dvou částí:
  1. záhlaví - začíná klíčovým slovem pro příkaz a končí dvojtečkou
  2. tělo - obsahuje jeden nebo více příkazů, které jsou stejně odsazené zleva
volání funkce (function call)
Příkaz k provedení funkce. Skladá se z jména funkce před závorkou se seznamem argumentů.
průběh výpočtu (flow of execution)
Pořadí, ve kterém jsou příkazy prováděny během běhu programu.
booleovská funkce (boolean function)
Funkce, která vrací booleovskou hodnotu.
složení funkcí (composition of functions)
Volání jedné funkce z těla druhé, nebo použití výstupní hodnoty jedné funkce jako argument při volání druhé.
parameter
Jméno v záhlaví funkce, které se vztahuje k hodnotě, poskytnuté ji (při volání) jako argument.
argument
Hodnota, poskytovaná volané funkci. Tato hodnota je přiřazena odpovídajícímu parametru funkce.
import
Příkaz, kterým do skriptu nebo otevřeného IPP vložíme (importujeme) soubor, funkci nebo proměnnou, definovanou v jiném skriptu.
funkce čisté (pure function)
Funkce, která vrací hodnotu příkazem return a nemění zadané argumenty.
funkce modifikační
Funkce, která mění hodnotu zadaných argumentů.
výstupní hodnota (return value)
Hodnota, která je výsledkem volání funkce.
spojení funkcí (function composition)
Výstup z jedné funkce použijeme jako vstup pro druhou.
lokální proměnná (local variable)
Proměnná, která je definovaná uvnitř funkce, kde pouze smí být užita.

3.13 Cvičení

  1. Zabalte následující kód do funkce:  compare(x,y):
    if x < y :
      print(x, "je menší než", y)
    elif x > y :
      print(x, "je větší než", y)
    else: 
      print(x, "a", y "jsou stejné")
    
    Importujte si ji do IPP a volejte ji třikrát, s prvním argumentem menším, větším a stejným než / jako druhý argument.
  2. S použitím textového editoru vytvořte skript test3.py Napište funkci jménem nine_lines, která použije funkci tri_riadky k vytištění devíti prázdných řádek. Nyní přidejte fci clear_screen, která vytiskne 25 prázdných řádek. Poslední řádkou skriptu by mělo být volání fce clear_screen.
  3. Poslední řádek programu test3.py přesuňte úplně nahoru, takže se volání funkcíe clear_screen dostane před jeji definici. Spusťte program a sledujte, jaké chybové hlášení dostanete. Jaké z toho plyne pravidlo?
  4. V chodící verzi test3.py přesuňte definici novy_riadok za definici tri_riadky. Sledujte chování spuštěného programu. Nyní přesuňte definici novy_riadok za volání fce tri_riadky. Posuďte souvislost s pravidlem z předchozího cvičení.
  5. Doplňte tělo definované funkce cat_n_times tak, aby n krát vytiskla řetězec s:
    def cat_n_times(s,n):
        <zde zapište svůj kód>
    Uložte skript import_test.py do adresáře, ze kterého spustíže IPP a zkuste následující:
    >>> from import_test import *
    >>> cat_n_times('Spam, 7')
    SpamSpamSpamSpamSpamSpamSpam
    
    Chodí? Vyzkoušejte si funkci i pro jiné argumenty.

comment up next how to end end