Függvények bevezetés

Python-ban a kódban bárhol definiálható függvény, a def kulcsszóval.

In [ ]:
def fv_neve(n):
    "... kód ..."

Példa függvényre és meghívására

Ez egy függvény definíció, itt csak azt írjuk le, hogy mit csináljon a negyzetel függvény, ha meghívjuk:

In [1]:
def negyzetel(L):
    uj_L = []
    for i in L:
        uj_L.append(i*i)
    return uj_L

A def kulcsszó után a függvény nevét írjuk, utána zárójelekben felsoroljuk a bemeneti paramétereket. A kettőspont után új blokk kezdődik, mint például egy for ciklusban, ez a blokk fut le amikor meghívjuk a függényt.

A blokkon belül új kulcsszó a return mely hatására a függvény futása leáll és visszatér a return után írt kifejezéssel.

Egy függvényt a nevével tudunk meghívni, mely után zárójelekben a bemeneti argumentumokat kell felsorolni (itt csak egy lista a bemeneti argumentum):

In [2]:
negyzetel([4, 3, 5])
Out[2]:
[16, 9, 25]

Természtesen egy változón is meg lehet hívni a függvényt:

In [3]:
szamok = [5, 1, 8]
negyzetelt_szamok = negyzetel(szamok)
print szamok, negyzetelt_szamok
[5, 1, 8] [25, 1, 64]

Mivel "jól" volt megírva a függvényünk így semmi nem kívánt dolog nem történt, de nézzük meg mi lesz, ha ezt a megvalósítást használjuk:

In [4]:
def negyzetel2(L):
    i = 0
    while i < len(L):
        L[i] = L[i] ** 2
        i += 1
    return L

szamok = [5, 1, 8]
negyzetelt_szamok = negyzetel2(szamok)
print szamok, negyzetelt_szamok
[25, 1, 64] [25, 1, 64]

Tehát amilyen műveletet a függvényen belül végrehajtottunk a listán az a beadott argumentumon végrehajtódott, megváltozott a szamok lista. Erről egy későbbi előadáson még részletesen beszélünk, addig is tudjunk róla, hogy ez egy lehetséges hibaforrás.

Példa többváltozós függvényre

A paramétereket szóközzel választjuk el:

In [5]:
def skalaris_szorzat(v1, v2):
    osszeg = 0
    for i in range(len(v1)):
        osszeg += v1[i] * v2[i]
    return osszeg
In [6]:
skalaris_szorzat([2, 3, 5], [1, 5, 2])
Out[6]:
27

A paraméterek bármilyen típusúak lehetnek. Akárhány paramétere lehet egy függvénynek, akár nulla is, a zárójelek ebben az esetben is kellenek:

In [7]:
def ures_lista():
    return []
In [8]:
L = ures_lista()
L.append(5)
print L
[5]

Különbség függvény és metódus között

Nagyon mélyen még nem fogunk belemenni csak később, viszont az elnevezéseket jó tudni. Függvényről beszélünk, ha úgy hívható meg mint a fenti függvények és metódusról, ha a következő módon:

In [9]:
L = [5, 2, 4]
L.sort()
print L
[2, 4, 5]

A sort a pythonban egy beépített metódusa a listáknak, mely rendezi az adott listát. Jó példa, mert létezik függvény formában is:

In [10]:
L = [5, 2, 4]
ujL = sorted(L)
print L, ujL
[5, 2, 4] [2, 4, 5]

A sorted függvény nem rendezi az argumentumként adott listát, csak visszatér egy rendezett listával.

Ez a hozzáállás igaz a beépített metódusokre és függvényekre, tehát a függvények nem módosítják a kapott változókat, míg a metódusok módosítják a változót amin meg vannak hívva. Ezt a megállapodást hasznos követni és csak olyan függvényeket írni, melyek nem módosítják a kapott változókat.

Metódus írásról később tanulunk.

Egyéb hasznos információk függvényekről

A return utasítás függvényből kilépését ki lehet használni, például:

In [11]:
def prim_e(n):
    for oszto in range(2, n):
        if n % oszto == 0:
            return False
    return True
In [12]:
print prim_e(15)
print prim_e(23)
False
True

Itt azt használtuk ki, hogy amint egy return parancshoz ér a függvény azonnal kilép és visszaadja ezt az eredményt. Tehát amint találunk egy osztót azonnal visszatérünk a hamis eredménnyel. Igazzal pedig csak akkor térünk vissza, ha végigért a ciklus, azaz nem találtunk megfelelő osztót.

Függvények használata függvényekben

Általunk írt függvényeket természetesen használhatunk más általunk írt függvényekben. Ez erősen ajánlott is. Egy kódolási stílus szerint (nem kell követni, főleg nem így az elején) 4-5 sornál hosszabb függvényeket tilos írni. Így a függvényeink rövidek és egyértelműek lesznek. A működésüket nem kommentekkel, hanem a változó és függvénynevekkel írjuk le.

Nézzünk egy példát:

Írjunk egy függvényt, melynek bemenete egy lista, a függvény keresse meg a lista legkisebb elemét és nullázza ki az összes ilyen értéket a listában, majd hajtsa ezt végre a legnagyobb elemmel is!

Hogyan futunk neki egy ilyen feladatnak?

  1. Részfeladatokra bontjuk
  2. A részfeladatokat megvalósítjuk
  3. Összekötjük a teljes programot

Itt a következő részfeladatokra bontható:

  • Listában minimum keresés
  • Listában maximum keresés
  • Adott elemmel egyenlő elemek kinullázása egy listában

Oldjuk is meg ezeket:

In [13]:
def minimum(L):
    min_elem = L[0]
    for e in L:
        if e < min_elem:
            min_elem = e
    return min_elem

def maximum(L):
    max_elem = L[0]
    for e in L:
        if e > max_elem:
            max_elem = e
    return max_elem

def kinullaz(L, elem):
    ujL = L[:]     # Másolatot készítek a listáról (elejétől végéig részlista)
    for i in range(len(ujL)):
        if ujL[i] == elem:
            ujL[i] = 0
    return ujL

Most, hogy a részfeladatokat már megoldottuk nem maradt hátra más, mint hogy összerakjuk egybe a fő függvényt:

In [14]:
def min_max_nullaz(L):
    minelem = minimum(L)
    maxelem = maximum(L)
    ujL = kinullaz(L, minelem)
    ujL = kinullaz(ujL, maxelem)
    return ujL
In [15]:
min_max_nullaz([2, 3, 1, 4, 6, 2, 9, 3, 1, 3, 1, 9, 3, 9])
Out[15]:
[2, 3, 0, 4, 6, 2, 0, 3, 0, 3, 0, 0, 3, 0]

Az utolsó három sor helyett írhattuk volna akár ezt is:

In [ ]:
return kinullaz(kinullaz(L, minelem), maxelem)

Természetesen meg lehetett volna oldani ezt a feladatot egy függvénnyel is, itt az eredmény:

In [35]:
def min_max_nullaz2(L):
    min_elem = L[0]
    for e in L:
        if e < min_elem:
            min_elem = e
            
    max_elem = L[0]
    for e in L:
        if e > max_elem:
            max_elem = e
            
    ujL = L[:]     # Másolatot készítek a listáról (elejétől végéig részlista)
    for i in range(len(ujL)):
        if ujL[i] == min_elem:
            ujL[i] = 0
            
    for i in range(len(ujL)):
        if ujL[i] == max_elem:
            ujL[i] = 0
            
    return ujL
In [36]:
min_max_nullaz2([2, 3, 1, 4, 6, 2, 9, 3, 1, 3, 1, 9, 3, 9])
Out[36]:
[2, 3, 0, 4, 6, 2, 0, 3, 0, 3, 0, 0, 3, 0]

Olvashatóság szempontjából az első megoldás sokkal szebb, bár a második is jó megoldás.

Ciklusok ciklusokban, bonyolultabb algoritmusok

Rendezés

Írjunk függvényt, mely rendez egy adott listát, de nem használja se a sort se a sorted-ot!

Első ötlet: buborék rendezés

In [16]:
def buborek(L):
    ujL = L[:]
    for i in range(len(ujL) - 1):
        for j in range(len(ujL) - i - 1):
            if ujL[j] > ujL[j + 1]:
                temp = ujL[j]
                ujL[j] = ujL[j + 1]
                ujL[j + 1] = temp
    return ujL
In [17]:
buborek([2, 3, 1, 4, 6, 2, 9, 3, 1, 3, 1, 9, 3, 9])
Out[17]:
[1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 6, 9, 9, 9]
In [18]:
buborek(range(10, 0, -1))
Out[18]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [19]:
def buborek_kiir(L):
    ujL = L[:]
    for i in range(len(ujL) - 1):
        for j in range(len(ujL) - i - 1):
            if ujL[j] > ujL[j + 1]:
                temp = ujL[j]
                ujL[j] = ujL[j + 1]
                ujL[j + 1] = temp
            print ujL
    return ujL
In [34]:
buborek_kiir(range(10, 0, -1))
[9, 10, 8, 7, 6, 5, 4, 3, 2, 1]
[9, 8, 10, 7, 6, 5, 4, 3, 2, 1]
[9, 8, 7, 10, 6, 5, 4, 3, 2, 1]
[9, 8, 7, 6, 10, 5, 4, 3, 2, 1]
[9, 8, 7, 6, 5, 10, 4, 3, 2, 1]
[9, 8, 7, 6, 5, 4, 10, 3, 2, 1]
[9, 8, 7, 6, 5, 4, 3, 10, 2, 1]
[9, 8, 7, 6, 5, 4, 3, 2, 10, 1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 10]
[8, 9, 7, 6, 5, 4, 3, 2, 1, 10]
[8, 7, 9, 6, 5, 4, 3, 2, 1, 10]
[8, 7, 6, 9, 5, 4, 3, 2, 1, 10]
[8, 7, 6, 5, 9, 4, 3, 2, 1, 10]
[8, 7, 6, 5, 4, 9, 3, 2, 1, 10]
[8, 7, 6, 5, 4, 3, 9, 2, 1, 10]
[8, 7, 6, 5, 4, 3, 2, 9, 1, 10]
[8, 7, 6, 5, 4, 3, 2, 1, 9, 10]
[7, 8, 6, 5, 4, 3, 2, 1, 9, 10]
[7, 6, 8, 5, 4, 3, 2, 1, 9, 10]
[7, 6, 5, 8, 4, 3, 2, 1, 9, 10]
[7, 6, 5, 4, 8, 3, 2, 1, 9, 10]
[7, 6, 5, 4, 3, 8, 2, 1, 9, 10]
[7, 6, 5, 4, 3, 2, 8, 1, 9, 10]
[7, 6, 5, 4, 3, 2, 1, 8, 9, 10]
[6, 7, 5, 4, 3, 2, 1, 8, 9, 10]
[6, 5, 7, 4, 3, 2, 1, 8, 9, 10]
[6, 5, 4, 7, 3, 2, 1, 8, 9, 10]
[6, 5, 4, 3, 7, 2, 1, 8, 9, 10]
[6, 5, 4, 3, 2, 7, 1, 8, 9, 10]
[6, 5, 4, 3, 2, 1, 7, 8, 9, 10]
[5, 6, 4, 3, 2, 1, 7, 8, 9, 10]
[5, 4, 6, 3, 2, 1, 7, 8, 9, 10]
[5, 4, 3, 6, 2, 1, 7, 8, 9, 10]
[5, 4, 3, 2, 6, 1, 7, 8, 9, 10]
[5, 4, 3, 2, 1, 6, 7, 8, 9, 10]
[4, 5, 3, 2, 1, 6, 7, 8, 9, 10]
[4, 3, 5, 2, 1, 6, 7, 8, 9, 10]
[4, 3, 2, 5, 1, 6, 7, 8, 9, 10]
[4, 3, 2, 1, 5, 6, 7, 8, 9, 10]
[3, 4, 2, 1, 5, 6, 7, 8, 9, 10]
[3, 2, 4, 1, 5, 6, 7, 8, 9, 10]
[3, 2, 1, 4, 5, 6, 7, 8, 9, 10]
[2, 3, 1, 4, 5, 6, 7, 8, 9, 10]
[2, 1, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Out[34]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Ennél hatékonyabb algoritmusok léteznek a keresésre, ezekről részletesebben az Algoritmuselmélet című tárgy keretében fogtok tanulni.

Valósítsuk meg még azt az ötletet, hogy egyesével megkessük a legkisebb, a második legkisebb, stb. elemet és ezeket a megfelelő helyre tesszük.

In [21]:
def minimum_index(L):
    min_index = 0
    for i in range(len(L)):
        if L[i] < L[min_index]:
            min_index = i
    return min_index

def min_rendez(L):
    ujL = L[:]
    for i in range(len(ujL) - 1):
        minindex = i + minimum_index(ujL[i:])
        ujL[i], ujL[minindex] = ujL[minindex], ujL[i]
    return ujL
In [22]:
min_rendez([2, 3, 1, 4, 6, 2, 9, 3, 1, 3, 1, 9, 3, 9])
Out[22]:
[1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 6, 9, 9, 9]
In [23]:
min_rendez(range(10, 0, -1))
Out[23]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [24]:
def min_rendez_kiir(L):
    ujL = L[:]
    for i in range(len(ujL) - 1):
        minindex = i + minimum_index(ujL[i:])
        ujL[i], ujL[minindex] = ujL[minindex], ujL[i]
        print ujL
    return ujL
In [25]:
min_rendez_kiir(range(10, 0, -1))
[1, 9, 8, 7, 6, 5, 4, 3, 2, 10]
[1, 2, 8, 7, 6, 5, 4, 3, 9, 10]
[1, 2, 3, 7, 6, 5, 4, 8, 9, 10]
[1, 2, 3, 4, 6, 5, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Out[25]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

A kiírástól csalóka lehet, mert kevesebb kimenetet kaptunk, ez azért van, mert itt csak a külső for ciklusban van a kiírás, nem a belsőben. Itt a belső ciklus el van rejtve a minimum_index függvényben.

Mátrixok

Pythonban a mátrixokat listák listájával tudjuk reprezentálni:

In [27]:
M = [[1, 2], [3, 4]]

Egy elemét egy mátrixnak így érhetjük el:

In [28]:
M[0][1]
Out[28]:
2

Írjunk most egy olyan függvényt, mely márixokat viszontlag szépen ír ki, ilyesmi formában:

1 2
3 4

In [29]:
def matrix_kiir(M):
    for i in range(len(M)):
        for j in range(len(M[i])):
            print M[i][j], "\t",   # TAB karakter
        print ""
In [30]:
matrix_kiir([[1,2,3],[4,5,6],[7,8,9]])
1 	2 	3 	
4 	5 	6 	
7 	8 	9 	
In [31]:
matrix_kiir([[1,2,3, 3.5],[4,5,6, 6.5],[7,8,9, 9.5]])
1 	2 	3 	3.5 	
4 	5 	6 	6.5 	
7 	8 	9 	9.5 	

Bonyolultabb adatszerkezetek

Törzsvásárlói kedvezményt szeretnénk adni a vásárlóinknak. Adott a nevük (egyedi, string) és az eddigi vásárlásaik végösszege (egyenként). Minden ügyfélhez egy lista tartozik, melynek első eleme a személy neve, a második egy lista a vásárlások összegéről, például:
["Anett", [54, 23, 12, 56, 12, 71]]
.

A kedvezményt a következő módon adnánk:

Összes vásárlás > 200: 10%
Összes vásárlás > 500: 15%
Összes vásárlás > 1000: 20%

Írjuk meg a függvényt, mely megkapja a vásárlók listáját (elemei, mint a fenti "Anett" lista) és visszaad egy listát melyben 2 elemű listák vannak, az első elem a vásárló neve, a második a kedvezménye. Pl:
["Anett", 10]

Hogyan fogjunk neki? Ismét bontsuk részfeladatokra:

  • Vásárló listából kinyerni a vásárlások szummáját
  • A szummából eldönteni a kedvezményt
  • Az egészet elvégezni a teljes vásárló listára
In [32]:
def kedvezmeny(vasarlok):
    kedvezmenyek = []
    for vasarlo in vasarlok:
        kedvezmenyek.append(kedvezmeny_szamol(vasarlo))
    return kedvezmenyek

def kedvezmeny_szamol(vasarlo):
    nev = vasarlo[0]
    osszeg = 0
    for vasarlas in vasarlo[1]:
        osszeg += vasarlas
    return [nev, osszegbol_kedvezmeny(osszeg)]

def osszegbol_kedvezmeny(osszeg):
    if osszeg > 1000:
        return 20
    if osszeg > 500:
        return 15
    if osszeg > 200:
        return 10
    return 0
In [33]:
kedvezmeny([["Anett", [54, 23, 12, 56, 12, 71]], 
            ["Bela", [11, 3, 12, 1, 12, 55]],
            ["Hagrid", [111, 545, 343, 56, 12, 66]], 
            ["Not_a_wizard", [54, 222, 65, 56, 43, 71]]])
Out[33]:
[['Anett', 10], ['Bela', 0], ['Hagrid', 20], ['Not_a_wizard', 15]]
In [ ]: