Kako definiramo funkcijo
Funkcije
Funkcije smo si doslej predstavljali kot škatlice: nekaj gre noter
(temu smo in bomo rekli argument), nekaj pride ven (temu se reče
rezultat funkcije), vmes pa se lahko še kaj opaznega dogaja, recimo
izpisuje. Primer funkcije, ki je počela vse to, je input
: kot
argument smo ji povedali, kaj naj vpraša uporabnika; kot rezultat je vrnila,
kar je vtipkal uporabnik; vmes se je zgodilo to, da je funkcija nekaj vprašala
uporabnika in počakala, da je le-ta odgovoril. Druga funkcija, ki smo jo
srečali, je bila sqrt
, ki dobi kot argument neko število in vrne
njegov koren. Vmes se ne dogaja nič opaznega, funkcija le "neopazno" naredi,
kar mora narediti.
S tem, kako delujejo funkcije in kako kaj naredijo, se doslej nismo ukvarjali. Te stvari so za nas napisali drugi (hvala, hvala) in mi jih lahko uporabljamo, ne da bi nas vznemirjalo vprašanje, kako so napisane. S tem, kako so napisane funkcije, ki so jih naredili drugi, se tudi v prihodnje ne bomo ukvarjali. Pač pa se bomo danes naučili pisati svoje.
Popolna števila
Število je popolno, če je enako vsoti svojih deliteljev. 28 je deljivo z 1, 2, 4, 7 in 14 ter je popolno, saj je 1+2+4+7+14 ravno 28. Napišimo program, ki sestavi seznam vseh popolnih števil do 1000.
Tokrat se dela ne bomo lotili tako, kot smo se ga ponavadi, temveč se bomo ob tem primeru naučili pisati funkcije.
Delitelji števila
Znamo napisati program, ki sestavi seznam vseh deliteljev nekega števila n?
Ne čisto, ker smo sezname doslej vedno sestavili ročno, tako da smo
napisali, recimo, s = [5, 1, 6, 7, 2]
. Seznamov nikoli ni naredil
program sam. To se naučimo kar mimogrede: če imamo nek seznam s
in
bi radi vanj dodali število 42
, napišemo
s.append(42)
. Zdaj pa bomo menda znali:
Najprej naredimo prazen seznam, nato gremo prek vseh števil od 1 do n in
če število deli n
, ga dodamo v s
.
Kaj ne bi bilo lepo, če bi imel Python kar funkcijo delitelji
,
ki bi jo lahko uporabili? Potem bi lahko napisali kar
Kot je povsem pravilno predlagal profesor Franc Oblak: česar ni, se pa nardi (ter v sredo polinoma, ki se ga na noben način ni dalo razcepiti, dodal + x - x in polinom je šel na faktorje kot toplo maslo). Napišimo si takšno funkcijo, da jo bomo lahko klicali.
Definicijo funkcije začnemo z def
; to je rezervirana beseda, ki
pomeni, da to, kar sledi, ni "program, ki ga je treba takoj izvesti", temveč
funkcija. Z drugimi besedami, def delitelji
pomeni: "kadar bo
kdo poklical funkcijo delitelji
, naredi naslednje:".
Imenu sledijo oklepaji, v katerih navedemo imena argumentov funkcije. V našem primeru bo funkcija zahtevala en argument. Torej, ta, ki bo poklical funkcijo, bo moral v oklepaje napisati eno reč (upamo, da bo napisal število, sicer pa naj si sam pripiše posledice).
Tista reč, ki jo bomo ob klicu funkcije podali kot argument, se bo znotraj
funkcije pojavila kot spremenljivka z imenom n
. Takšno ime smo
namreč uporabili v prvi vrstici, v "glavi" funkcije. Vrednosti ji ne bomo
priredili: ko bo nekdo poklical funkcijo, bo Python tej spremenljivki kar sam
od sebe priredil vrednost, ki jo bo "klicatelj" napisal kot argument funkcije.
Če torej nekdo pokliče
n
vrednost 35 in če pokliče
n
vrednost 13. n
ima vrednost argumenta.
Za def delitelji(n)
sledi dvopičje in zamik. Vse, kar sledi
takole zamaknjeno, je koda funkcije. Kaj mora narediti le-ta? No, tisto, kar
pač dela funkcija: sestaviti seznam deliteljev n
. To pa ne le
znamo, temveč smo celo ravno prejle naredili in lahko le skopiramo.
Na koncu (ali tudi že kje vmes - bomo že videli primer) funkcija pove, kaj
naj klicatelj dobi kot rezultat. To stori s stavkom return s
.
Geometrija
Napišimo funkcijo, ki dobi kot argument dolžine stranic trikotnika in vrne
njegovo ploščino. Ta funkcija bo imela tri argumente; poimenujmo jih
a
, b
in c
.
Ko smo pri tem, napišimo še funkcijo funkcijo za obseg trikotnika ter za obseg in ploščino kroga.
Vsota števil v seznamu
Zdaj napišimo drugo funkcijo: funkcijo, ki dobi seznam števil in izračuna njihovo vsoto.
Funkcija ima spet en argument, tokrat smo ga poimenovali s
.
Ta argument bo seznam števil, ki jih je potrebno sešteti. Funkcija gre - z
zanko for
- prek tega seznama in sešteva, kot smo počeli že
včeraj v trgovini. Na koncu rezultata ne izpiše (print
), kot smo
delali doslej, temveč ga vrne (return
).
(Mimogrede povejmo še, da nam funkcije vsota
ne bi bilo
potrebno napisati, saj obstaja: imenuje se sum
.)
Popolno število
Vrnimo se k popolnim številom. Rekli smo, da je število popolno, če je enako vsoti svojih deliteljev. Lahko bi torej rekli
vendar ne bomo. Napisali bomo funkcijo, ki vrne True
, če je
število popolno in False
, če ni.
Pazite, tudi tule nismo pisali
Lahko bi, vendar bi bilo smešno. Pač pa lahko funkcijo še skrajšamo (in navadno bi jo tudi res), takole
Končno ostane še program, ki bo z uporabo gornje funkcije sestavil seznam
vseh popolnih števil manjših od 1000.
V njem z zanko for
preštejemo do 1000, za vsako število posebej
preverimo, ali je popolno in če je, ga dodamo na seznam.
Klici funkcij
Najprej zberimo vse skupaj:
Kako se izvaja tako napisan program? Malo drugače, kot smo vajeni. Začetek
programa - vse do mesta s = []
, so definicije funkcij. Python tega
dela programa ne izvede, le zapomni si funkciji, da ju bo kasneje lahko
poklical. Stvari se začnejo zares dogajati šele, pri s = []
. Ko
program pride do klica funkcije popolno
, skoči v to funkcijo --
vendar si zapomni, odkod je skočil, tako da se bo kasneje lahko vrnil na to
mesto.
Prav. Zdaj smo v funkciji popolno
in n
je neka
številka (najprej 1, naslednjič bo 2 in tako naprej). Že takoj, v prvi
vrstici skoči izvajanje v funkcijo delitelji
. Ta sestavi seznam
deliteljev in ga vrne - tistemu, ki jo je poklical, funkciji
popolno
. Nato se nadaljuje izvajanje funkcije popolno: ta v
naslednji vrsti pokliče funkcijo vsota
. Funkcija
vsota
izračuna in vrne vsoto. Spet smo v funkciji
popolno
, ki izračuna vrednost izraza v == n
;
vrednost izraza je True
ali False
. Funkcija
popolno
ga vrne tistemu, ki jo je klical, se pravi oni zanki
na koncu skripte. Če je rezultat True
, se bo število izpisalo,
sicer pač ne.
Rezultat sredi funkcije
Napišimo funkcijo, ki pove, ali je dano število praštevilo. Vrnila bo
True
(je) ali False
(ni).
Prvi return
je znotraj stavka if
. Če odkrijemo,
da kakšno število med 2 in n-1 deli n (se pravi, če je ostanek po deljenju
n
z i
enak 0), dano število ni praštevilo in vrnemo
False
. S tem se izvajanje funkcije prekine, funkcija vrne
rezultat in konec. Nobenega break
ali česa podobnega ne
potrebujemo. return
vedno konča izvajanje funkcije. Do drugega
return
a tako pridemo le, če se ni izvedel prvi
return
. To pa seveda pomeni, da ni bilo nobenega števila, ki bi
delilo dano število n
.