5. Funkcije

Do sada smo koristili funkcije, no samo one unaprijed definirane u Pythonu poput funkcije float(), len() i slično. U ovom ćemo poglavlju naučiti pisati vlastite funkcije i to iz dva važna razloga:

  1. organizacija koda koji rješava neki problem funkcijama čini kod bitno preglednijim te
  2. ono izrazito povećava ponovnu upotrebljivost koda, tj. omogućuje da ne moramo uvijek nanovo pisati rješenje nekog problema.

Kako se funkcije pišu vidjet ćemo najlakše na primjeru.


In [24]:
def uvecaj(broj):
    return broj+1

Ovdje smo definirali (def) novu funkciju imena uvecaj koja prima jedan argument ((broj)) te koja vraća (return) taj argument uvećan za jedan (broj +1). Iz tijela funkcije vidljivo je da argument mora biti brojčana vrijednost. Kako je Python dinamički tipiziran jezik, tj. kako se tip podataka određuje tijekom izvršavanja koda, nije moguće, odnosno potrebno ograničavati tip podataka koji se funkciji pruža kao argument.

Pogledajmo kako bi napisali funkciju koja prebrojava broj samoglasnika u nekom Unicode nizu znakova:


In [29]:
def broj_samoglasnika(niz_znakova):
    rezultat=0
    for znak in niz_znakova:
        if znak.lower() in 'aeiou':
            rezultat+=1

U većini funkcija računamo rješenje nekog problema (u ovom slučaju broj samoglasnika u nizu znakova) te na kraju izračuna konačnu vrijednost vraćamo koristeći rezerviranu riječ return. Funkcija u ovom primjeru kao argument prima niz znakova (niz_znakova), a vraća cjelobrojnu vrijednost (rezultat) koja odgovara broju samoglasnika u tom nizu znakova.

Na sljedeći način ćemo upotrijebiti dvije napisane funkcije:


In [26]:
print uvecaj(23)


24

In [32]:
print broj_samoglasnika('Ovo je niz znakova.')


7

U prvom primjeru smo broj 23 uvećali za jedan, a u drugom smo izračunali broj samoglasnika u nizu Ovo je niz znakova..

U nastavku ćemo napisati dvije funkcije za računanje frekvencijske distribucije te njeno sortiranje. Oba smo postupka upoznali u poglavlju o rječnicima, no sada ćemo ih zapisati kao funkcije.

Prva je funkcija za računanje frekvencijske distribucije:


In [33]:
def frek_distr(iterabilni):
    rjecnik={}
    for element in iterabilni:
        rjecnik[element]=rjecnik.get(element,0)+1
    return rjecnik

Funkcija frek_distr kao argument prima neki iterabilni objekt iterabilni. U našem slučaju će to najčešće biti niz znakova te nešto kasnije i lista riječi iz nizova znakova. Zatim stvara prazan rječnik (rjecnik={}) koji će sadržavati pojave i njihove vrijednosti. Nakon toga for petljom iterira kroz iterabilni objekt (niz znakova ili lista) (for element in iterabilni) te računa u novostvorenom rječniku koliko se puta pojavila određena vrijednost, odnosno računa frekvencijsku distribuciju (rjecnik[element]=rjecnik.get(element,0)+1). Konačno vraća taj novostvoreni rječnik s uređenim parovima (pojava, broj pojavljivanja) (return rjecnik).

Druga funkcija sortira frekvencijsku distribuciju:


In [34]:
def sortiraj_distr(rjecnik):
    return sorted(rjecnik.items(),key=lambda x:-x[1])

Funkcija sortiraj_distr kao argument prima rječnik (rjecnik) te vraća listu parova sortiranu po drugoj vrijednosti para (return sorted(rjecnik.items(),key=lambda x:-x[1])). Ta će nam funkcija trebati kad ćemo htjeti napraviti uvid u najčešće ili pak najrjeđe događaje u frekvencijskoj distribuciji.

Na primjer, obje funkcije primijenit ćemo na sljedeći način:


In [35]:
niz_znakova='otorinolaringologija'
fd=frek_distr(niz_znakova)
print fd
print sortiraj_distr(fd)


{'a': 2, 'g': 2, 'i': 3, 'j': 1, 'l': 2, 'o': 5, 'n': 2, 'r': 2, 't': 1}
[('o', 5), ('i', 3), ('a', 2), ('g', 2), ('l', 2), ('n', 2), ('r', 2), ('j', 1), ('t', 1)]

Prednost ovakvog rješenja je, kako smo na početku ovog poglavlja i rekli, ta što je čitljivost posljednjeg koda bitno veća te ta što nismo nanovo morali definirati rješenje ta dva problema kao što to nećemo morati učiniti ni ubuduće.

Osim što možemo računati frekvencijsku distribuciju znakova u nizu, možemo izračunati i frekvencijsku distribuciju pojavnica. Prvo ćemo napisati funkciju za opojavničenje nekog niza znakova:


In [36]:
def opojavnici(niz):
    import re
    return re.findall(r'\w+',niz,re.UNICODE)

Funkcija opojavnici kao argument uzima neki niz znakova niz. Zatim učitava modul za regularne izraze re. Konačno, vraća sve Unicode alfanumeričke znakove.

Ove tri funkcije predstavljaju osnovne alate za obrade.

Na sljedeći ćemo način opojavničiti neki niz znakova, izračunati frekvencijsku distribuciju pojavnica, sortirati ih te ispisati sortiranu listu:


In [37]:
pojavnice=opojavnici('biti ili ne biti')
fd=frek_distr(pojavnice)
sd=sortiraj_distr(fd)
print sd


[('biti', 2), ('ne', 1), ('ili', 1)]

U nastavku ćemo pokrenuti funkcije nad datotekom datoteka.txt te ispisati sortiranu frekvencijsku distribuciju znakova i frekvencijsku distribuciju pojavnica.


In [38]:
dat=open('datoteka.txt').read().decode('utf8').lower()
pojavnice=opojavnici(dat)
fd_znak=frek_distr(dat)
fd_pojavnica=frek_distr(pojavnice)
sd_znak=sortiraj_distr(fd_znak)
sd_pojavnica=sortiraj_distr(fd_pojavnica)
print sd_znak
print sd_pojavnica


[(u' ', 13), (u'e', 8), (u'o', 8), (u'r', 6), (u'd', 5), (u'.', 5), (u'v', 5), (u'j', 4), (u'i', 3), (u'\n', 2), (u'g', 1), (u'l', 1), (u'p', 1), (u'3', 1), (u'u', 1), (u'2', 1), (u'?', 1)]
[(u'je', 4), (u'ovo', 4), (u'red', 4), (u'prvi', 1), (u'3', 1), (u'li', 1), (u'drugi', 1), (u'2', 1)]

Zadatke možete naći ovdje: Zadaci