Kirjoittaja: Antti Laaksonen (2009).
⚠ Huomio! Tämä opas on vanhentunut. Oppaan sisältöön ei voi enää luottaa. Opas on säilytetty vain sen historiallisen arvon vuoksi. ⚠
Opassarjan kuluessa on tutustuttu moneen hyödylliseen funktioon. Esimerkiksi funktio str
muuttaa arvon merkkijonoksi, funktio range
muodostaa lukuja sisältävän listan, funktio len
laskee merkkijonon merkkien määrän ja funktio min
etsii listan pienimmän luvun.
Tämän oppaan aiheena on omien funktioiden laatiminen. Funktiot selventävät koodin rakennetta, koska niiden avulla eri puolilla ohjelmaa tarvittava samanlainen koodi täytyy kirjoittaa vain kerran. Lisäksi hyvin suunniteltuja funktioita voi käyttää uudestaan tulevissa ohjelmissa.
Oppaan ensimmäinen funktio tulostaa tekstin laatikon sisään. Seuraavaksi nähdään, mitä hyötyä funktiosta on tässä tapauksessa.
Seuraava ohjelma tulostaa tekstin laatikkoon:
# -*- coding: latin-1 -*- print "*" * 15 print "*", "Tervetuloa!", "*" print "*" * 15
Ohjelman tulostus on seuraava:
*************** * Tervetuloa! * ***************
Tässä "*" * 15
on lyhennysmerkintä, joka tarkoittaa 15 tähtimerkkiä. Vastaavasti "abc" * 4
olisi merkkijono "abcabcabcabc"
.
Samalla tavalla voi toteuttaa ohjelman, jossa kaikki tekstit ovat laatikoissa:
# -*- coding: latin-1 -*- print "*" * 15 print "*", "Tervetuloa!", "*" print "*" * 15 print "*" * 20 print "*", "Anna tunnussana:", "*" print "*" * 20 sana = raw_input() if sana == "python": print "*" * 11 print "*", "Oikein!", "*" print "*" * 11 else: print "*" * 11 print "*", "Väärin!", "*" print "*" * 11
Ohjelman tulostus voi olla seuraava:
*************** * Tervetuloa! * *************** ******************** * Anna tunnussana: * ******************** python *********** * Oikein! * ***********
Ohjelma toimii kyllä halutulla tavalla, mutta sen koodissa on turhaa toistoa, koska laatikon tulostavat komennot on kopioitu moneen kohtaan. Seuraavaksi nähdään, kuinka koodin rakennetta voi parantaa funktion avulla.
Seuraavassa ohjelmassa on funktio laatikko
, joka tulostaa halutun tekstin laatikkoon. Ohjelman toiminta vastaa edellistä ohjelmaa, mutta koodin rakenne on huomattavasti selkeämpi.
# -*- coding: latin-1 -*- def laatikko(teksti): print "*" * (len(teksti) + 4) print "*", teksti, "*" print "*" * (len(teksti) + 4) laatikko("Tervetuloa!") laatikko("Anna tunnussana:") sana = raw_input() if sana == "python": laatikko("Oikein!") else: laatikko("Väärin!")
Funktion alussa on sana def
, jonka jälkeen tulee funktion nimi laatikko
. Sitten suluissa ovat funktion parametrit. Tässä funktiolla on yksi parametri teksti
, joka tarkoittaa tekstiä, joka funktion täytyy tulostaa laatikkoon.
Funktio laatikko
yleistää tekstin tulostuksen laatikkoon. Funktiolle voi antaa parametrina minkä tahansa tekstin ja funktio osaa tulostaa sen ympärille oikean määrän tähtimerkkejä. Merkintä "*" * (len(teksti) + 4)
tarkoittaa, että tähtimerkkejä on neljä enemmän kuin tekstin pituus.
Seuraavassa ohjelmassa myös laatikon reunamerkki on funktion parametri:
# -*- coding: latin-1 -*- def laatikko(teksti, reuna): print reuna * (len(teksti) + 4) print reuna, teksti, reuna print reuna * (len(teksti) + 4) laatikko("Tervetuloa!", "*") laatikko("Anna tunnussana:", "?") sana = raw_input() if sana == "python": laatikko("Oikein!", "!") else: laatikko("Väärin!", "!")
Ohjelman tulostus voi olla seuraava:
*************** * Tervetuloa! * *************** ???????????????????? ? Anna tunnussana: ? ???????????????????? python !!!!!!!!!!! ! Oikein! ! !!!!!!!!!!!
Nyt funktiolla on kaksi parametria: parametri teksti
on tulostettava teksti ja parametri reuna
on merkki, jolla teksti täytyy ympäröidä.
Funktio palauttaa usein arvon ohjelman kohtaan, jossa funktiota kutsutaan. Näin toimii esimerkiksi funktio len
, joka palauttaa sille annetun merkkijonon pituuden. Funktiossa komento return
poistuu funktiosta ja palauttaa arvon.
Seuraavassa ohjelmassa on funktio kaanna
, joka kääntää merkkijonon toisinpäin. Ohjelma kysyy käyttäjältä sanoja ja kääntää niitä toisinpäin.
# -*- coding: latin-1 -*- def kaanna(mjono): uusi = "" for merkki in mjono: uusi = merkki + uusi return uusi while True: sana = raw_input("Anna sana: ") if sana == "": break print "Toisinpäin: " + kaanna(sana)
Ohjelman tulostus voi olla seuraava:
Anna sana: kirja Toisinpäin: ajrik Anna sana: valinta Toisinpäin: atnilav Anna sana: puro Toisinpäin: orup Anna sana:
Ohjelma kutsuu silmukassa funktiota kaanna
parametrina käännettävä sana. Funktio muodostaa käännetyn sanan ja palauttaa sen komennolla return
. Sitten käännetty sana liittyy tulostettavan merkkijonon osaksi.
Funktion kaanna
avulla voi myös tarkistaa, onko sana palindromi eli onko se sama alusta loppuun ja lopusta alkuun luettuna. Tehdään sitä varten uusi funktio palindromi
:
def palindromi(sana): return sana == kaanna(sana)
Tämä funktio palauttaa totuusarvon (True
tai False
) sen mukaan, onko sille annettu sana palindromi vai ei. Funktio palindromi
kutsuu funktiota kaanna
, koska se haluaa verrata sanaa toisinpäin käännettyyn sanaan. Jos sana on palindromi, se on sama käännettynä.
Seuraava ohjelma kertoo, ovatko käyttäjän antamat sanat palindromeja:
# -*- coding: latin-1 -*- def kaanna(teksti): uusi = "" for merkki in teksti: uusi = merkki + uusi return uusi def palindromi(teksti): return teksti == kaanna(teksti) while True: sana = raw_input("Anna sana: ") if sana == "": break if palindromi(sana): print "Sana on palindromi!" else: print "Sana ei ole palindromi!"
Ohjelman tulostus voi olla seuraava:
Anna sana: enne Sana on palindromi! Anna sana: kaivo Sana ei ole palindromi! Anna sana: syksy Sana ei ole palindromi! Anna sana: autioitua Sana on palindromi! Anna sana:
Kun käyttäjä kirjoittaa sanan, tapahtuu seuraavaa:
palindromi
.palindromi
kutsuu funktiota kaanna
.kaanna
palauttaa funktiolle palindromi
käännetyn sanan.palindromi
palauttaa pääohjelmalle arvon True
, jos sana on palindromi, ja arvon False
, jos sana ei ole palindromi.Alkuluku on positiivinen kokonaisluku, joka on jaollinen vain luvulla 1 ja itsellään. Lisäksi on sovittu, että luku 1 ei ole alkuluku. Seuraava ohjelma etsii kaikki alkulukut, jotka ovat pienempiä kuin 50.
# -*- coding: latin-1 -*- def alkuluku(luku): if luku < 2: return False for jakaja in range(2, luku): if luku % jakaja == 0: return False return True for luku in range(50): if alkuluku(luku): print luku,
Ohjelman tulostus on seuraava:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
Funktio alkuluku
käsittelee luvun seuraavasti:
False
.False
.True
.Tässä range(2, luku)
on lista, jonka ensimmäinen luku on 2 ja viimeinen luku on yksi pienempi kuin luku
. Esimerkiksi range(2, 7)
on lista [2, 3, 4, 5, 6]
. Luku 7 ei ole jaollinen millään näistä luvuista, joten luku 7 on alkuluku.
Seuraava ohjelma näyttää tilaston listan aineistosta:
# -*- coding: latin-1 -*- def tilasto(luvut): if len(luvut) == 0: print "Tyhjä aineisto!" return for luku in luvut: print "*" * luku, luku print "Keskiarvo:", float(sum(luvut)) / len(luvut) tilasto([5, 3, 10, 8, 4, 4, 9, 3])
Ohjelman tulostus on seuraava:
***** 5 *** 3 ********** 10 ******** 8 **** 4 **** 4 ********* 9 *** 3 Keskiarvo: 5.75
Funktion tilasto
parametri on lista lukuja. Jos lista on tyhjä, funktio tulostaa virheviestin ja päättyy heti. Tässä funktio ei palauta arvoa, minkä vuoksi komennon return
ainoa tarkoitus on poistua funktiosta.
Funktio käy läpi listan luvut ja tulostaa niitä vastaavat palkit. Lopuksi funktio laskee lukujen keskiarvon jakamalla lukujen summan niiden määrällä. Lukujen summa on muutettu liukuluvuksi, jotta jakolaskun lopputulos on liukuluku.
Funktion sisäiset muuttujat eivät vaikuta pääohjelman ja muiden funktioiden muuttujiin. Seuraavassa ohjelmassa sekä pääohjelmassa että funktiossa on muuttuja nimi
, mutta muuttujat ovat erillisiä. Vaikka funktion muuttuja nimi
saa arvon "Uolevi"
, pääohjelman muuttujan nimi
arvo on edelleen "Henrikki"
.
# -*- coding: latin-1 -*- def muutos(): nimi = "Uolevi" nimi = "Henrikki" muutos() print nimi # tulostaa "Henrikki"
Sanan global
avulla pääohjelman ja funktion muuttujat voi yhdistää. Seuraavassa ohjelmassa muuttuja nimi
on yhteinen, jolloin funktion suorituksen jälkeen myös pääohjelmassa muuttujan nimi
arvo on "Uolevi"
.
# -*- coding: latin-1 -*- def muutos(): global nimi nimi = "Uolevi" nimi = "Henrikki" muutos() print nimi # tulostaa "Uolevi"
Olen saanut selville että tämän oppaan koodeista voi yhdistää "Ritari Henrikki"-pelin joka sijoittuu keskiajalle.
Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.