Funktio on yleensä kokonaisuus, joka suorittaa yhtä toimintoa tai vastaa vastaa yhdestä ohjelman tehtävästä.

Kun funktio on kiinni oliossa, kutsutaan sitä metodiksi. Metodeita käsitellään osassa Luokka.

Funktion luominen muokkaa

Funktio luodaan def avainsanalla.

Esimerkki yksinkertaisesta funktiosta

def hello():
    print("Hei")

# kutsutaan hello() funktiota
hello()

Tuloste

Hei

Parametrit muokkaa

Funktiolla voi olla parametreja, joita sille annetaan.

Esimerkki funktiosta, jolle annetaan parametrina name-muuttuja.

def hello(name):
    print("Hei " + name)
 

name = "Peikko"
hello(name)

name = "Matti"
hello(name)

Tuloste

Hei Peikko
Hei Matti

Funktion parametrille voi antaa oletusarvon, jota käytetään, jos mitään arvo ei anneta.

def hello(name="Keke"):
    print("Hei " + name)
 

name = "Peikko"
hello(name)

hello()

Tuloste

Hei Peikko
Hei Keke

Funktiota kutsuttaessa voidaan parametrit antaa myös nimellä. Jos argumentit annetaan parametrin nimellä, pitää mahdolliset nimettömät argumentit antaa ensin.

hello(name="Peikko")

Tuloste

Hei Peikko

Usean arvon palauttaminen muokkaa

Funktiosta voi palauttaa useita arvoja luettelemalla ne pilkulla erotettuna.

def jaa(jaettava, jakaja):
    return jaettava // jakaja, jaettava % jakaja

Paluuarvo on silloin itse asiassa monikko (tuple). Funktion kutsusta paluuarvon voi lukea yhtenä monikkona tai erillisinä arvoina.

>>> tulos = jaa(5, 2)
>>> tulos
(2, 1)
>>> osamäärä, jakojäännös = jaa(5, 2)
>>> osamäärä
2
>>> jakojäännös
1

Paikalliset funktiot muokkaa

Funktiota ei tarvitse määritellä tiedoston ylimmällä tasolla, vaan sen voi määritellä myös toisen funktion sisällä.

def lajittele(lista):
    """Lajittelee annetut sanat päätteen mukaan.
    """
    def apu(sana):
        return "".join(reversed(list(sana)))
    return sorted(lista, key=apu)

print(lajittele(["kana", "lakana", "vakava", "takana", "pakana", "sakara", "pakara", "hana"]))

Tuloste

['hana', 'kana', 'lakana', 'pakana', 'takana', 'pakara', 'sakara', 'vakava']

Yllä funktio apu annettiin parametrina sorted-funktiolle. Funktioviittauksen voi tällä tavalla antaa argumenttina, tallentaa muuttujaan tai palauttaa funktiosta. Funktiota voi kutsua muuttujan kautta samalla tavalla kuin sen varsinaisella nimelläkin.

>>> lajittelu = lajittele
>>> lajittelu(["muusi", "musti", "uusi", "bluussi"])
['bluussi', 'uusi', 'muusi', 'musti']

Paikallisen funktion voi myös palauttaa funktiosta. Paikallisella funktiolla on pääsy kaikkiin isäntäfunktion paikallisiin muuttujiin ja parametriarvoihin myös palauttamisen jälkeen.

def tee_lisääjä(lisättävä):
    def kääre(luku):
        return luku + lisättävä
    return kääre

lisää_yksi = tee_lisääjä(1)

print(lisää_yksi(2))

Tulostaa

3

Tyyppivihjeet muokkaa

Funktion parametrien ja paluuarvon tyypin voi merkitä tyyppivihjeillä. Tyyppivihjeet ovat vain ohjelmoijalle tarkoitettuja. Python ei tarkista niitä mitenkään. Eräissä sovelluskehitysympäristöissä on kuitenkin automaattinen tarkistus.

Parametrin tyyppi kirjoitetaan kaksoispisteen jälkeen. Funktion palautusarvo merkitään ennen funktion rungon avaavaa kaksoispistettä nuolen (->) jälkeen.

def tee_tunnus(nimi: str, numero: int) -> str:
    return f'{nimi} ({numero})'

Taulukot merkitään kirjoittamalla taulukon alkioiden tyyppi hakasulkujen [] sisään.

def lajittele(luvut: [int]) -> [int]:
    pass

Lambdat muokkaa

Yhden rivin mittaisia nimettömiä funktioita voi tehdä lambda-avainsanalla. Lambda-sanan jälkeen luetellaan parametrit ilman sulkuja. Kaksoispisteen jälkeen tulee yhden lauseen mittainen lambdan runko. Lambdoja käytetään lähinnä, kun annetaan toiselle funktiolle parametrina funktio, josta se kutsuu. Tätä käsitellään enemmän funktionaalista ohjelmointia käsittelevässä luvussa.

tiedot = [
    { 'nimi': 'Hanski', 'ikä': 33 },
    { 'nimi': 'Väiski', 'ikä': 24 },
    { 'nimi': 'Hiski', 'ikä': 45 },
]
>>> iät = map(lambda x: x['ikä'], tiedot)
>>> list(iät)
[33, 24, 45]

Vaihteleva määrä parametreja muokkaa

Joskus on hyödyllistä tehdä funktio, jota voi kutsua vaihtelevalla määrällä argumentteja. Esimerkiksi Pythonin sisäänrakennetuille funktioille print, min ja max voi antaa miten monta arvoa tahansa.

Kun funktion määrittelyssä merkitään parametrin eteen asteriski (*), kokoaa parametri kaikki loput funktiolle annetut argumentit yhteen muuttujaan, joka on tyypiltään monikko (tuple).

>>> def f(*args):
...     print(args)
... 
>>> f(1, 2, 3, 4)
(1, 2, 3, 4)

Esimerkki: annettujen lukujen keskiarvon laskeva funktio.

def keskiarvo(*luvut):
    tulos = 0
    for luku in luvut:
        tulos += luku
    return tulos / len(luvut)
>>> keskiarvo(1, 2, 3, 4, 5, 6, 7, 8)
4.5

Asteriskilla merkityn parametrin lisäksi voi sitä ennen olla muita tavallisia parametreja.

def yhdistä_luetteloksi(pre, suf, *arvot):
    tulos = []
    for arvo in arvot:
        tulos.append(pre + arvo + suf)
    return ", ".join(tulos)
>>> yhdistä_luetteloksi("[[", "]]", "a", "b", "c")
'[[a]], [[b]], [[c]]'

Myös nimetyille argumenteille on mahdollista käyttää ne kokoavaa parametria. Tätä merkitään kahdella asteriskilla. Funktion sisällä tällainen nimetyt argumentit kokoava parametri on tyypiltään dict eli sanakirja. Myös ** kokoaa loput nimetyt argumentit, sitä ennen parametriluettelossa voi olla muita parametreja, joita ei koota yhteen.

def muotoile_tiedot(**tiedot):
    tulos = []
    for k, v in tiedot.items():
        tulos.append(f"{k + ':': <10} {v}")
    return "\n".join(tulos)
>>> print(muotoile_tiedot(Nimi="Korkki Korhonen", Ikä=30, Ammatti="sellisti"))
Nimi:      Korkki Korhonen
Ikä:       30
Ammatti:   sellisti

Jos käytetään molempia kokoavia muotoja, on parametrien järjestys seuraava:

[nimetön 1], ... [nimetön n], [*nimettömät kokoava], [oletusarvollinen 1], ... [oletusarvollinen n], [**nimetyt kokoava]

tai

[nimetön 1], ... [nimetön n], [oletusarvollinen 1], ... [oletusarvollinen n], [*nimettömät kokoava], [**nimetyt kokoava]

Listan tai monikon muuttaminen funktion argumenteiksi muokkaa

Operaattoreita *- ja ** voi paitsi käyttää funktion argumenttien kokoamiseen, myös muuttamaan lista, monikko tai sanakirja argumenteiksi funktiota kutsuttaessa.

Operaattorilla * voi muuttaa listan, monikon tai muun sekvenssityypin sisällön funktion argumenteiksi.

>>> keskiarvo(*[1, 2, 3, 4, 5, 6, 7, 8])
4.5

Operaattorilla ** voi muuttaa sanakirjan funktion nimetyiksi argumenteiksi.

>>> tiedot = { "Nimi": "Korkki Korhonen", "Ikä": 30, "Ammatti": "sellisti" }
>>> print(muotoile_tiedot(**tiedot))
Nimi:      Korkki Korhonen
Ikä:       30
Ammatti:   sellisti
>>> lista = [1, 2, 3, 4, 5, 6]
>>> print(*lista)
1 2 3 4 5 6

Funktiossa ei tarvitse olla *-parametria tai **-parametria, vaan argumenteiksi muuttaminen toimii minkä tahansa funktion kanssa, mutta silloin pitää olla tarkkana, että arvoja on oikea määrä tai niillä on oikeat nimet.

def ynnää(luku1, luku2):
    return luku1 + luku2
>>> arvot = (5, 6)
>>> ynnää(*arvot)
11
>>> arvot = { 'luku1': 7, 'luku2': 8 }
>>> ynnää(**arvot)
15

Funktion kaikki parametrit voi siten siepata käyttämällä sekä *-parametria että **-parametria. Siepatut parametrit voi välittää toiselle funktiolle *- ja **-operaattoreilla.

def f(*args, **kwargs):
    return g(*args, **kwargs)

Dekoraattorit muokkaa

Olemassa olevan funktion toimintaa voi muuttaa toisen funktion avulla. Tällaista muuttavaa funktiota kutsutaan dekoraattoriksi.

Dekoraattori on funktio, joka ottaa parametrikseen funktion, ja palauttaa uuden funktion, joka kutsuu varsinaista funktiota. Tässä välissä dekoraattori voi tehdä muita toimintoja. Alkuperäinen funktio siis ikäänkuin kääritään toiseen funktioon. Kun kääreelle annetaan sama nimi kuin alkuperäiselle funktiolle, kutsutaan alkuperäisen sijasta aina tätä käärefunktiota. Tarkalleen ottaen dekoraattorin ei tarvise olla funktio, vaan se voi olla mikä tahansa kutsuttavissa oleva (callable) olio.

Alla olevassa esimerkissä dekoraattori logitus tulostaa funktion parametrit ennen funktion kutsua ja paluuarvon funktion kutsumisen jälkeen. Kääre on funktio joka korvaa alkuperäisen hae_tervehdys -funktion. (Tässä on käytetty *args- ja **kwargs-parametreja, jotta dekoraattori toimii kaikilla funktioilla. Yhtä hyvin voisi käyttää tavallisia parametreja.)

def logitettu(funktio):
    def kääre(*args, **kwargs):
        print(f"Kutsutaan funktiota {funktio.__name__}; parametrit", args, kwargs)
        ret = funktio(*args, **kwargs)
        print(f"Kutsuttiin funktiota {funktio.__name__}; tulos", ret)
        return ret
    return kääre

def ynnää(luku1, luku2):
    return luku1 + luku2

ynnää = logitettu(ynnää)
print(ynnää(2, 3)) # Tässä kutsutaan käärefunktiota, joka on nyt alkuperäisen funktion nimellä

Tulostaa

Kutsutaan funktiota ynnää; parametrit (2, 3) {}
Kutsuttiin funktiota ynnää; tulos 5
5

Funktion voi kääriä dekoraattoriin määrittelyn yhteydessä erityisellä @-syntaksilla. Esimerkiksi yllä voitaisiin rivin

hae_tervehdys = logitus(hae_tervehdys)

sijaan käyttää funktion hae_tervehdys määrittelyssä merkintää

@logitettu
def ynnää(luku1, luku2):
    return luku1 + luku2

Dekoraattori parametreilla muokkaa

Dekoraattorin voi muodostaa myös funktiolla annettujen parametrien mukaiseksi. Dekoraattorin tilalle @-lausekkeeseen laitetaan tilalle funktiokutsu, joka palauttaa dekoraattorin (joka palauttaa käärefunktion). Havainnollistetaan asiaa tekemällä dekoraattorin, joka lisää lainausmerkit kohdefunktion palauttaman arvon ympärille. Halutut lainausmerkit voi antaa tapauskohtaisesti. Aloitamme tekemällä kuitenkin samanlaisen yksinkertaisen dekoraattorin kuin aiemmin.

def siteerattu(funktio):
    alkumerkki = '”'
    loppumerkki = '”'
    def kääre(*args, **kwargs):
        return alkumerkki + funktio(*args, **kwargs) + alkumerkki
    return kääre


@siteerattu
def hae_tervehdys(nimi):
    return f'Terve {nimi}!'

print(hae_tervehdys("Jykä"))

Tulostaa

”Terve Jykä!”

Seuraavaksi lisäämme edellisen siteerattu-funktion ympärille funktion, joka palauttaa sen. Funktio siteerattu käyttää tee_siteerattu-funktiolle annettuja argumentteja omassa koodissaan.

def tee_siteerattu(alkumerkki, loppumerkki):
    def siteerattu(funktio):
        def kääre(*args, **kwargs):
            return alkumerkki + funktio(*args, **kwargs) + loppumerkki
        return kääre
    return siteerattu


@tee_siteerattu('«', '»')
def hae_tervehdys(nimi):
    return f'Terve {nimi}!'

print(hae_tervehdys("Jykä"))

Tulostaa

«Terve Jykä!»

Dekoraattoreita voi myös pinota useita päällekkäin.

Pythonissa on olemassa joitakin valmita dekoraattoreita. Esimerkiksi olion gettereiden ja setteriden luomiseen käytetyt @property ja @x.setter sekä @staticmethod. Näitä käsitellään olio-ohjelmoinnin yhteydessä. Mitä tahansa funktiota, joka ottaa funktion parametrikseen voi käyttää dekoraattorina.

Aiheesta muualla muokkaa