Funkcije

Funkcije su korisne za razbijanje velikih programa na manje delove, što programe čini čitljivijim i lakšim za održavanja. Funkcije su takođe korisne kada morate da ponavljate isti kod u raznim delovima vašeg programa. Kod koji se ponavlja možete staviti unutar funkcije i pozivati ga kada god je potrebno da izvršavate naredbe iz tog koda. Funkcije možete koristiti i za kreiranje svojih pomoćnih programa, matematičkih funkcija itd.

Osnovni koncept

Funkcije se definišu def naredbom. Naredba se završava sa dve tačke, a kod koji je deo funkcije se piše u bloku ispod def naredbe. Ovde kreiramo jednu jednostavnu funkciju koja nešto štampa.

def print_hello():
    print('Hello!')

print_hello()
print('1234567')
print_hello()

Rezultat rada gornjeg programa:

Hello!
1234567
Hello!

Prve dve linije definišu funkciju. U poslednje tri linije pozivamo definisanu funkciju dva puta.

Jedna od upotreba funkcije je kada isti kod koristite u različitim delovima vašeg programa, jer tada možete vaš program učiniti kraćim i čitljivijim. Na primer, pretpostavimo da iz nekog razloga treba da štampate pravougaonik kao ovaj dole prikazan, na više mesta u vašem programu.

**************
*            *
*            *
**************

Ako stavimo kod u funkciju, onda kada god vam zatreba da štampate pravougaonik, jedino što je potrebno je da pozovete funkciju, umesto da ponovo ukucavate isti kod. Evo kako bi takva funkcija izgledala.

def draw_square():
    print('*' * 15)
    print('*', ' '*11, '*')
    print('*', ' '*11, '*')
    print('*' * 15)

Jedna od prednosti ovakvog pristupa je da kada odlučite da promenite veličinu pravougaonika, treba samo da modifikujete funkciju, dok bi u slučaju da ste ponavljali kod morali svuda da napravite izmenu.

Argumenti funkcije

Funkcijama možemo proslediti vrednosti. Evo primera:

def print_hello(n):
    print('Hello ' * n)
    print()

print_hello(3)
print_hello(5)
times = 2
print_hello(times)

Rezultat:

Hello Hello Hello
Hello Hello Hello Hello Hello
Hello Hello

Kada pozivamo print_hello funkciju sa vrednošću 3, ta vrednost se smešta u varijablu n. Možemo se pozivati na varijablu n u kodu funkcije.

Funkciji možemo proslediti i više vrednosti istovremeno:

def multiple_print(string, n)
    print(string * n)
    print()

multiple_print('Hello', 5)
multiple_print('A', 10)

Rezultat:

HelloHelloHelloHelloHello
AAAAAAAAAA

Povratna vrednost iz funkcije

Možemo napisati funkcije koje vrše računanje i vraćaju rezultat.

Primer 1

Ovde dajemo jedan jednostavan primer funkcije koja konvertuje tempearturu iz Celzijusa u Farenhajte.

def convert(t):
    return t*9/5+32

print(convert(20))

Rezultat:

68

Naredba return se koristi da se pomoću nje pošalje rezultat proračuna nazad pozivaocu funkcije.

Uočite da same funkcije ne štampaju ništa. Štampanje smo vršili van funkcije. Na taj način možemo koristiti rezultat funkcije da sa njim vršimo dalje proračune kao u donjem primeru:

print(convert(20)+5)

Da smo rezultat štampali u samoj funkciji umesto što smo ga return naredbom vratili, u tom slučaju bi rezultat bio štampan ali i zaboravljen za dalju upotrebu.

Primer 2

Kao još jedan primer, Python math modul sadrži trigonometrisjke funkcije, ali sve one rade samo u radijanima. Mi možemo napraviti ekvivalentne funkcije koje rade u stepenima, kako prikazuje sledeći primer.

from math import pi, sin

def deg_sin(x):
    return sin(pi*x/180)

Primer 3

Funkcija može vratiti više vrednosti istovremeno, i to u obliku liste.

Recimo da želimo da napišemo funkciju koja rešava sistem jednačina ax+by=e i cx+dy=f. Može se matematički pokazati da su njihova rešenja x=(de-bf)/(ad-bc) i y=(af-ce)/(ad-bc). Funkicija koja nalazi ta rešenja treba da nam vrati rešenja i za x i za y.

def resi_jednacinu(a,b,c,d,e,f):
    x = (d*e-b*f)/(a*d-b*c)
    y = (a*f-c*e)/(a*d-b*c)
    return [x,y]

xres, yres = resi_jednacinu(2,3,4,1,2,5)
print('Resenje je x = ', xres, 'i y = ', yres)

Resenje je x = 1.3 i y = -0.2 U ovom primeru koristili smo skraćenicu za pridruživanje, o čemu je bilo reči u nekom ranijem poglavlju.

Primer 4

Naredba return se može koristiti i za prevremeni završetak funkcije.

def multiple_print(string, n, bad_words):
    if string in bad_words:
        return
    print(string * n)
    print()

Isti efekat se može postići i sa if/else naredbom, ali u nekim slučajevima return naredba će učiniti vaš kod jednostavnijim i čitljivijim.

Podrazumevajući (default) i argumenti sa ključnim rečima (keyword)

Možete zadati podrazumevajuću vrednost za neki argument funkcije. Takva vrednost je opciona, pa ako u pozivu funkcije pozivaoc ne navede neku drugu vrednost za taj argument, u kodu funkcije će se koristiti podrazumevajuća vrednost. Evo primera:

def multiple_print(string, n=1)
    print(string * n)
    print()

multiple_print('Hello', 5)
multiple_print('Hello')

Rezultat:

HelloHelloHelloHelloHello Hello

Podrazumevajući argumenti se moraju nalaziti na kraju u definiciji funkcije, dakle posle svih ne-podrazumevajućih argumenata.

Ključne reči

Sličan koncept imammo i sa takozvanim ključnim (keyword) argumentima funkcije. Recimo da imamo sledeću definiciju funkcije:

def fancy_print(text, color, background, style, justify):

Svaki put kad pozivamo ovu funkciju, potrebno je da znamo korektan redosled argumenata. Srećom Python omogućava da argumente imenujemo pri pozivu funkcije kao što pokazuju sledeći primeri:

fancy_print(text='Hi', color='yellow', background='black',
            style='bold', justify='left')

fancy_print(text='Hi', style='bold', justify='left',
            background='black', color='yellow')

Kao što vidimo, redosled argumenata sada nije važan pošto koristimo ključne reči (nazive argumenata).

Kada definišemo funkciju, dobra je ideja da zadajemo podrazumevajuće vrednosti argumenat. Na primer u većini slučajeva pozivaoc funkcije želi levo pozicioniranje teksta, belu pozadinz, itd. Korišćenjem ovih vrednosti kao podrazumevajućih znači da pozivaoc ne mora da navodi svaki argument kad god poziva funkciju. Evo jednog primera:

def fancy_print(text, color='black', background='white',
                style='normal', justify='left'):
    # ovde dolazi kod same funkcije

fancy_print('Hi', style='bold')
fancy_print('Hi', color='yellow', background='black')
fancy_print('Hi')

Napomena

U stavri, mi smo podrazumevajuće i argumente sa ključnim rečima već videli – to su sep, end i file argumenti u print funkciji.

Lokalne varijable

Recimo da imamo dve funkcije, kao ove prikazane naniže, i da obe funkcije koriste varijablu i:

def func1():
    for i in range(10):
        print(i)

def func2():
    i=100
    func1()
    print(i)

Problem koji bi mogao da nastane ovde je kada pozovemo funkciju func1, možemo pomešati vrednost varijable i sa onom iz funkcije func2. U velikim programima bila bi noćna mora ako bi morali da vodimo računa da li smo naziv neke varijable ponovo upotrebili u različitim funkcijama. Na sreću, u Pythonu o tome ne moramo da brinemo. Kada je varijabla definisana unutar neke funkcije, ona postaje lokalna varijabla, što znači da ona ne postoji van te funkcije. Na taj način svaka funkcija može da definiše svoje varijable i da ne brine da li se isti nazivi varijabli koriste u nekim drugim funkcijama.

Globalne varijable

S druge starne, ponekad želimo da se ista varijabla koristi u više funkcija. Takva varijabla se zove globalna varijabla. Morate biti pažljivi pri korišćenju globalnih varijabli, posebno u velikim programima, ali manji broj globalnih varijabli u manjim programima može biti ponekad pogodan način za pisanje kraćih i čitljivijih programa. Evo jednog kratkog primera:

def reset():
    global time_left
    time_left = 0

def print_time():
    print(time_left)

time_left=30

U ovom primeru imamo varijablu time_left za koju želimo da se može koristiti u više funkcija. Ako funkcija želi da menja vrednost te varijable, onda u toj funkciji moramo navesti da je time_left globalna varijablae. Za to koristimo naredbu global. S druge strane ako želimo samo da koristimo globalnu varijablu (ali da ne menjamo njenu vrednost) tada nam nije potrebna naredba global.

Funkcije generatori

Generatori su funkcije koje vam omogućavaju da generišete vrednosti za for petlju.

Evo jednog jednostavnog primera:

def generator():
    for i in range(10000000000):
        yield i

for item in generator():
    print(item)
    if item > 19:
        break

U ovom primeru funkcija generator umesto da vraća jednu vrednost naredbom return, pri svakom pozivu naredbom yield daje sledecu vrednost. Funkcija nekako pamti gde je stala u prethodnom pozivu pa tu nastavlja u sledecem pozivu. Ova mogućnost može značajno da štedi memoriju jer funkcija ne vraća sve generisane vrednosti već jednu po jednu sve dok je potrebno.

Evo sada primera u kojem pravimo našu verziju dobro poznate range() funkcije:

def my_range(start, stop, step = 1):
    i = start
    while i < stop:
        yield i
        i += step

for b in my_range(14,24,3):
    print(b)

Vežbe

13.1 Napišite funkciju pod nazivom pravougaonik koja prihvata dva cela broja m i n kao argumente i štampa m × n boks koji se sastoji od zvezdica. Dole je prikazan izlaz funkcije pravougaonik(2,4)

****
****

13.2 Napišite funkciju pod nazivom dodaj_usklicnik koja prihvata listu stringova i dodaje znak uzvika (!) na kraj svakog od stringova iz liste. Program treba da modifikuje originalnu listu i ne vraća ništa.

13.3 Napišite istu funkciju ali da ona ne modifikuje originalnu listu već da vraća novu listu.

13.4 Napišite funkciju suma_cifara koja prihvata jedan ceo broj num i vraća sumu njegovih cifara.

13.5 Digitalni koren nekog broja n se dobija na sledeći način: Saberemo cifre broja n da dobijemo novi broj. Saberimo cifre tog broja da dobijemo novi broj. Nastavljamo ovaj proces sve dok broj dobijen sabiranjem cifara ne bude jednocifren. Taj broj je digitalni koren. Na primer, ako je n=45893, posle sabiranja njegovih cifara imamo 4+5+8+9+3 = 29. Saberemo cifre broja 29 pa dobijemo 2+9=11. Sada saberemo cifre broja 11i dobijemo 1+1=2. Pošto je 2 jednocifren, on je digitalni koren broja 45893. Napišite funkciju koja vraća digitalni koren celog broja n.

13.6 Napišite funkciju prva_razlika koja prihvata dva stringa i vraćat prvu poziciju na kojoj se stringovi razlikuju. Ako su stringovi identični funkcija vraća -1.

13.7 Napišite funkciju binom koja prihvata dva cela broja n i k i vraća binomijalni koeficijent n C k. Definicija: n C k = n!/(k!(n-k)!).

13.8 Napišite funkciju koja prihvata ceo broj n i vraća slučajan ceo broj sa tačno n cifara. Na primer ako je n jednako 3,tada bi 125 i 593 bili validne vrednosti za vraćanje iz funkcije, ali bi 093 bilo neispravno jer je to u stvari broj 93, koji je dvocifren.

13.9 Napišite funkciju broj_faktora koja prihvata ceo broj i vraća koliko faktora (delioca) ima taj broj.

13.10 Napišite funkciju faktori koja prihvata ceo broj i vraća listu njegovih faktora.

13.11 Napišite funkciju najblizi koja prihvata listu brojeva L i broj n i vraća najveći element iz L koji nije veći od n. Na primer ako je L=[1,6,3,9,11] a n=8, tada funkcija treba da vrati 6, zato što je 6 najbliža vrednost broju 8 u L,a koja nije veća od 8.

13.12 Napišite funkciju poklapanje koja prihvata dva stringa i vraća koliko ima poklapanja između dva stringa. Poklapanje je slučaj kada stringovi imaju isto slovo na istoj poziciji. Na primer, ‘python’ i ‘path’ se poklapaju na prvom, trećem i četvrtom slovu, pa funkcija traba da vrati 3.

13.13 Setimo se da ako je s neki string tada s.find(‘a’) pronalazi poziciju (indeks) prvog slova a u s. Problem je što ona ne pronalazi sve pozicije slova a. Napišite program findall koji za dati string i za dato slovo, vraća listu koja sadrži sve pozicije na kojima se nalazi to slovo u stringu. Funkcija treba da vrati praznu listu ako se slovo ne nalazi u stringu.

13.14 Napišite funkciju promeni_velicinu koja za dati string vraća string u kojem su sva velika slova zamenjena malim i obratno.

13.15 Napišite funkciju is_sorted koja za datu listu vraća True ako je lista sortirana, a False u suprotnom slučaju.

13.16 Napišite funkciju root koja za dati broj x i ceo broj n vraća x 1/n. Pri definiciji funkcije postavite podrazumevajuću (default) vrednost za n da bude 2.

13.17 Napišite funkciju one_away koja prihvata dva stringa i vraća True ako su stringovi iste dužine i razlikuju se samo u jednom slovu, kao na primer bike/hike ili water/wafer.

13.18 Napišite funkciju primes koja za dati broj n vraća listu prvih n prostih brojeva. Neka podrazumevajuća vrednost za n bude 100.

  • Modifikujte gornju funkciju tako da ima i jedan opcioni argument pod nazivom start koji omogućava da lista startuje sa vrednosću većom od 2.Funkacija treba da vrati listu prvih n prostih brojeva koji su veći ili jednaki vrednosti varijable start. Podrazumevajuća vrednost za start treba da bude 2.

13.19 Napišite funkciju koja za dati ceo broj, vraća naziv toga broja na englsekom (srpskom) jeziku. Na primer, za broj 123456 kao argument funkcija treba da vrati „ one hundred twenty-three thousand, four hundred fifty-six“.

13.20 Napišite funkciju merge koja prihvata dve sortirane liste (istih ili različitih dužina), i spaja (merdžuje) ih u jednu sortiranu listu.

  • Uradite isto korišćenjem sort metode.
  • Uradite ovo bez korišćenja sort metode.

13.21 U jednom od prethodnih poglavlja smo za proveru da li se neka reč nalazi u listi reči koristili naredbu

if rec in lista_reci:

Ovo je nažalost veoma sporo, ali postoji brži način koji se zove binarno pretraživanje (binary search). Da implementiramo binarno pretraživanje u nekoj funkciji, počinjemo sa poređenjem varijable rec sa rečju iz sredine liste lista_reci. Ako su iste završili smo traženje i možemo da vratimo True. S druge strane ako rec dolazi pre reči iz sredine, onda traženje treba da nastavimo u prvoj polovini liste. Ako rec dolazi posle sredine, tada traženje nastavljamo u drugoj polovini liste. Ponavljamo ovaj proces sve dok ili ne pronađemo traženu reč ili nemamo više gde da tražimo ,u kom slučaju vraćamo False.

13.22 Tik-tak-tu (Tic-tac-toe), ili kako se to kod nas zove Iks-Oks, tabla može biti predstavljena jednom 3 × 3 dvodimenzionom listom, sa nulama za prazna polja, i X i O za popunjena polja.

  • Napišite funkciju koja prihvata Iks-Oks listu i na slučajno odabranu poziciju (koja mora biti prazna) postavlja O.
  • Napišite funkciju koja prihvata Iks-Oks listu i proverava da li je neko ostavrio pobedu. Funkcija vraća True ako postoji pobednik, u suptoenom vraća False.

13.23 Napišite funkciju koja prihvata 9 × 9 potencijalno rešeni Sudoku i vraća True ako je rešenje korektno, a False ako ima grešku. Sudoku je kortektno rešen ako nema ponovljenih brojeva ni u jednom redu ili koloni, kao ni u jednom od devet “blokova.”