4
Funkce

### Proč používat funkce?

### Základy funkcí

def <jméno>(<arg1, arg2, ..., argN>): 
    <příkazy  tělo funkce>
    return <návratová hodnota>

>>> def krat(x, y):        # vytvoří funkci, přiřadí jménu
...     return x * y       # tělo, spouštěno při každém volání
... 

>>> krat(2, 4)             # argumenty v závorkách
8
>>> krat('Ni', 4)          # funkce vcelku typy nezajímají
'NiNiNiNi'

def prunik(posl1, posl2):
    vysl = []                    # začneme s prázdnou posl.
    for x in posl1:              # procházíme první posloupnost
        if x in posl2:           # je prvek i ve druhé?
            vysl.append(x)       # potom ho přidej na konec
    return vysl

>>> prunik("třesky","plesky")    # dva řetězce
['e', 's', 'k', 'y']
>>> prunik([1, 2, 3], (1, 4))    # různé posloupnosti
[1]

### Obory platnosti

# globální obor pl.
X = 99                  # X a funkce v globálním oboru pl.

def funkce(Y):          # Y a Z přiřazujeme v rámci funkce
    # lokální obor pl.
    Z = X + Y           # X jsme nepřiřadili, je globální
    return Z

funkce(1)               # volání funkce vrací hodnotu 100

y, z = 1, 2        # globální proměnné

def sglobalnimi():
    global x       # x přiřazujeme
    x = y + z      # pravidlo LGS

### Předávání argumentů

>>> def menitko(x, y):
...     x = 2                # změní pouze hodnotu lok. jména
...     y[0] = 'cosi'        # pracujeme se sdílenou referencí
...
>>> X = 1
>>> L = [1, 2]
>>> menitko(X, L)            # předáváme konst. a nekonst. obj.
>>> X, L                     # nezměněno, změněno; L[:]- kopie
(1, ['cosi', 2])

>>> def nekolik(x, y):
...     x = 2              # změní pouze lokální hodnotu
...     y = [3, 4]
...     return x, y        # argumenty vracíme jako ntici ...
...
>>> X = 1
>>> L = [1, 2]
>>> X, L = nekolik(X, L)   # kterou můžeme přiřadit ntici
>>> X, L                   # předávaných jmen
(2, [3, 4])

def fce(spam, eggs, toast=0, ham=0):     # první dva nutné
    print (spam, eggs, toast, ham)

fce(1, 2)                                # výstup: (1, 2, 0, 0)
fce(1, ham=1, eggs=0)                    # výstup: (1, 0, 0, 1)
fce(spam=1, eggs=0)                      # výstup: (1, 0, 0, 0)
fce(toast=1, eggs=2, spam=3)             # výstup: (3, 2, 1, 0)
fce(1, 2, 3, 4)                          # výstup: (1, 2, 3, 4)

def prunik(*argumenty):
    vysl = []
    for x in argumenty[0]:              # procházíme první posl.
        for dalsi in argumenty[1:]:     # pro ostatní posl.:
            if x not in dalsi: break    #  je prvek obsažen?
        else:                           # ne – ukončit smyčku 
            vysl.append(x)              # smyčka neukončena
    return vysl

def sjednoceni(*argumenty):
    vysl = []
    for posl in argumenty:              # procházíme posl.
        for x in posl:                  # procházime jejich prv.
            if not x in vysl:           #  je prv. již ve výsl.?
                vysl.append(x)          # ne – přidáváme jej tam
    return vysl

% python
>>> from prunik2 import prunik, sjednoceni
>>> s1, s2, s3 = "SPAM", "SCAM", "SLAM"

>>> prunik(s1, s2), sjednoceni(s1, s2)         # 2 operandy
(['S', 'A', 'M'], ['S', 'P', 'A', 'M', 'C'])

>>> prunik([1,2,3], (1,4))                     # různé typy
[1]

>>> prunik(s1, s2, s3)                         # 3 operandy
['S', 'A', 'M']

>>> union(s1, s2, s3)
['S', 'P', 'A', 'M', 'C', 'L']

### Věcičky

lambda argument1, argument2, ..., argumentN : výraz

>>> def f1(x, y, z): return x + y + z
...
>>> f1(2, 3, 4)
9

>>> f2 = lambda x, y, z: x + y + z
>>> f2(2, 3, 4)
9

>>> x = (lambda a="ráz", b="dva", c="tři": a + b + c)
>>> x("dvá")
'dvádvatři'

>>> apply(f1, (2, 3, 4))
9
>>> apply(f2, (2, 3, 4))
9

if podmínka:
    action, args = f1, (1,2,3)
else:
    action, args = f3, (1)
apply(action, args)

>>> cisilka = [1, 2, 3, 4]

>>> upravena = []
>>> for x in cisilka:                 # ke každému prvku
...     upravena.append(x + 10)       #  přičti deset
...

>>> upravena
[11, 12, 13, 14]

>>> def inc(x): return x + 10 
...
>>> map(inc, cisilka) 
[11, 12, 13, 14]

>>> map((lambda x: x + 3), cisilka)   # objekt typu funkce
[4, 5, 6, 7]

>>> def proc(x):
...     print x                       # automat. vrací None
...
>>> x = proc('testujeme 123...')
testujeme 123...
>>> print x
None

>>> seznam = [1, 2, 3]
>>> seznam = seznam.append(4)      # append je “procedura”
>>> print seznam                   #  -- mění prvky přímo
None

>>> def vypis(zprava): 
...     print zprava
...
>>> x = vypis                      # x je další jméno naší fce.
>>> x('Jak se máme?')              # volání x
Jak se máme?

>>> def neprimo(fce, arg):
...     fce(arg)                   # volání přidáním závorek
...
>>> neprimo(echo, 'Hello jello!')  # předáme objekt typu fce.
Hello jello!

>>> codelat = [ (echo, 'Spam!'), (echo, 'Ham!') ]
>>> for (fce, arg) in codelat:
...     apply(fce, (arg,))
...
Spam!
Ham!

### Oblíbené problémy

>>> X = 99
>>> def ktereX():
... 	print X                    # bráno jako globální
... 	
>>> ktereX()
99

>>> def ktereX():
... 	print X                    # jako lokální nenalezeno
... 	X = 88                     # přiřazujeme -> lokální
... 	
>>> ktereX()
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
  File "<interactive input>", line 2, in ktery
UnboundLocalError: local variable 'X' referenced before assignment

>>> def ktereX():
...     global X              # X explicitně globální ...
...     print X
...     X = 88                # ... v celém oboru platnosti
...
>>> ktereX()
99

>>> X = 99
>>> def ktereX():
...     import __main__       # import modulu příkazové řádky
...     print __main__.X      # blíže určené (globální) jméno
...     X = 88                # bez bližšího určení - lokální
...     print X
...
>>> ktereX()
99
88

if podmínka:
    def fce():
        tělo
else:
    def fce():
        tělo
další kód
fce()

def vnejsi(x):
    def vnitrni(i):
        print i,
        if i: vnitrni(i-1)
    vnitrni(x)
print vnejsi(3)

>>> def uklada(x=[]):         # vytvoří nový objekt
...     x.append(1)           # ... a ten bude růst
...     print x
...
>>> uklada([2])               # nepoužívá implicitní h.
[2, 1]
>>> uklada()                  # používá implicitní h.
[1]
>>> uklada()                  # ... a “roste”
[1, 1]
>>> uklada()
[1, 1, 1]

>>> def uklada(x=None):
...     if x is None:         # žádný argument?
...         x = []            # vytvoř nový seznam
...     x.append(1)           # meň seznam
...     print x
...
>>> uklada([2])
[2, 1]
>>> uklada()                  # seznam “neroste”
[1]
>>> uklada()
[1]

### Shrnutí

### Cvičení

def f1(a, b): print a, b               # obyčejné, dle pozice
def f2(a, *b): print a, b              # varargs, dle pozice
def f3(a, **b): print a, b             # varargs, dle jména
def f4(a, *b, **c): print a, b, c 
def f5(a, b=2, c=3): print a, b, c     # implicitní hodnoty
def f6(a, b=2, *c): print a, b, c 

f1(1, 2) 
f1(b=2, a=1)

f2(1, 2, 3)

f3(1, x=2, y=3)

f4(1, 2, 3, x=2, y=3)

f5(1)
f5(1, 4)

f6(1)
f6(1, 3, 4)