![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Vestavěné funkce, které jsme zatím používali, jako abs, pow a max tvoří 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
V kapitole 3 nám vracela hodnotu ta funkce, která obsahovala příkaz print. Jak to dopadne, když tento příkaz do funkce nezadáme? Zkusme si to na příkladech:
>>> def hum(a,b): # zde 'print' máme ... print a+b ... >>> hum(2,3) 5 # a máme výstup >>> def lum(a,b): # zde 'print' nemáme ... a+b >>> lum(2,3) >>> # a výstup také ne >>> x = lum(2,3) >>> print x None # ani zde ne
Bez výslovného příkazu na nás funkce nemluví, v lepším případě krčí rameny (viz None).
V této kapitole se seznámíme s funkcemi, které vrací hodnotu příkazem return. Než nás napadne lepší označení, budeme jim říkat funkce produktivní (fruitful functions), neboli funkce s výstupní hodnotou. Prvním příkladem bude fce area, která vrátí plochu kruhu zadaného poloměrem:
def area(radius): temp = 3.14159 * radius**2 return temp
Příkaz return jsme již viděli, ale ve funkci výnosné zahrnuje return i výstupní hodnotu. Říká doslova: "Okamžitě z této funkce vystup a následující výraz použij jako výstupní hodnotu". Onen výraz může být libovolně složitý, takže můžeme zapsat stručněji:
def area(radius): return 3.14159 * radius**2
Na druhé straně, dočasné proměnné jako je temp ulehčují vyhledávání chyb.
Někdy je užitečné mít více příkazů return, v každé větvi podmínky jeden. Poznali jsme již vestavěnou fci abs; nyní si napíšeme vlastní:
def absolute_value(x): if x < 0: return -x else: return x
Protože tyto příkazy jsou v alternativní podmínce, provede se pouze jeden. Jakmile se provede, funkce končí bez provedení následných příkazů.
Naši funkci můžeme zapsat také stručněji. Místo příkazu else dáme přímo příkaz return.
def absoluteValue(x): if x < 0: return -x return x
Přesvědčme se, že tato fce pracuje stejně jako ta předchozí.
Kód, který je zapsán za příkazem return i kterékoliv další místo, kam se tok programu nedostane, se nazývá mrtvý kód.
Je dobré aby ve funkci výnosné každá možná cesta programem narazila na příkaz return. V následující verzi absolute_value toto zajištěno není:
def absolute_value(x): if x < 0: return -x elif x > 0: return x
Tato verze není zcela správná, protože bude-li x rovno nule, žádná z podmínek není pravdivá a funkce končí, aniž by narazila na příkaz return; výslednou hodnotou je speciální hodnota zvaná None:
>>> print absoluteValue(0)
None
None je jedinečná hodnota typu NoneType:
>>> type(None) <type 'NoneType' >
Nyní bychom bychom měli být schopni poznat pouhým pohledem na zápis funkce co má provádět. Pokud jsme prováděli cvičení, sami jsme několid menších fcí napsali. Při psaní větších funkcí nám mohou nastat potíže kvůli významovým chybám a chybám při běhu programu.
Abychom se vyrovnali s rostoucí složitostí programů seznámíme se s technikou, zvanou přírůstkový rozvoj. Jeho cílem je vyloučení dlouhých seancí při odstraňování chyb tím, že se postupně přidávají a testují krátké úseky kódu.
Jako příklad předpokládejme, že chceme nalézt vzdálenost dvou bodů, daných souřadnicemi (x1, y1) a (x2, y2). Vzdálenost podle Pythagorovy věty je:

Nejprve musíme uvážit jak by měla funkce distance vypadat. Jinými slovy, jaké budou vstupy (parametry) a jaký bude výstup (hodnota return)?
V našem případě musíme na vstupu zadat dva body, reprezentované čtyřmi parametry. Výstupní hodnotou bude vzdálenost s hodnotou float.
Již můžeme psát obrys funkce:
def distance(x1, y1, x2, y2): return 0.0
Je zřejmé, že tato verze žádnou vzdálenost nepočítá, neboť vždycky vrátí nulu. Je ale skladebně (syntakticky) správná, poběží a můžeme jí testovat před tím než ji zkomplikujeme.
Abychom ji otestovali, zavoláme ji pro jednoduché hodnoty:
>>> distance(1, 2, 4, 6) 0.0
Hodnoty jsme vybrali tak, aby vodorovná vzdálenost bodů byla 3, svislá 4 a výsledná vzdálenost 5 (což je přepona pravoúhlého trojúhelníka). Při testování funkce je užitečné znát správný výsledek předem.
V této chvíli jsme se přesvědčili, že funkce je syntakticky správná a můžeme začít přidávat řádky kódu. Po každé malé změně funkci znovu otestujeme. Objeví-li se v kterémkoli místě chyba, budeme vědět kde musí být – v posledním přidaném řádku.
Prvním logickým krokem ve výpočtu bude nalézt rozdíly x2-x1 a y2-y1. Tyto hodnoty uložíme do dočasných proměnných dx,dy a vytiskneme je.
def distance(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 print "dx is", dx print "dy is", dy return 0.0
Je-li funkce v pořádku, měly by výsledky být 3 a 4. Jestliže ano, ověřili jsme si, že náš dílčí program pracuje správně. Pokud ne, potřebujeme prověřit jenom několi málo řádků.
Nyní sečteme součet čtverců pro dx a dy.
def distance(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 dsquared = dx**2 + dy**2 print "dsquared is: ", dsquared return 0.0
Všimněme si, že jsme odstranili příkaz print, který jsme zapsali v předchozím kroku. Takové části kódu říkáme lešení, protože pomáhá při sestavení programu, ale není součástí finálního výsledku.
Opět necháme proběhnout program a zkontrolujeme výstup (což by mělo být 25).
Konečně, s použitím zlomkového exponentu 0.5 pro nalezení odmocniny, můžeme spočítat výsledek:
def distance(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 dsquared = dx**2 + dy**2 result = dsquared**0.5 return result
Pokud nám to chodí správně, jsme hotovi.
Když začínáme, měli bychom přidávat jen po jednom či dvou řádcích. Po získání jisté zkušenosti můžeme přidávat po větších dávkách. Přírůstkový rozvoj nám v každém případě ušetří mnoho času při odstraňování chyb.
Klíčové aspekty tohoto postupu jsou:
Padla již zmínka, že jedna funkce může volat druhou. Této schopnosti říkáme propojení nebo složení (composition) funkcí.
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. Naštěstí jsme právě napsali funkci distance, která to umí, takže ji můžeme hned použít:
radius = distance(xc, yc, xp, yp)
V druhém kroku určíme plochu kruhu pro daný poloměr a zobrazíme ji.
result = area(radius)
return result
Když to celé zabalíme do jedné funkce, dostaneme:
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 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))
Funkce mohou vracet i booleovské hodnoty, což je často vhodné pro ukrytí složitých ověřování uvnitř funkcí. Například:
def is_divisible(x, y): if x % y == 0: return True else: return False
Jméno této funkce je is_divisible (je_dělitelné). Je obvyklé dávat booleovským funkcím jména, která zní jako otázka "ano či ne". Funkce is_divisible vrací buď True nebo False podle toho, zda x je či není dělitelné y.
Funkci můžeme ještě zjednodušit využitím faktu, že podmínka příkazu if je sama booleovským výrazem. Výsledek získáme přímo i po vypuštění příkazu if:
def is_divisible(x, y): return x % y == 0
Následující seance předvádí novou funkci v akci:
>>>is_divisible(6, 4) False >>>is_divisible(6, 3) True
Booelovské funkce jsou často používány v podmíněných příkazech:
if is_divisible(x, y): print "x is divisible by y" else: print "x is not divisible by y"
Mohlo by být lákavé napsat výraz ve tvaru:
if is_divisible(x, y) == True:
...
Avšak toto extra srovnání je nadbytečné.
Funkce ja dalším typem Pythonu, jako dosud poznané typy int, float, str, bool a NoneType.
>>> def func(): ... return "fce func was called" ... >>> type (func) <type '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 argumentu fun nahradíme vlastním křestním jménem?
Dobrá čitelnost programu je pro programátora velmi důležitá, protože programy jsou častěji čteny a upravovány než psány. Všechny příklady kódů v této knize jsou psány ve shodě s manuálem Python Enhancement Proposal 8 (PEP 8), v němž jsou uvedeny pokyny pro stylové úpravy kódu.
Až naše programy budou rozsáhlejší, budou i naše potřeby stylu naléhavější ale několik pokynů bude užitečných už teď:
Kromě jednoduchých a dvojitých uvozovek, které jsme poprvé viděli v Kapitole 2 při označení řetězců, má Python také řetězce s trojitými uvozovkami. Tyto uvozovky mohou být tvořeny jednoduchými i dvojitými uvozovkami:
>>> type ("""This is a triple quoted string
using 3 double quotes.""")
<type 'str'>
>>> type ('''This is a triple quoted string
using 3 single quotes.''')
<type 'str'>
>>>
Uvnitř řetězce s trojitými uvozovkami mohou být uvozovky jednoduché i dvojité:
>>> print ''' "Ach ne", zvolala, "Benovo kolo je rozbite" ''' "Ach ne", zvolala, "Benovo kolo je rozbite" >>>
Konečně, řetězce s trojitými uvozovkami mohou zabírat i více řádků:
>>> message = """ This message will ... span several ... lines. """ >>>
Tento tvar uvozovek se používá 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. Pojmy třída a metoda budou probrány později, modul je v podstatě soubor s koncovkou .py.
V dnešní době je při rozvoji programu velmi používané automatické testování krátkých úseků zdrojového kódu.
Pro toto testování má Python vestavěný modul doctest. Zkoumané vzorky kódu se umístí do dokumentačního řetězce na první řádce skriptu nebo těla funkce. V každém vzorku je na prvním řádku volání fce s argumentem, na druhém řádku je očekávaná odezva.
Za docstringem se umístí testovaný kód. Na konci skriptu nutno umístit záhadný příkaz, který importuje modul doctest a spustí testování. Ukázku si uložme do souboru myfunctions.py:
def is_divisible_by_2_or_5(n): """ >>> is_divisible_by_2_or_5(8) True >>> is_divisible_by_2_or_5(7) false >>> is_divisible_by_2_or_5(5) True >>> is_divisible_by_2_or_5(9) false """ return n%2 == 0 or n%5 == 0 if __name__ == '__main__': import: doctest doctest.testmod()
Modul doctest prověří zadanou fci pro každý argument, uvedený v dokumentačním řetězci a každý dílčí výstup porovná se zadanými hodnotami.
Zjistí-li shodu, neděje se nic. Pokud narazí na rozpor, spustí rozsáhlé chybové hlášení.
Vyzkoušejme si to na našem příkladě, když záměrně pošpatníme funkci tak, že druhou rovnost (==) nahradíme nerovností (!=).
Všechna cvičení budou postupně přidávána do souboru se jménem ch05.py. Na konec totoho skriptu se umístí následující kód:
if __name__ == '__main__': import doctest doctest.testmod()Po zapsání každého cvičení spustíme skipt, abychom se přesvědčili, že naše nová funkce projde testem.
def compare (a, b): """ >>> compare(5,4) 1 >>> compare(7,7) 0 >>> compare(2,3) -1 """ # zde napis svou fci
def hypotenuse (a,b): """ >>> hypotenuse(3,4) 5.0 >>> hypotenuse(12,5) 13.0 >>> hypotenuse(7,24) 25.0 """ # zde napis svou fci
def slope (x1,y1,x2,y2): """ >>> slope(5,3,4,2) 1.0 >>> slope(1,2,3,2) 0.0 >>> slope(1,4,1,2) 0.5 """ # zde napis svou fciFunkci slope použij v další funkci intercept(x1,y1,z2,y2), která vrací ypsilonovou pořadnici přímky, procházející bodem (x1,y1) a (x2,y2).
def intercept (x1,y1,x2,y2): """ >>> intercept(1,6,3,12) 3.0 >>> intercept(6,1,1,6) 7.0 >>> intercept(4,6,12,8) 5.0 """ # zde napis svou fci
def is_factor (f,n): """ >>> is_factor(3,12) True >>> is_factor(5,12) False >>> is_factor(2,14) True """ # zde napis svou fci
def is_multiple( (m,n): """ >>> is_multiple(12,3) True >>> is_multiple(12,4) True >>> is_multiple(12,5) False """ # zde napis svou fciŠlo by použít fci is_factor při definici fce is_multiple?
def f2c( (t): """ >>> f2c(212) 100 >>> f2c(32) 0 >>> g2c(-40) -40 >>> g2c(37) 3 """ # zde napis svou fci
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |