Vytváření funkcí
Definice funkce
Funkce se definuje pomocí klíčového slova def
.
tělo funkce
Za dvojtečkou následuje blok – tělo
funkce. Pokud je v tělu funkce příkaz return
, pak se v tomto místě
funkce ukončí a pokračuje se dalšími příkazy za místem, kde byla
funkce volána. Pokud je za slovem return
nějaký výraz, stane se
návratovou hodnotou funkce. Jinak vrací funkce implicitně hodnotu
None
.
Příklad definice a použití funkce:
... return x*x
...
>>> mocnina(2)
4
Funkce je také objektem. Její platnost začíná její definicí, můžete jí přiřadit
do proměnné (tím jí přídělit nové jméno), nebo jí zrušit příkazem
del
.
>>> del mocnina
>>> square(3)
9
>>> mocnina(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'mocnina' is not defined
Parametry funkce
Funkce může mít žádný, jeden, mnoho, nebo proměnlivý počet parametrů.
Jelikož je Python beztypový jazyk, neuvádí se ani typy parametrů funkce. I pokud vytvoříte funkci, která nepoužívá žádný parametr, nesmíte zapomenout na závorky za jménem funkce. První tři případy jsou triviální, proto ukáži jen funkci s proměnlivým počtem argumentů.
Argumenty, jejichž počet dopředu neznáme se ukládá do proměnné označené hvězdičkou jako n-tice. Proměnná s * je vždy až za všemi ostatními „normálními“ parametry.
print(type(ntice))
citac = zacatek
for i in ntice:
citac = citac + 1
print("%2i:" % citac, i)
>>> vypis(5,'1','dva',3,'4')
<class 'tuple'>
6: 1
7: dva
8: 3
9: 4
Implicitní hodnoty parametrů
Implicitní hodnoty parametrů jsou příjemnou součástí moderních programovacích jazyků, jako například C++. Python není vyjímkou.
Implicitní hodnota se parametrům přiřadí v definici funkce pomocí =. Pokud se volá funkce, která obsahuje implicithní hodnoty pro některé parametry, nemusí se za tyto parametry s implicitní hodnotou dosazovat.
Vpravo od implicitního parametru mohou být již jen parametry s implicitní hodnotou. Při volání funkce se objekty dosazují nejdříve do parametrů bez implicitních hodnot a poté do parametrů s implicitními hodotami (postupuje se zleva do prava). Z toho vyplívá, že chcete-li dosadit za implicitní parametr, musíte dosadit za všechny parametry vlevo od něj. Nebo použít použít jména parametrů (viz dále).
... x = x**y
... if not format:
... return x
... else:
... return "({0})".format(x)
...
>>> print(mocnina(2), mocnina(2, 3), mocnina(2, 2, True))
4 8 (4)
A jeden chytáček: implicitní argumenty se přiřazují jen jednou. To znamená, že při použití implicitního argumetnu při každém volání funkce používáte tu samou proměnnou. Což se může někdy hodit a někdy ne. V příkladu níže se to hodí.
... if(add == None):
... return f.pop()
... f.insert(0,add)
... print(f)
...
>>> fronta('a')
['a']
>>> fronta('b')
['b', 'a']
>>> fronta('c')
['c', 'b', 'a']
>>> fronta()
'a'
>>> fronta()
'b'
Jména parametrů
Nechcete-li přemýšlet, v jakém pořadí jsou zapsány parametry v definici funkce, můžete je volat s jejich jmény. Tato možnost se také hodí pro implicitní parametry, chcete-li přiřadit hodnotu implicitnímu parametru a přitom nepřiřazovat hodnoty všem implicitním parametrům vlevo od něj.
... print(a, b, c, d, e)
...
>>> funkce(b='b', a='A', e='E')
A b c d E
>>> funkce('A', e='E', b='b')
A b c d E
>>> funkce(a='A', e='E') # chyba - není předán parametr b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: funkce() missing 1 required positional argument: 'b'
V předcházejícím příkladě s mocninou bychom si při třetím volání funkce mohli ušetřit vyplňování druhého argumentu.
'(4)'
Proměnlivý počet parametrů
Pokud dopředu nevíte kolik předáte funkci argumentů, můžete použít parametr s hvězdičkou (varadic argument). Ten bude obsahovat argumenty, které bude funkce obsahovat „navíc“ oproti obyčejným argumentům a argumentům s implicitní hodnotou, které jsou deklarovány před argumentem s hvězdičkou.
Argument s hvězdičkou musí být uveden až za parametry bez implicitní hodnoty. Argumenty s implicitní hodnotou, které jsou v definici funkci až za argumentem s hvězdičkou, nelze předat funkci jinak než jako pojmenovaný argument.
... print(a, b, c, d)
... print(ostatni)
...
>>> moje_fce(3, 4)
3 4 5 ddd
()
>>> moje_fce(3, 4, 5, 6, 7)
3 4 5 ddd
(6, 7)
>>> moje_fce(3, 4, 5, 6, 7, d='D')
3 4 5 D
(6, 7)
Poslední parametr může být parametr s dvěma hvězdičkami. Tam se přiřazují všechny argumenty, které jsou předány funkci „navíc“ jako pojmenované argumenty.
Předané hodnoty jsou uloženy do argumentu ve formě slovníku, kde klíč je jméno argumentu a hodnota je hodnota předaná argumentu.
Tento parametr musí být uveden jako poslední.
print(a, b, c)
print(ostatni)
print(ostatni_pojmenovane)
...
>>> moje_fce(3, 4)
3 4 5
()
{}
>>> moje_fce(3, 4, 5, 6, 7)
3 4 5
(6, 7)
{}
>>> moje_fce(3, 4, 5, 6, x=7)
3 4 5
(6,)
{'x': 7}
>>> moje_fce(b=3, a=4, f=5, c=6, x=7)
4 3 6
()
{'f': 5, 'x': 7}
Rozbalování argumetnů
Tato podivně pojmenovaná část je o tom, jak předat jako argumenty hodnoty uložené v seznamu (nebo listu) a slovníku.
Pokud předáte seznam nebo slovník jen svým jménem, předají se jako jeden argument. Pomocí hvězdičky nebo dvou je můžete rozbalit, jako byste jednotlivé hodnoty seznamu rozepsali do argumetnů volané funkce. U slovníků to navíc funguje jako pojmenované argumenty.
... print(a, b, c, d)
... print(zbytek)
... print(pojmenovane)
...
>>> seznam = ['a','b','c','d']
>>> slovnik = {'d' : 'DDD','e' :'EEE'}
>>> test(3,4)
3 4 0 0
()
{}
>>> test(slovnik, seznam) #slovnik odpovida jednomu argumentu (a) a seznam druhemu (b)
{'e': 'EEE', 'd': 'DDD'} ['a', 'b', 'c', 'd'] 0 0
()
{}
>>> test(*slovnik) # klíče slovníku se použijí jako nepojmenované argumenty, viz poznámka 1)
e d 0 0
()
{}
>>> test(*seznam)
a b c d
()
{}
>>> test(**slovnik)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test() missing 2 required positional arguments: 'a' and 'b'
>>> test('a','b',**slovnik)
a b 0 DDD
()
{'e': 'EEE'}
>>> test('a','b',**seznam) # chyba - ** lze aplikovat jen na slovník
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test() argument after ** must be a mapping, not list
Lokální versus globální proměnné
Teď je na čase si připomenou Jmenný prostor.
Funkce si vytvářejí také svůj lokální jmenný prostor. Každé přiřazení do
proměnné uloží hodnotu do tohoto lokálního jmenného prostoru a neovlivní
tak ten globální (což je super). Pokud se na nějakou proměnnou odvoláváte
(jejím jménem, jak jinak), pak se hledá v tomto lokálním jmenném prostoru.
Pokud se tam nenajde, hledá se ve jmenném prostoru funkce, která danou funkci
volala … a tak to pokračuje, až se dostanete do globálního jmenného
prostoru. Pokud se jméno proměnné (nebo funkce, třídy …) nenajde ani tam,
pak teprve dojde k výjimce NameError
.
Lokálně vytvořené proměnné (uvnitř těla funkce) po skončení funkce zanikají.
Pokud chcete přeci jen přiřadit hodnotu nějaké globální proměnné, můžete použít
klíčové slovo global
. Proměnná, do které se přiřazuje
se pak začne hledat v nadřazené funkci, ještě nadřazenější funkci … až
v globálním jmenném prostoru. Pokud se nenajde ani tam, tak se v globálním jmenném
prostoru vytvoří (žádná chyba).
>>> 'x' in dir() # proměnná 'x' je součástí globálního jmenného prostoru
True
>>> def test():
... x = 'localni promenna'
... y = 'localni promenna'
... global z
... z = 'globalni'
...
>>> test()
>>> print(x, z)
('globalni promenna', 'globalni')
>>> 'y' in dir() # proměnná 'y' se do globálního jmenného prostoru nedostala
False
>>> print(y)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
Jeden programátorský oříšek, který by vás mohl zaskočit:
- >>> x = 'globalni promenna'
- >>> def test1():
- ... print(x)
- ...
- >>> test1()
- globalni promenna
- >>> def test2():
- ... print(x)
- ... x = 'localni'
- ... print(x)
- ...
- >>> test2()
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "<stdin>", line 2, in test2
- UnboundLocalError: local variable 'x' referenced before assignment
Funkce test1()
používá globální proměnnou, na tom není nic
divného. Ovšem funkce test2()
už na řádku 8 bere x
jako lokální proměnnou, kvůli přiřazení na řádku 9. Pokud jste čekali,
že Python vyhodnotí na řádku 8 x jako globální proměnnou a až
na řádku 10 jako lokální, pak je to 1:0 pro Python :-). Python si totiž nejdřív
pročte celý blok, zapamatuje si všechny lokální proměnné (s nepřiřazenou hodnotou),
jako byste je všechny deklarovali na začátku bloku.