Perintä (inheritance)



Samankaltaiset tiedostot
Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

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

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Java kahdessa tunnissa. Jyry Suvilehto

9. Periytyminen Javassa 9.1

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

Ohjelmoinnin peruskurssi Y1

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

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

Ohjelmoinnin perusteet Y Python

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

Mitä on periytyminen?

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

9. Periytyminen Javassa 9.1

Ohjelmoinnin perusteet Y Python

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

Ohjelmoinnin perusteet Y Python

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

Ohjelmointikielet ja -paradigmat 5op. Markus Norrena

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

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

Ohjelmoinnin perusteet Y Python

UML Luokkakaavio 14:41

Ohjelmoinnin perusteet Y Python

Aalto Yliopisto T Informaatioverkostot: Studio 1. Oliot ja luokat Javaohjelmoinnissa

812336A C++ -kielen perusteet,

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Ohjelmoinnin peruskurssi Y1

Javan perusteita. Janne Käki

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Olio-ohjelmointi Javalla

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Pakkaukset ja määreet

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Ohjelmointikielet ja -paradigmat 5op. Markus Norrena

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

Ohjelmoinnin peruskurssi Y1

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Solidity älysopimus ohjelmointi. Sopimus suuntautunut ohjelmointi

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Common Lisp Object System

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

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

Ohjelmoinnin peruskurssi Y1

1. Omat operaatiot 1.1

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

linux linux: käyttäjän oikeudet + lisää ja - poistaa oikeuksia

815338A Ohjelmointikielten periaatteet

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Rajapinta (interface)

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

on ohjelmoijan itse tekemä tietotyyppi, joka kuvaa käsitettä

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Tutoriaaliläsnäoloista

Sisällys. 11. Rajapinnat. Johdanto. Johdanto

Ohjelmistojen mallintaminen luokkamallin lisäpiirteitä

Periytyminen (inheritance)

16. Javan omat luokat 16.1

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

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

Ohjelmoinnin perusteet Y Python

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

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

Ohjelmoinnin perusteet Y Python

Tehtävä 1. TL5302 Olio-ohjelmointi Koe Malliratkaisuja. Tässä sekä a)- että b)-kohdan toimiva ratkaisu:

C++ rautaisannos. Kolme tapaa sanoa, että tulostukseen käytetään standardikirjaston iostreamosassa määriteltyä, nimiavaruuden std oliota cout:

QT tyylit. Juha Järvensivu 2008

14. Poikkeukset 14.1

TIE Ohjelmistojen suunnittelu. Luento 8..9: moniperintä

Ohjelmoinnin perusteet Y Python

Ohjelmointi 1 C#, kevät 2013, 2. tentti

Ohjelmoinnin peruskurssi Y1

- Komposiittityypit - Object (Mukaanlukien funktiot) - Array. - Erikoisdatatyypit - null - undefined

Ohjelmistotekniikan menetelmät, suunnittelumalleja

Tenttikysymykset. + UML-kaavioiden mallintamistehtävät

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Transkriptio:

Perintä (inheritance) Perintä on menetelmä, jonka avulla jostakin olemassaolevasta luokasta voidaan johtaa uusi luokka, joka saa automaattisesti käyttöönsä perimänsä luokan ominaisuuksia. Perittävää luokkaa kutsutaan yliluokaksi (superclass) Uutta, yliluokan ominaisuudet perivää luokkaa kutsutaan aliluokaksi (subclass) Periminen ilmaistaan sijoittamalla luokan nimen jälkeen sulkuihin perittävän luokan (yliluokan) nimi.

Perintä class class User(object): User(object): def def set_password set_password (self, (self, passwd): passwd): toteutus toteutus Class Class Admin(User): Admin(User): toteutus toteutus

Perintä (inheritance) Yliluokan ja aliluokan suhde Aliluokan ja yliluokan välillä on ns. IsA suhde. Allaolevassa esimerkissä every admin is a user class class User(object): User(object): def def set_password set_password (self, (self, passwd): passwd): toteutus toteutus class class Admin(User): Admin(User): toteutus toteutus

Perintä (inheritance) Esimerkissä Admin-luokka perii luokan User Nyt Admin luokalla on perinnän kautta toteutus metodille set_password. Luokka perii yliluokalta myös sen toteuttamat metodit, yliluokat sekä muuttujat. Käytännössä Admin-oliot ovat myös yliluokkiensa (User ja Object) tyyppisiä (IsA-suhde) class class User(object): User(object): def def set_password set_password (self, (self, passwd): passwd): toteutus toteutus class class Admin(User): Admin(User): toteutus toteutus

Esimerkki Kirjaston tietokanta sisältää nykyisin varsin monenlaisia lainattavia asioita Kirjoja Kasetteja CD:itä Videoita DVD-levyjä Nuotteja, mikrofilmejä, jne Näillä on paljon yhteisiä ominaisuuksia Luokkia mallinnettaessa yhteiset ominaisuudet tulisi mahdollisuuksien mukaan kerätä yliluokkaan.

Esimerkki: ennen perintää Luokissa on yhteisiä tai melkein yhteisiä toteutusosia Koodia toistetaan turhaan Ohjelmaa muutettaessa samat korjaukset tehdään kaikkiin luokkiin class CD(object): def get_name(self): def get_artists(self): class Book(object): def def get_play_time(self): get_name(self): Nimi on kaikilla Artist, author ja editor ovat oikeastaan sama asia def get_authors(self): class Magazine(object): def get_name(self): def get_pages(self): def get_editors(self): def get_issn(self):

Esimerkki: perinnän jälkeen Yhteiset piirteet luokassa LibraryItem Kaikilla aliluokilla metodit get_name ja get_authors käytössä class LibraryItem(object): def get_name(self): def get_authors(self): class CD(LibraryItem): def get_play_time(self): class Book(LibraryItem): def get_pages(self): class Magazine(LibraryItem): def get_issn(self):

Perintähierarkia Yhdellä luokalla voi olla monta aliluokkaa ja millä tahansa aliluokalla taas omia aliluokkia jne. Perintähierarkia on termi, jolla viitataan siihen kuinka luokat perinnän kautta muodostavat puumaisen rakenteen jonka huipulla on Pythonissa luokka object. Object Person Numbers Mappings jne Admin User Integers

Moniperintä Luokka voi periä ominaisuutensa useammasta eri luokasta class Oval(Circle, Rectangle): def get_area(self): def get_perimeter(self): Viitattaessa aliluokan metodiin (tai muuttujaan) hakujärjestys perintärakenteessa on alhaalta ylös, vasemmalta oikealle. (ratkaisee ns. timanttiongelman) Ensin etsittäisiin siis Circle-luokasta ja sen yliluokista ja vasta sitten Rectangle-luokasta ja sen yliluokista. Python käyttää ensimmäistä osumaa. Sen ylä- ja oikealla puolella olevia täytyy erikseen kutsua class Oval(Circle, Rectangle): def init (self, x, y, r1, r2): Rectangle. init (self, x, y, r1, r2)

Luokka oliona Kun tulkki kohtaa avainsanan class, se luo muistiin olion TestiLuokka Koska oliosta TestiLuokka voi luoda ilmentymiä, sen täytyy olla luokka class TestiLuokka(object): pass olio = TestiLuokka() olio.muuttuja = 456 print olio.muuttuja TestiLuokka.muuttuja = 123 print TestiLuokka.muuttuja Koska oliolle TestiLuokka voi lisätä muuttujan, sen täytyy olla myös olio Koska luokka on Pythonissa olio, se voidaan luoda ohjelman suorituksen aikana lennosta. def luo_luokka_uusi(): class Uusi(object): def init (self, arvo): self.arvo = arvo return Uusi Uusi = luo_luokka_uusi() print Uusi toinen_olio = Uusi(8) print toinen_olio.arvo <class ' main.uusi'> 8

type-funktio Funktio type näyttää olion tyypin Se pystyy myös luomaan luokan saamistaan parametreista: olio = TestiLuokka() olio.muuttuja = 456 Uusi = luo_luokka_uusi() print type(olio) print type(olio.muuttuja) print type(uusi) def alusta(self, arvo): self.arvo = arvo def hae_nimi(self): return self.nimi huomaa pilkku <class ' main.testiluokka'> <type 'int'> <type 'type'> Uusi = type('uusi', (object,), {' init ': alusta, 'hae_nimi': hae_nimi, 'nimi': 'jussi'}) On sama kuin: Ja kummallekin toimii: class Uusi(object): def init (self, arvo): self.arvo = arvo self.nimi = 'jussi' def hae_nimi(self): return self.nimi print Uusi hemmo = Uusi(3) print hemmo print hemmo.hae_nimi() print hemmo.arvo

Metaluokka Pythonissa luokat luodaan metaluokilla luokkien luokilla Funktio type on metaluokka, jota Python käyttää kaikkien luokkien luomiseen 4 on int-luokan ilmentymä, joka taas on type-luokan ilmentymä ja metodi hae_nimi on instancemethodluokan ilmentymä, joka sekin on type-luokan ilmentymä Metaluokka on siis periaatteessa Pythonin maailmankaikkeuden luoja. Kaikki Pythonin sisäänrakennetut luokat ovat sen ilmentymiä Sen avulla voi myös luoda omia luokkia ohjelman suorituksen aikana

Omat metaluokat type on Pythonissa sisäänrakennettuna mutta metaluokkia voi myös luoda itse. Pythonin kirjastossa on moduuli abc, josta löytyy metaluokka ABCMeta Jos oman luokan metaluokaksi valitsee tämän ABCMeta type:n sijaan, luodaankin hieman toisenlainen luokkaolio Luokasta tulee abstrakti perusluokka Sillä on hieman erilaiset säännöt periytymisen suhteen

Abstrakti perusluokka Abstrakti perusluokka on luokkamäärittely jossa mille tahansa luokalle voi määrätä virtuaalisen yliluokan. Pythonissa sarjatyypin luokille on määrätty metaluokaksi abstrakti perusluokka Sequence tai MutableSequence Tarkoituksena on että isinstance- ja issubclassfunktiot voivat tunnistaa olioita ja luokkia jonkin tietyn luokan ilmentymiksi tai aliluokiksi: isinstance([], Sequence) issubclass(list, Sequence) issubclass(list, MutableSequence) isinstance((), Sequence) not issubclass(tuple, MutableSequence)

Abstrakti luokka Kertomalla, että luokan metaluokka on ABCMeta, voidaan käyttää abstrakteja metodeja Jos luokkaan lisätään metodi, joka merkitään abstraktiksi, silloin luokasta ei voi luoda oliota Aliluokista voi luoda olioita vain silloin, kun kaikki abstraktit metodit on korvattu aliluokassa

Abstrakti metodi Abstraktin metodin tehtävä on kuvata jokin toiminto, joka aliluokilla väistämättä on, mutta jolla ei itse yliluokan tasolla ole järkevää toteutusta tai toteutus vaihtelee aliluokittain Esim. luokassa Kuvio voi olla abstrakti metodi piirrä() Kuitenkin vasta aliluokissa Soikio ja Suorakulmio metodille on olemassa mahdolliset toteutukset

Abstrakti metodi Luokan metodin merkitseminen abstraktiksi edellyttää siis että luokan metaluokka on ABCMeta Abstrakteja metodeja voi kutsua aliluokista normaalisti type-fuktio ei voi lisätä luokkaan abstraktia metodia, eikä metodia voi muuttaa abstraktiksi tai tavalliseksi ajon aikana. Metodin merkitseminen abstraktiksi toimii vain normaalia perintää käyttäen. Jos aliluokka tehdään register-metodilla, metodien abstraktius menettää merkityksensä Abstraktilla metodilla voi olla myös sisältö auttamassa toiston vähentämisessä

Abstrakti luokka (esimerkki) LibraryItem abstraktina luokkana Kaikissa siitä periytyvissä luokissa oltava metodit init ja is_available() Lehdet taas eivät kaikki ole lainattavissa, joten DailyPaper abstraktiksi import abc class LibraryItem(object): metaclass = abc.abcmeta @abc.abstractmethod def init (self, author_list, ): class DailyPaper(LibraryItem): metaclass = abc.abcmeta @abc.abstractmethod def init (self, name, year, ): LibraryItem. init (self, ) def get_number(self): return self.number def is_available(self): pass class Book(LibraryItem): def get_authors(self): return self.author_list @abc.abstractmethod def is_available(self): '''Method docstring. ''' def init (self, author_list, ): LibraryItem. init (self, ) def is_available(self): if self.due_date: return False else: return True

Abstrakti luokka (esimerkki) LibraryItem abstraktina luokkana Kaikissa siitä periytyvissä luokissa oltava metodit init ja is_available() Lehdet taas eivät kaikki ole lainattavissa, joten DailyPaper abstraktiksi import abc class LibraryItem(object): metaclass = abc.abcmeta @abc.abstractmethod def init (self, author_list, ): class DailyPaper(LibraryItem): metaclass = abc.abcmeta @abc.abstractmethod def init (self, name, year, ): LibraryItem. init (self, ) def get_number(self): return self.number def is_available(self): pass class Book(LibraryItem): def get_authors(self): return self.author_list @abc.abstractmethod def is_available(self): '''Method docstring. ''' def init (self, author_list, ): LibraryItem. init (self, ) def is_available(self): if self.due_date: return False else: return True

Perintä ja näkyvyys Nimi sellaisenaan kertoo, että muuttuja/metodi on käytettävissä luokan ulkopuolelta '_' (yksi alaviiva) nimen edessä kertoo, että muuttujaa tai metodia ei ole tarkoitus käyttää suoraan luokan ulkopuolelta Aliluokat voivat kuitenkin käyttää sitä ' ' (kaksi alaviivaa) nimen edessä kertoo, että tulkki muuttaa nimen muotoon _luokka nimi, jolloin aliluokkakaan ei voi käyttää sitä (name mangling) Tarkoituksena estää yli- ja aliluokkien väliset nimitörmäykset Private methods are private for a reason, but like many other things in Python, their privateness is ultimately a matter of convention, not force. (http://www.diveintopython.net/object_oriented_framework/private_functions.html)

Korvaaminen (Overriding) Perinnässä aliluokan metodi korvaa yliluokan metodin jos niillä on sama nimi. Python etsii oikeannimistä metodia perintähierarkiassa alhaalta ylös ja vasemmalta oikealle (jos peritään useammasta luokasta) Käyttää ensimmäistä vastaantulevaa Jos tämän lisäksi halutaan käyttää vielä jonkin yliluokan metodia, sitä täytyy erikseen kutsua

Korvaaminen (Overriding) Lisätään kirjastoesimerkkiin metodi get_details() Metodi palauttaa merkkijonoesityksen kulloisestakin esineestä. Metodin voi korvata aliluokassa, jolloin eri esineet voivat tulostaa erilaisen kuvauksen tyypistään riippuen Ongelma Nyt jokaisen aliluokan täytyisi toteuttaa ISBNkenttien tms. tulostukset toisistaan erillään. Turhaa toistoa Voidaanko yliluokan get_details-metodia käyttää apuna?

Korvaaminen (Overriding) Aliluokasta (ja vain sieltä) voidaan eksplisiittisesti kutsua yliluokan metodia LibraryItem. init (self, ) Tai: super(aliluokka, ilmentymä).metodi(parametrit) Yleensä kutsu tehdään vastaavassa aliluokan metodissa import abc class LibraryItem(object): metaclass = abc.abcmeta def get_details(self): return 'name: {}, author(s): {}, class Magazine(LibraryItem): def get_details(self): return 'Magazine:\n' + super(magazine, self).get_details() +

Operaattoreiden korvaaminen Joskus voi olla hyödyllistä muuttaa perusoperaattoreiden toimintaa omatekoisten luokkien tapauksessa: from math import pi class Circle(object): def init (self, radius): self.radius = radius def get_area(self): return pi * self.radius ** 2 if name == ' main ': ring1 = Circle(5) ring2 = Circle(3) ring3 = Circle(3) if ring1.get_area() > ring2.get_area(): print 'ring1 was bigger' if ring2.get_area() < ring3.get_area(): print 'ring2 was smaller' if ring2.get_area() == ring3.get_area(): print 'ring2 and ring3 equal size'

Omilla operaattoreilla from math import pi class Circle(object): def init (self, radius): self.radius = radius def get_area(self): return pi * self.radius ** 2 def lt (self, other): return self.radius < other.radius ring1 = Circle(5) ring2 = Circle(3) ring3 = Circle(3) if ring1 > ring2: print 'ring1 was bigger' if ring2 < ring3: print 'ring2 was smaller' if ring2 == ring3: print 'ring2 and ring3 equal size' def le (self, other): return self.radius <= other.radius def eq (self, other): return self.radius == other.radius def ne (self, other): return self.radius!= other.radius def gt (self, other): return self.radius > other.radius def ge (self, other): return self.radius >= other.radius Jos alkaa korvata operaattoreita omilla, silloin kannattaa aina korvata kaikki

color1 = Color('red') color2 = Color('yellow') print color1 + color2 color3 = Color('magenta') print color1 + color3 orange Traceback (most recent call last): File "xxx", line 46, in <module> print color1 + color3 File "xxx", line 23, in add raise TypeError() TypeError class Color(object): def init (self, color_name): self.color_name = color_name.lower() def add (self, other): if self.color_name == 'blue': if other.color_name == 'blue': return self elif other.color_name == 'red': return Color('violet') elif other.color_name == 'yellow': return Color('green') else: raise TypeError() elif self.color_name == 'red': elif self.color_name == 'yellow': else: raise TypeError() def str (self): return self.color_name

Perinnän etuja Koodia tarvitsee kirjoittaa vähemmän Uudelleenkäyttö (Reuse) Koodin ylläpito selkiytyy Muutokset yliluokkaan päivittyvät myös aliluokkiin Mallinnusnäkökulma Olioita voidaan tarvittaessa käsitellä luokasta riippumatta yliluokan tasolla.

Perinnän ongelmia Jos yliluokan toiminta muuttuu olennaisesti niin aliluokkien toiminta täytyy muistaa tarkistaa Jos aliluokka rikkoo sopimuksen (dokumentoidun käyttäytymisen) toteutetaan jokin yliluokan ominaisuus tahallaan eri tavalla joskus käytännöllistä riskialtista Kaikki alkuperäistä luokkaa käyttävä koodi luottaa siihen että luokka ja sen aliluokat tekevät niinkuin oli luvattu. Sudenkuoppia Alustusmetodi käyttää metodia A kenttien alustukseen. Aliluokka korvaa metodin A, mutta ei kutsu yliluokan metodia. Kentät jäävät alustamatta. (Tositarina)