![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
S pojmem funkce jsme se v předchozí kapitole již několikrát setkali, dokonce jsme některé již používali (
Dalším typem funkce jsou funkce uživatelsky definované (user-defined), neboli uživatelské funkce.
S pojmem funkce úzce souvisí pojem metoda, což je funkce, definovaná uvnitř třídy (viz kap. 10) a je volaná pro
>>>hi = "nazdar"# objekt typu <string> >>>hi .upper () 'NAZDAR'
Funkce je uspořádané pořadí příkazů, které provádějí požadovanou operaci pro zadaný výčet parametrů. Příkazy jsou deklarovány v těle funkce, parametry jsou uvedeny v záhlaví funkce. Syntaxe pro definování funkce je tato:
def jméno_funkce (výčet parametrů):# záhlaví ukončené dvojtečkou """ docstringg - nepovinný dokumentační řetězec """ příkazy# odsazené tělo funkce
Jméno funkce může být libovolné, kromě klíčového slova Pythonu. Výčet parametrů představuje výčet očekávaných hodnot, které je nutné funkci při invokaci (volání) poskytnout. Tento výčet může být i prázdný.
Pod záhlavím lze umístit dokumentační řetězec (docstring), který obsahuje krátkou informaci o funkci.
Uvnitř těla 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. Přechod kurzoru na počátek nového řádku signalizuje konec definování funkce.
Definice funkce se vždy skládá ze dvou částí - a to ze:.
Zde je příklad deklarace či definice funkce bez parametrů (a bez docstringu):
def novy_riadok ():# uživatelská funkce bez parametru # invokace vestavěné funkce 'print'
Funkce se jmenuje
Definování nové funkce ještě nespustí její provádění. K tomu musíme funkci volat (invokovat). Při volání (invokaci) funkce zadáváme její jméno a výčet hodnot, kterým v této situaci říkáme argumenty. Ty jsou přiřazeny k definovaným parametrům funkce. Závorky jsou vždy povinné:
Výstupem tohoto programu v konzole IDLE nebo Thonny je:emptyLines.py def novy_riadok ():""" vrátí prázdný řádek """ # dokumentační řetězec # volání vestavěné fce uvnitř funkce # volání vestavěné funkce print() novy_riadok ()# volání vlastní uživatelské fce # volání vestavěné funkce print()
First Line# mezera je vytvořena volanou funkcí novy_riadok Second Line
F:\Codetest\HowTo\ch-04> pythonemptyLines.py First Line Second Line
Nejjednodušší je funkce, která nic neprovádí:
def cosi (): pass# 'pass' je klíčové slovo
Hodnotám, které zadáváme při volání funkce, říkáme argumenty. Tyto hodnoty jsou přiřazeny k parametrům v deklarovaném záhlaví funkce. Parametry jsou (zjednodušeně řečeno) výčtem jmen, argumenty jsou výčtem hodnot. Jednotlivé parametry výčtu představují
Parametr s přiřazenou hodnotou (např.
Jméno s přiřazenou hodnotou, uplatněné při volání funkce, se označuje jako
V dalším textu použijeme označení párový parametr pro implicitní parametr a párový argument pro pojmenovaný argument.
Jednotlivé kategorie parametrů a argumentů jsou (podle pořadí zleva doprava) tyto:
poziční, variadické poziční, párové, variadické párové.
Poziční
Variadické
Při zadávání argumentů deklarované funkci jsou kontrolovány tyto aspekty:
>>>li = [1,2,3,4] >>>def mysum (arg):# funkce s 1 parametrem sum (arg)) >>> mysum(li)# 1 argument pro 1 parem. arg 10 >>> mysum(1,2,3,4)# 4 argumenty pro 1 param. arg TypeError ...
Mezi pozičními a párovými parametry či argumenty existuje zdánlivě benevolentní vztah, který však respektuje požadavek aby se poziční argument neocitl za párovým.
def mocnina (m, n=2):# m je poziční, n=2 je párový parametr # pořadí je OK
>>> mocnina(3)#1 OK: n=2 - párový parametr 9 >>> mocnina(3,2)#2 OK: n=2 - potvrzené přiřazení 9 >>> mocnina(3,n=2)#3 OK: n=2 - potvrzené přiřazení 9 >>> mocnina(3,n)#4 viz poznámka dole NameError: name 'n' is not defined >>> mocnina(2,3)#5 OK: n=3 - změna přiřazení 8 >>> mocnina(m=2,n=4)#6 OK: oba argumenty jsou párové 16 >>> mocnina(m=2,3)#7 porušení pravidla: SyntaxError: positional argument follows keyword argument ... poziční argument nesmí přijít za párovým
Hvězdička
def foo (a, b, *, c, d):# hvězdička jen organizuje
>>> foo(2, 4, c="jin", "jan")# "jan" je poziční argument SyntaxError: positional argument follows keyword argument >>> foo(2, 4, c="jin", d="jan")# c,d jsou párové argumenty 2 4 jin jan# no comment
def ef (a, b, /, c, d, *, e, f):# lomítko jen organizuje
>>> ef(10, 20, 30, d=40, e=50, f=60) 10 20 30 40 50 60 >>>f (10,a=20 ,30 , d=40, e=50, f=60)SyntaxError: positional argument follows keyword argument >>> ef(10, b=20, c=30, d=40, e=50, f=60)TypeError: f() got some positional-only arguments passed as keyword arguments # dle definice mají být první dva argumenty poziční
Některé vestavěné funkce, například
>>>len (obj='hello')TypeError: len() takes no keyword arguments
Variadické argumenty *args mají formát
Invokace funkce s variadickým parametrem typu
>>>def myFun (*argv):for arg in argv: # tato funkce poskytuje více možností # Argumenty funkce: >>>myt = (a:="Tam za vodou", b:="v rákosí ...")# entice >>>mys = {a:="Tam za vodou", b:="v rákosí ..."}# set >>>myd = {a:"Tam za vodou", b:"v rákosí ..."}# slovník # Různé invokace funkce: >>> myFun(*myt); myFun(*myd) >>> myFun(a:="Tam za vodou", b:="v rákosí ...") >>> myFun(*{a:"Tam za vodou", b:"v rákosí ..."}) >>> myFun(*mys) num1 = 7,11 Tam za vodou v rákosí ...# ... porovnejte s invokací (jen tak, pro zajímavost): >>> myFun(myt); myFun(myd)# Pozor na způsob přiřazení: >>> mytt = (a: "Tam za vodou", b: "v rákosí ...")mytt = (a: "Tam za vodou", b: "v rákosí ...") ^ SyntaxError: invalid syntax # slovníková forma obsahu vyžaduje složené závorky
Další příklad: Vestavěná funkce
Při invokaci vestavěné funkce lze pro variadický parametr uplatnit buď výčet hodnot nebo variadický či prostý argument:
>>>num1 = 7,11# entice, neboli tuple >>>max (7,11),max (num1),max (*num1) (11, 11, 11) >>>num2 = 3*11, 5**3, 512-9, 1024*0; num2 (33, 125, 503, 0) >>>max (3*11, 5**3, 512-9, 1024*0),max (num2),max (*num2) (503, 503, 503) >>>str = "abakus" >>>max ("abakus"),max (str),max (*str) ('u', 'u', 'u')# pořadí je dáno přiřazenými kódovými čísly
def add(*number): # entice jako variadický parametr result =0for iin number: result +=i
>>>add (1,2,3,4,5)# přes poziční argumenty 15 >>>num = (47,11,12) >>>add (*num)# přes variadickou proměnnou 70add (num)# přes prostou proměnnou TypeError: unsupported operand ...
Pro ilustraci variadického parametru (*b) vytvoříme funkci, ve které použijeme i poziční i párový parametr:
def sum_not_first (a,*b,c=8):# poziční, variadický, párový parametr temp =sum (b)
Variadický poziční parametr
>>> sum_not_first(1, 2, 3, 4)# c=8 stále platí! sum(b)= 9 a,b,c = 1 (2, 3, 4) 8# o '1' si řekne par. 'a' sum_not_first=sum(b)+c= 17
Jinak tomu je s variadickým parametrem na prvním místě. Za variadickým pozičním argumentem smějí přijít jen párové argumenty!:
def sum_not_first (*b,c=8,a):# zatím nic proti ničemu temp = sum(b)
>>> sum_not_first(1, 2, 3, 4)# chyba se projeví až při invokaci TypeError: sum_not_first() missing 1 required keyword-only argument: 'a' # chybí 1 párový argument
Argument pro
>>> sum_not_first(1, 2, 3, a=4)# a=4: náprava chyby sum(b)= 6 a,b,c = 4 (1, 2, 3) 8 sum_not_first=sum(b)+c= 14
Nyní si ukažme pozici
def sum_not_first (a,c=8,*b):temp =sum (b)
>>> sum_not_first(1, 2, 3, 4)# něma problema sum(b)= 7 a,b,c = 1 (3, 4) 2 sum_not_first = 9
Podle klobacího pořádku obdržel parametr
Lze rovněž použít pouze prvky sběrného parametru:
def sum_skip_first (a,*b):temp =sum (b)# sum() je vestavěná funkce
>>> sum_skip_first(1, 2, 3, 4) a, b, sum(b) is: 1 (2, 3, 4) 9
Variadický formát lze použít i při obsazování pozičních parametrů:
def test_args (a, b, c):# hvězdička zde značí součin
>>>slova = (" abra", "kadabra")# argumentem je entice >>> test_args(2, *slova)# hvězdička signalizuje entici Virbl: abrakadabra abrakadabra
Případně:
>>>pairs = {" hola": "b", "hej": "c"}# argumentem je slovník >>> test_args(2, *pairs)# hvězdička signalizuje entici Virbl: holahej holahej# Enticové rozbalení slovníku vrací pouze klíče slovníku.
Variadické
# kwargs.py def about (**users):for key,val in users .items() :
a) Invokace funkce pro
>>>log ={'user':'Tom', 'city':'London', 'pet':['dog','cat','fish']} >>> about(**log)# argument má formát slovníku user => Tom city => London pet => ['dog', 'cat', 'fish']
b) Invokace funkce pro
# zde je argumentem výčet párů (bez rozbalení): >>> about(user='Tom', city='London', pet=['dog','cat','fish']) user => Tom city => London pet => ['dog', 'cat', 'fish']
Sběrné parametry mohou posloužit jako šikovný 'vysavač' pro nadbytečně zadané argumenty:
def eta (a, b, *c, **d):# a,b jsou poziční parametry
>>> eta(2, 3, 4, 6)# parametr *c vyluxoval co zbylo, 5 (4, 6)# na parametr **d nezbylo nic
Půvabná je rovněž tato ukázka rozbalení sběrných parametrů u slovníku:
def moje_troje (a, b, c):
>>>a = {'i': "one", 'j': "two", 'k': "three"}# slovník >>> moje_troje(*a) i j k# "Enticové" rozbalení slovníku vrací klíče slovníku. >>> moje_troje(**a)TypeError: moje_troje() got an unexpected keyword argument 'i'
Při luxování argumentů musí mít interpret jasno, co kam může přijít. Základní instrukce obdrží z výčtu parametrů v záhlaví funkce. Při invokaci funkce pro aktuální výčet argumentů provede příkazy z těla funkce:
def foo (a, b, *args, c, d, **kwargs):td = {"m":109,"n":110}kwd = {"q":113,"r":114}
Proměnné
>>> foo(1,2,3,4, td, 'oko', c=6, d='nos', kwd)SyntaxError: positional argument follows keyword argument
Viníkem je
#1 prosté uplatnění 'td' a enticové rozbalení '*kwd': >>> foo(1,2,3,4, td, 'oko', c=6, d='nos', *kwd) 1 2 (3, 4, {'m': 109, 'n': 110}, 'oko', 'q', 'r') 6 nos {}#2 'enticové' rozbalení '*td' i '*kwd': >>> foo(1,2,3,4,*td,'oko',c=6,d='nos',*kwd) 1 2 (3, 4, 'm', 'n', 'oko', 'q', 'r') 6 nos {}#3 prosté uplatnění 'td' a slovníkové rozbalení '**kwd': >>> foo(1,2,3,4,td,'oko',c=6,d='nos',**kwd) 1 2 (3, 4, {'m': 109, 'n': 110}, 'oko') 6 nos {'q': 113, 'r': 114}#4 enticové rozbalení 'td' a slovníkové rozbalení '**kwd': >>> foo(1,2,3,4,*td,'oko',c=6,d='nos',**kwd) 1 2 (3, 4, 'm', 'n', 'oko') 6 nos {'q': 113, 'r': 114}
Ve shodě s kap. 9.7 (metoda
>>> foo(1,2,3,4,*td.values (),'oko',c=6,d='nos',*kwd.values ()) 1 2 (3, 4, 109, 110, 'oko', 113, 114) 6 nos {}
Nepřehlédněme, že se nám rozbalené hodnoty (i klíče) slovníků přiřazují do variadické entice.
Vestavěné funkce, které jsme zatím používali, jako
>>>biggest =max (3, 7, 2, 5); biggest# --> 7 >>>x =abs (3 - 11) + 10; x# --> 18
Ve vlastních funkcích jsme vesměs používali vestavěnou funkci
def area (rad):# 'rad' je zde poloměr kruhové plochy # area(10) -->> 314.0
To, že funkce
def suma (rad, b):
dostáváme chybové hlášení, že se pokoušíme sečíst nesourodé operandy:
>>> suma(10, 100) 314.0# výstup z fce area(rad) TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Nahradíme-li však v první funkci volání
def arrea (rad):return 3.14*rad**2# arrea(10) -->> 314.0 def suma (rad, b):# suma(10,100) -->> 414.0
Příkaz return ukončí provádění funkce v místě svého výskytu a vrací dále použitelnou hodnotu (pokud taková existuje).
Úspěch úspěšné varianty funkce
Čistá funkce nemění hodnotu vstupu, nemá vedlejší účinky a pro stejný vstup vrací vždy stejný výsledek. Vedlejší účinky produkují funkce
Pokusíme-li se tedy použít výstup funkce
Funkce, která mění vstupní hodnoty, má vedlejší účinky a je závislá na stavu vnějšího prostředí (například proměnných mimo funkci), je označována jako funkce nečistá (inpure) neboli modifikátor.
Použití příkazu
Zde je
def double_stuff_p (a_list):new_list = []# zárodek nového seznamu for value in a_list: new_list += [2*value]return new_list# nebo: print(new_list)
Čistotu této funkci zajišťuje nová pomocná proměnná
>>> lst = ["hi", 22, True]# True bude při kompilaci redukováno na 1 >>> double_stuff_p (lst) ['hihi', 44, 2] >>> lst ['hi', 22, True]# vstupní seznam nezměněn
Opakovaným voláním funkce čisté pro stejné argumenty dostáváme vždy stejný výstup, a to bez vedlejších účinků, například modifikace vstupních údajů.
Příklad téže funkce jako nečisté. Tato funkce mění každým voláním prvky zadaného argumentu i hodnotu výstupu přesto, že končí příkazem
def double_stuff_m (a_list):# argumentem bude seznam for i in range (len (a_list)):# postupná změna vstupu a_list[i] = a_list[i] * 2return a_list# nebo: print(a_list)
Tato funkce mění (modifikuje) hodnotu proměnné
>>> lst = ["hi", 22, True] >>> double_stuff_m(lst) ['hihi', 44, 2]# hodnota lst se mění! >>> double_stuff_m(lst) ['hihihihi', 88, 4]# mění se i při opakovaném volání
Jak si lze ověřit, příkaz
Má se za to, že čisté funkce se snadněji tvoří a jsou méně náchylné k chybám než programy, které používají funkce nečisté. Nicméně, programy s čistými funkcemi jsou někdy méně výkonné.
Funkce první třídy má tyto vlastnosti:
Funkce či metoda, která přijme jinou funkci jako argument nebo která jinou funkci vrací, se nazývá
Příkladem takové funkce budiž níže uvedená funkce
def f (n):return 3*n - 6def g (n):# fce f, g, h jsou funkce 1. třídy return 5*n + 2def h (n):return -2*n + 17def doto (value, fun):return fun(value)# argumentem má být hodnota a funkce
>>> doto(7, f) 15 >>> doto(7, g) 37 >>> doto(7, h) 3
Funkce
Jiný příklad funkce vyššího řádu:
def print_haf ():# funkce první třídy def do_twice (func):# funkce vyššího řádu func(); func()
>>> do_twice(print_haf) Haff Haff
Při volání funkce
Funkcemi vyššího řádu jsou i dekorátory - viz Kap. 10.7.
V kapitole 5.9,10 jsou popsány vestavěné funkce vyššího řádu
Kromě toho, že můžeme funkci zadat jiné funkci jako argument (jak popsáno v předchozím odstavci u funkce vyššího řádu), můžeme uvnitř funkce volat jinou, případně tutéž funkci. V obou případech hovoříme o složené funkci, ve druhém navíc o rekurzivní (složené) funkci.
Rekurzivní funkci poznáme v Kap. 11.1.
Jako další příklad prosté složené funkce (nikoliv funkce vyššího řádu) 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
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
import math # potřebujeme funkci 'sqrt' a konstantu 'pi' def distance (xc,yc, xp,yp):return math .sqrt ((xp-xc)**2 + (yp-yc)**2)def area (rad):math .pi *rad**2)
Pro další výpočet si vytvoříme dočasné proměnné
def area2 (xc, yc, xp, yp):radius = distance(xc, yc, xp, yp)result = area(radius)return result
Funkci jsme pojmenovali
Dočasné proměnné
def area2 (xc, yc, xp, yp):return area(distance(xc, yc, xp, yp))
Výsledkem je funkce s odkazy na funkce, deklarované mimo tělo aktuální funkce. Při volání této funkce musí mít interpret k disposici deklarace zmiňovaných fukcí.
>>> area2(20, 20, 0, 10) 1570.7963267948967
Funkce, která přijímá jinou funkci jako argument, se řadí mezi funkce vyššího řádu. S tímto typem funkcí jsme se setkali již v odstavci 4.4.
Jak již víme, vnořené (vnitřní) funkce jsou funkce, deklarované uvnitř jiných funkcí. Vnitřní funkce má přístup k proměnným a argumentům vnější funkce i k proměnným globálního prostoru, pokud nejsou
Název vnější funkce, zapsané v globálním prostoru souboru, tvoří globální proměnnou tohoto prostoru.
y = 8# globální proměnná y def outer_var ():# vnější funkce x = 2# lokální proměnná vnější fce def inner_var ():# vnitřní funkce x = 6# lokální proměnná vnitřní fce # příkaz vnitřní funkce # příkaz vnější funkce inner_var()# invokace vnitřní funkce
Proměnná vnitřní fce (x=6) stíní proměnnou vnější fce (x=2). Obě funkce mají přístup ke globální proměnné y=8:
>>> outer_var()# invokace vnější funkce outer = 10# x,y = 2,8 inner = 14# x,y = 6,8
Pokud bychom potřebovali aby hodnota proměnné vnitřní funkce byla přístupná i z prostoru vnější funkce, deklarujeme ji jako
a = "piroh"# globální proměnná def outer_fce ():# deklarace vnější fce a = 5# lokální proměnná vnější fce def inner_fce ():# deklarace vnitřní fce nonlocal a# deklarace 'nelokálnosti' a = 10# lokální proměnná vnitřní fce # příkaz vnitřní fce # příkaz vnější fce inner_fce()# volání vnitřní fce # příkaz vnější fce outer_fce()# volání vnější fce
Vnější fce1: a = 5 Vnitřní fce: a = 10 Vnější fce2: a = 10# původně bylo a = 5
Kdybychom vypustili deklaraci nelokálnosti (
Vnější fce1: a = 5 Vnitřní fce: a = 10 Vnější fce2: a = 5
Kdybychom zrušili všechny proměnné
Vnější fce1: a = piroh Vnitřní fce: a = piroh Vnější fce2: a = piroh
Kdybychom místo deklarace
Vnější fce1: a = 5 Vnitřní fce: a = 10 Vnější fce2: a = 5
Kdybychom deklaraci
Vnější fce1: a = 5 Vnitřní fce: a = 10 Vnější fce2: a = 5
Klíčová slova nonlocal a global lze použít v těchto jmenných prostorech:
Velkým korektorem přístupnosti je chyba typu
def ule ():global s# první reference 's' s = "zlatíčko"# druhá reference 's'
>>> s = "Hordubal"; ule() one: s = Hordubal two: s = zlatíčko# výstup z funkce ule() >>> print("three: s = ", s)# třetí reference 's' three: s = zlatíčko
Bez deklarace
Pokud vnořená funkce odkazuje na proměnnou, deklarovanou v rámci vnější funkce a pokud vnější funkce vrací vnitřní funkci, označujeme vnořenou funkci jako klauzuru. Vnitřní funkce může použít parametr (x), deklarovaný vnější funkcí:
def num_outer (x):# vnější funkce def num_inner (y):# vnitřní funkce return x * y# výstup z vnitřní funkce return num_inner# výstup z vnější funkce
Volání naší vnější funkce vrací vnitřní funkci pro argument vnější funkce:
>>> num_outer(10)# chybí hodnota parametru y <function num_outer.<locals>.num_inner at 0x03DE2028>
Volání klauzury lze provést jedinou invokací:
>>> num_outer(12)(4) 48
Nebo ji lze volat ve dvou krocích s použitím pomocné proměnné:
>>> huk = num_outer(12)# x = 12 >>> huk(4)# y = 4 48
Vnitřní funkce je zde vázaná na hodnotu
>>> del(num_outer) huk(5)# x = 12, y = 5 60
Vnější funkce s proměnnou:
def pat ():# vnější funkce msg = "Jsem 'pat'"# proměnná vnější funkce def mat ():# vnitřní funkce # příkaz vnitřní funkce return mat# příkaz vnější funkce
>>> pat()() Jsem 'pat' >>> bat = pat(); bat() Jsem 'pat'
Speciálním druhem funkcí jsou takzvané anonymní funkce, které používají společné označení lambda. Anonymní jsou proto, že nemaji vlastní jméno. Na rozdíl od ostatních funkcí se deklarují přímo v místě použití. Jejich syntaxe je velice prostá:
lambdaparametry :výraz [argumenty ]
Funkce lambda může mít libovolný počet parametrů ale jen jeden deklarovaný výraz (expression).
>>> (lambdax, y :x * y ) (2, 3 )# bezprostředně volané provedení funkce 6 >>>soucin = lambdax, y :x * y # jméno umožňuje opakované použití >>> soucin(2, 3)# invokace 6
Anonymní funkci lze s výhodou použít jako argument pro jinou funkci (připadně ještě s jinou funkcí):
# lambda uvnitř skriptu: numera = (2, 6, 8, 10, 11, 4, 12, 7, 13, 17, 0, 3, 21)selekce = list(filter(lambda num: (num > 7), numera)) print(selekce)# -->[8, 10, 11, 12, 13, 17, 21]
Ve funkci lambda lze rovněž použít variadický parametr
# parametry funkce jsou hodnoty (values) slovníku 'slov': >>>slov = {'one':1, 'two':2, 'three':3} >>>mean_val = (lambda **slov: sum(slov.values()) / len(slov)) >>> mean_val(**slov) 2.0# tato funkce pracuje prostřednictvím proměnné **kwargs se slovníkem (viz výše) i s enticí pojmenovaných (keyword) hodnot: >>> mean_val(one=1, two=2, three=3) 2.0
Funkce
Funkce
Python disponuje obsáhlou řadou vestavěných matematických funkcí a konstant, k nímž získáme přístup importem modulu
>>> import math >>> math.exp(2)# --> e**2 7.38905609893065 >>> 3*math.pi 9.42477796076938
V prostředí IDLE ji volejte třikrát - s prvním argumentem menším, větším a stejným (než) jako druhý argument.if x < y :elif x > y :else:
def vynos (p, r, *, t=10, n=12):
Vložte tento skript do souborudef cat_times (s,n): <zde zapište svůj kód>
>>> from caclr-ttimes import * >>> cat_times('Spam', 7) SpamSpamSpamSpamSpamSpamSpamChodí? Vyzkoušejte si funkci i pro jiné argumenty.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |