Luento 17: Perintä. self.points = 0 self.status = 'Student'

Samankaltaiset tiedostot
Perintä (inheritance)

Ohjelmoinnin perusteet Y Python

Sisällys. JAVA-OHJELMOINTI Osa 6: Periytyminen ja näkyvyys. Luokkahierarkia. Periytyminen (inheritance)

9. Periytyminen Javassa 9.1

Ohjelmoinnin perusteet Y Python

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

9. Periytyminen Javassa 9.1

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Rajapinnat ja sisäluokat

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

Ohjelmoinnin peruskurssi Y1

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Ohjelmoinnin jatkokurssi, kurssikoe

Pythonin Kertaus. Cse-a1130. Tietotekniikka Sovelluksissa. Versio 0.01b

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Sisällys. Metodien kuormittaminen. Luokkametodit ja -attribuutit. Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2

Sisällys. Mitä on periytyminen? Yksittäis- ja moniperiytyminen. Oliot ja perityt luokat. Periytymisen käyttö. 8.2

Mitä on periytyminen?

Ohjelmoinnin perusteet Y Python

UML Luokkakaavio 14:41

Ohjelmoinnin peruskurssien laaja oppimäärä, kevät

T Olio-ohjelmointi Osa 5: Periytyminen ja polymorfismi Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

Ohjelmoinnin perusteet Y Python

A) on käytännöllinen ohjelmointitekniikka. = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys)

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssi Y1

Tentti: T Ohjelmoinnin peruskurssi, osa 1. Yleistä. Tehtävä 1

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1

Javan perusteita. Janne Käki

815338A Ohjelmointikielten periaatteet

Java kahdessa tunnissa. Jyry Suvilehto

Ohjelmoinnin perusteet Y Python

Harjoitustyö: virtuaalikone

Ohjelmoinnin perusteet Y Python

Kerta 2. Kerta 2 Kerta 3 Kerta 4 Kerta Toteuta Pythonilla seuraava ohjelma:

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2

Ohjelmoinnin perusteet Y Python

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 5: Python

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

T Ohjelmoinnin perusteet Y (Python). Tentti

ITKP102 Ohjelmointi 1 (6 op)

15. Ohjelmoinnin tekniikkaa 15.1

Ohjelmoinnin perusteet Y Python

Sisällys. 6. Metodit. Oliot viestivät metodeja kutsuen. Oliot viestivät metodeja kutsuen

Zeon PDF Driver Trial

Kooste. Esim. Ympyrän keskipiste voidaan ajatella ympyrän osaksi.

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

Jypelin käyttöohjeet» Miten saan peliin pistelaskurin?

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

Ohjelmoinnin perusteet Y Python

SEPA REFAKTOROINTI Antti Ahvenlampi, 57408L Erik Hakala, 57509T

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Sisällys. 11. Rajapinnat. Johdanto. Johdanto

Rajapinta (interface)

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 6: Python

Ohjelmoinnin perusteet Y Python

1 Tehtävän kuvaus ja analysointi

Ohjelmistojen mallintaminen luokkamallin lisäpiirteitä

Ohjelmoinnin perusteet Y Python

Tietotekniikan valintakoe

Ohjelmoinnin peruskurssi Y1

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

2. Olio-ohjelmoinnin perusteita 2.1

Olio-ohjelmoinnissa luokat voidaan järjestää siten, että ne pystyvät jakamaan yhteisiä tietoja ja aliohjelmia.

Ohjelmoinnin perusteet Y Python

Oliot viestivät metodeja kutsuen

1. Omat operaatiot 1.1

4. Luokan testaus ja käyttö olion kautta 4.1

Ohjelmoinnin peruskurssien laaja oppimäärä

Sokkelon sisältö säilötään linkitetyille listalle ja tekstitiedostoon. Työ tehdään itsenäisesti yhden hengen ryhmissä. Ideoita voi vaihtaa koodia ei.

ITKP102 Ohjelmointi 1 (6 op)

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmointi 2 / 2010 Välikoe / 26.3

Olio-ohjelmointi Javalla

Yksikkötestaus. import org.junit.test; public class LaskinTest public void testlaskimenluonti() { Laskin laskin = new Laskin(); } }

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Ohjelmoinnin perusteet Y Python

15. Ohjelmoinnin tekniikkaa 15.1

Tietorakenteet ja algoritmit

Tietojen syöttäminen ohjelmalle. Tietojen syöttäminen ohjelmalle Scanner-luokan avulla

Periytyminen (inheritance)

16. Javan omat luokat 16.1

Metodien tekeminen Javalla

Ohjelmoinnin peruskurssien laaja oppimäärä

Transkriptio:

Luento 17: Perintä class Staff(object): def init (self, name, salary): self.salary = salary self.status = 'Staff' def set_name(self, new_name): self.name = new_name def get_status(self): return self.status def get_salary(self): return self.salary def raise_salary(self, new_salary): if self.salary < new_salary: self.salary = new_salary + ' ' + self.status + ' ' + str(self.salary) class Student(object): def init (self, name): self.points = 0 self.status = 'Student' def set_name(self, new_name): self.name = new_name def get_status(self): return self.status def add_points(self, new_points): self.points += new_points + ' ' + self.status + ' ' + str(self.points)

Olemme jo tottuneet siihen, että jokaiseen luokkaan pitää kirjoittaa kaikki ne metodit, joiden mukaisia toimintoja siitä luodun olion halutaan suorittavan. Toisaalta taas, on sanottu että toistuvat osuudet pitää laittaa funktioihin/metodeihin. Mitä siis tehdä, kun kahdessa luokassa on esitetty täsmälleen samat asiat, eli niissä on toistoa. Niin, ja jos noita kohtia joutuisi muuttamaan, niin samat muutokset pitäisi tehdä kumpaankin luokkaan. Ei siis mitenkään helposti ylläpidettävää ohjelmakoodia. Olio- ohjelmoinnissa on käsite perintä, jota voisi käyttää hyväksi tässä tapauksessa. Perintä Perintä eli periytyminen (engl. inheritance) on tekniikka, jonka avulla voi määritellä ylä- ja alakäsitteitä. Perinnässä ilmoitetaan koodissa, että tietty luokka ("aliluokka") sisältää kaikki tietyn toisen luokan ("yliluokan") piirteet, mukaan lukien metodien toteutuksen ja ilmentymämuuttujat. Lisäksi jokaisella aliluokalla voi olla omiakin piirteitä. Perintärelaatiolla voi muodostaa hierarkioita ihan niin kuin tuossa eläinten luokituksessakin. Edellisen tai seuraavan "sukupolven" luokkia samassa "sukupuun haarassa" kutsutaan välittömiksi yli- ja aliluokiksi (engl. direct/immediate super- /subclass). Koska kaikki pythonissa on olioita, nekin kuuluvat erilaisiin aliluokkiin. Jokaisella aliluokalla on yliluokkiensa ominaisuudet ja lisäksi vielä omia ominaisuuksia.

Muutetaan alun esimerkin henkilökunta ja opiskelija käyttämään perintää. Ensin tarvitaan yhteinen nimi noille luokille: mitä ne molemmat kuvaavat. Tässä noita yhdessä voisi kutsua vaikka henkilöiksi (person). Seuraavaksi kerätään kummastakin luokasta kaikki metodit ja muuttujat, jotka ovat aivan samoja kummassakin. Metodit def set_name(self, new_name): self.name = new_name def get_status(self): return self.status ovat täsmälleen toistensa kopioita. Loput asiat luokissa ovatkin sitten erilaisia. Tehdään noista valituista yliluokka Person: class Person(object): Perii kaiken luokasta object def set_name(self, new_name): self.name = new_name def get_status(self): return self.status Tämä näyttää aivan tavalliselta luokalta. Ainoa mikä puuttuu, on alustusmetodi mutta se ei haittaa, jos käytämme aliluokissa alkuperäisiä alustusmetodeja. Sitten laitetaan vain sekä opiskelija että henkilökunta perimään nämä ominaisuudet: class Staff(Person): def init (self, name, salary): self.salary = salary self.status = 'Staff' Perii kaiken luokasta Person class Student(Person): def init (self, name): self.points = 0 self.status = 'Student' Perii kaiken luokasta Person Nyt sekä Staff, että Student- luokilla on molemmilla käytettävissään metodit set_name(), get_name() ja get_status() ja luokkia voi jo testata näiden osalta:

from register import Staff from register import Student def main(): proffa = Staff('H. Ajamieli', 4000) siivooja = Staff('S. Iivooja', 2000) olli = Student('O. Opiskelija') teemu = Student('Teemu Teekkari') print proffa.get_name() print teemu.get_status() H. Ajamieli Student if name == ' main ': main() Nyt on vuorossa loppujen metodien lisääminen luokkiin. class Staff(Person): def init (self, name, salary): self.salary = salary self.status = 'Staff' def get_salary(self): return self.salary def raise_salary(self, new_salary): if self.salary < new_salary: self.salary = new_salary + ' ' + self.status + ' ' + str(self.salary) class Student(Person): def init (self, name): self.points = 0 self.status = 'Student' def add_points(self, new_points): self.points += new_points + ' ' + self.status + ' ' + str(self.points)

Yliluokka Person sisältää kaikki metodit, jotka ovat yhteisiä kaikille henkilöille. Siitä tehdyt aliluokat voivat käyttää kaikkia yliluokan metodeja ja lisäksi omia metodeja. Perintää kuvataan nuolikuviolla. Student Person Staff Kerätään tulos yhteen: class Person(object): def set_name(self, new_name): self.name = new_name def get_status(self): return self.status class Staff(Person): def init (self, name, salary): self.salary = salary self.status = 'Staff' def get_salary(self): return self.salary def raise_salary(self, new_salary): if self.salary < new_salary: self.salary = new_salary + ' ' + self.status + ' ' + str(self.salary) class Student(Person): def init (self, name): self.points = 0 self.status = 'Student' def add_points(self, new_points): self.points += new_points + ' ' + self.status + ' ' + str(self.points)

Ohjelma lyheni jonkun verran. Nyt jos yhteisiä metodeja tarvitsee muuttaa, muutokset tehdään vain yhteen kohtaan ohjelmakoodia. Lisäksi testaus pitäisi onnistua samalla testimoduulilla kuin aikaisemminkin. Perinnän lisäksi tämä toimii siis esimerkkinä ohjelman uudelleenrakentamisesta (refactoring). Siinä ohjelman toteutustavan muuttaminen ei saa vaikuttaa ohjelman toimintaan. Samojen testien pitäisi antaa samat tulokset kummassakin tapauksessa. Tehdään siis testi aiemmalla testiohjelmalla (regressiotestaus) ja todetaan, että toimii samoin edelleen. Katsotaanpa sitten toista esimerkkiä. Mikä voisi olla lemmikkien yhdistävä tekijä? Tehdään siis luokat lemmikeille ja otetaan yhdeksi jo aiemminkin esillä ollut papukaija. Toinen olkoon vaikkapa kissa. Molempia kutsutaan joksikin, niillä on siis nimet ja ne kuuluvat jompaankumpaan lajiin. Lisäksi ne ääntelevät jollain tavalla. Kissoilla on oma äänivalikoimansa ja papukaija voi osata puhua. Tehdään näillä tiedoilla yliluokka Pet: class Pet(object): def init (self, name, species): self.species = species def get_species(self): return self.species def speak(self): index = random.randint(0, len(self.repertoire)-1) return self.repertoire[index] return '{:s} is a {:s}'.format(self.name, self.species) Lemmikin luonnin yhteydessä kerrotaan lemmikin nimi ja laji. Lemmikkiä voi käskeä kertomaan nimensä ja lajinsa sekä päästämään jonkin äänen. Loppuun on lisätty olion tulostusta varten str - metodi. Metodi palauttaa merkkijonona lemmikin nimen ja sen lajin. Mitä ominaisuuksia kissalla voisi olla näiden lisäksi. Ne karvapallot tuntien vaikka mitä, mutta otetaan nyt vain kunkin kissan herkkuruoka. Tehdään kissalle oma alustusmetodi, joka täydentää lemmikkiluokan alustusmetodia. class Cat(Pet): def init (self, name, goodies): Pet. init (self, name, "Cat") self.goodies = goodies self.repertoire = ['Meow!', 'Hrrrr', 'Hiss!'] def get_goodies(self): return self.goodies

Kun luodaan uusi kissaolio, kerrotaan kissan nimi ja sen herkkuruoka. Koska kissalla on oma alustusmetodi, se syrjäyttää lemmikin alustusmetodin. Lemmikin alustusmetodissa on kuitenkin nimen ja lajin talteenotto, joten sitä ei kannata hylätä kokonaan. Otetaan ensin kissan nimi ja lajitieto talteen kutsumalla lemmikin alustusmetodia. class Pet(object): class Cat(Pet): def init (self, name, goodies): Pet. init (self, name, "Cat") def init (self, name, species): self.species = species Yliluokan nimi Yliluokan metodi Kutsuva olio Yliluokan metodin vaatimat parametrit Herkkuruoka ja äänivalikoima alustetaan metodin lopuilla riveillä. Kissoilla ei ole mitään suurempaa tarvetta mielistellä omistajaansa, joten sen äänivalikoima on suunnilleen vakio. Naukaisut, kehräykset ja sähinät voi alustaa kaikille samoiksi. Kissojen oma metodi on herkkuruoan haku. Mitä omaa on papukaijalla? Tässä tapauksessa väri ja lauseet, jotka se on mahdollisesti oppinut. Jokainen kaija osaa kuitenkin perus kraah- äänen. class Parrot(Pet): def init (self, name, color, repertoire=[]): Pet. init (self, name, "Parrot") self.color = color self.repertoire = ['Kraah'] self.repertoire.extend(repertoire) return '{:s} is a {:s} {:s}.'.format(self.get_name(), self.color, self.get_species()) Jos papukaijaa luotaessa lauselista jätetään antamatta, sen tilalle tulee tyhjä lista (repertoire=[]). Samoin kuin kissan tapauksessa, nimi ja laji otetaan talteen yliluokan alustusmetodin kautta ja papukaijan omat tiedot, kuten väri ja mahdolliset opitut lauseet, otetaan ilmentymämuuttujiin alustusmetodin loppuosassa. Luokalle on tehty myös oma str - metodi korvaamaan yliluokan vastaavan metodin. Papukaijan kohdalla halutaan näkyviin myös linnun väri.

Tuo korvaaminen (overriding) toimii siten, että kutsuttaessa olion metodia tulkki selaa luokkia perimishierarkiassa alhaalta ylöspäin, eli aliluokista yliluokkiin ja käyttää ensimmäistä vastaantulevaa oikeannimistä metodia. Kissan str löytyy siis vasta yliluokasta mutta papukaijan jo omasta luokasta. Papukaijan str - metodi siis korvaa yliluokan vastaavan ja tulkki käyttää aina sitä. Moniperintä Pythonissa luokka voi periä ominaisuuksia useammalta luokalta samaan aikaan. Olkoon yksinkertaisena esimerkkinä seuraava: class Horse(object): def init (self, age): self.age = age def trot(self): print 'klop klop' def whinny(self): print 'Ihahaa' class Bird(object): def init (self, wingspan): self.weight = wingspan def chirp(self): print 'chirp chirp' def fly(self): print 'flap flap' class Pegasus(Horse, Bird): def init (self, age, wingspan): Horse. init (self, age) Bird. init (self, wingspan) Hevonen ja lintu ovat normaaleja luokkia. Kummastakin voi luoda olioita tavalliseen tapaan. Hevonen hirnuu ja ravaa, lintu lentää ja sirkuttaa. Entäpä sitten Pegasus? Sehän on se siivekäs hevonen kreikan mytologiasta. Ravaamisen lisäksi se osaa siis lentää. Pegasus on tässä tehty periyttämällä sille sekä hevosen että linnun ominaisuudet. Periyttämällä luokka useammasta yliluokasta siihen saadaan kaikkien näiden yliluokkien ominaisuudet. Siivekkäät hevoset osaavat siis hirnua ravata, lentää ja sirkuttaa. Tuolle sirkuttamiselle tosin täytyy tehdä jotain: sen voisi vaikka syrjäyttää Pegasus- luokassa ja laittaa pegasuksen chirp- metodin kutsumaan hevosen whinny- metodia. Näin pegasus- olion chirp- metodia kutsuttaessa kuuluisikin hirnuntaa.

class Pegasus(Horse, Bird): def init (self, age, wingspan): Horse. init (self, age) Bird. init (self, wingspan) def chirp(self): Horse.whinny(self) Jos useammasta luokasta periytetylle luokalle ei tee omaa alustusmetodia, tulkki hakee sitä yliluokista. Yliluokat kokeillaan siinä järjestyksessä kuin ne luokan otsikossa ovat. Tässä tapauksessa siis käytettäisiin Horse- luokan init - metodia, jos sellainen on ja jos ei ole, kokeillaan Bird luokkaa. Molempia ei siis käytetä automaattisesti, vaan ensimmäistä löytyvää. Yleensä kannattaakin tehdä moniperintää käyttävälle aliluokalle oma alustusmetodi, joka kutsuu yliluokkiensa alustusmetodeja. Testiohjelma: from horses import * def main(): print '----Usual horse-----' horse1 = Horse(5) horse1.whinny() horse1.trot() print '----Flying horse-----' horse2 = Pegasus(3, 6.5) horse2.whinny() horse2.trot() horse2.fly() horse2.chirp() if name == ' main ': main() Ja sen tulostus: ----Usual horse----- Ihahaa klop klop ----Flying horse----- Ihahaa klop klop flap flap chirp chirp

Super Toinen tapa kutsua yliluokan metodia syrjäyttävästä luokasta on käyttää super- funktiota. Sitä käytettäessä yliluokkaa ei tarvitse nimetä, vaan Python hoitaa vastaavan metodin etsimisen yliluokista. Pegasuksen chirp- metodin tapauksessa sen käyttö olisi seuraava: class Pegasus(Horse, Bird): def init (self, age, wingspan): Horse. init (self, age) Bird. init (self, wingspan) def chirp(self): super(pegasus, self).whinny() Funktiolle annetaan parametreina luokka, jossa kutsu sijaitsee sekä self. Funktiolle annetaan metodina sen funktion nimi, jota halutaan kutsua. Huomaa, että kutsusta puuttuu self mutta muut mahdolliset parametrit sille pitää antaa. super- fuktio toimii tässä tapauksessa ihan oikein mutta monimutkaisemmissa luokkarakenteissa sen oikeaoppinen käyttö vaatii lisätyötä, joka ei ole enää tämän kurssin asioita. Lisäksi sen käyttö vaatii uuden luokkamäärittelyn mukaisia luokkia, joissa luokan nimen perässä on aina se, mistä se periytyy. class Horse(object): Vanhan tyylin mukaisilla luokkamäärittelyillä, joissa yliluokka piti kertoa vain silloin, jos se oli jotakin itse tehtyä (ei Pythonin sisäänrakennettu tyyppi) class Horse: super ei toimi.