Klasser og objekter#

Læringsutbytte

Etter å ha arbeidet med dette temaet, skal du kunne:

  1. gjøre rede for hva som menes med objektorientert programmering

  2. konstruere enkle klasser og objekter

Objektorientert programmering er en måte å organisere og gjenbruke kode på som er enda litt mer abstrakt og enda litt nyttigere enn funksjoner. Python er et objektorientert språk, så du har brukt objekter allerede uten å nødvendigvis vite om det. Det første objektorienterte programmeringsspråket i verden var Simula, som var utviklet av nordmennene Ole-Johan Dahl og Kristen Nygaard. I populære programmeringsspråk som Java og C++ er objektorientering så grunnleggende at vi ikke kan programmere i disse språkene uten å bruke det. I Python kan vi derimot velge om vi ønsker å bruke objektorientert kode eller ikke.

Det er ikke sikkert du forstår meningen med objekter med det første. Koden blir ofte mer komplisert og teknisk, og det realfaglige innholdet kan noen ganger drukne litt i koden. Det viktigste er derimot at du får litt kjennskap til hva det er og hvordan det kan brukes, slik at du forstår når du faktisk bruker objekter og hvordan de fungerer. Om du vil bruke objektorientert programmering for å strukturere din egen kode eller ikke, kan du velge helt selv.

Objektorientert programmering tar utgangspunkt i klasser, som er oppskrifter på objekter. Disse objektene har egenskaper gitt av denne klassen, og vi kan endre på objektene og gi dem nye egenskaper med funksjoner som vi kaller metoder.

Definisjoner

En klasse er en oppskrift på objekter. Et objekt er en instans (utgave) av en klasse. Objekter er størrelser som er definert via et sett med data (attributter), det vil si egenskaper ved objektene. Objektene kan vi endre og manipulere ved å bruke klassens metoder. Metoder er funksjoner som virker på objektene.

Et enkelt eksempel på et objekt, er heltallsobjekter. For eksempel er tallet 42 et objekt som tilhører klassen “int” (integer = heltall). Metodene du kan bruke på disse objektene, er blant annet addisjon og multiplikasjon.

Eksempel:

klasse = int

objekt = 42

metoder = +, -, *, /

Vi kan se at 42 tilhører klassen int ved å skrive ut typen til objektet:

print(type(42))
<class 'int'>

Skilpaddeobjekter#

Vi har allerede også håndtert objekter gjennom skilpaddegrafikk (turtle). Når vi lager en skilpadde som skal tegne noe, lager vi en instans (et objekt) av klassen “Turtle”. Tidligere skreiv vi bare kommandoene “forward”, “left” og så videre, så da er det kanskje ikke åpenbart at vi bruker metoder dette objektet. Det blir dermed litt enklere å se dersom vi faktisk kaller objektet noe. La oss returnere til en skilpadde som heter Rafael. Istedenfor å bare skrive kommandoene, lager vi nå et skilpaddeobjekt helt eksplisitt:

Her ser vi at vi bruker metodene på objektet ved å skrive “objektnavn.metodenavn()”. Dette gjør også at vi kan lage flere skilpadder i samme kodevindu!

Underveisoppgave

Lag en ny skilpadde som heter Leonardo. Skilpadden skal være blå, og den skal lage gå slik at den danner et rektangel (200 x 100) sammen med figuren som Rafael har tegna.

Klasser#

La oss prøve å lage vår egen klasse med ulike egenskaper. Vi vil definere en klasse som lager objekter med egenskapene til et glass. Det er god skikk å lage klassenavnet med stor forbokstav, og det gjør vi slik:

class Glass:
    def __init__(self):
        self.innhold = 0

Nå har vi definert klassen “Glass” og gitt det en egenskap (attributt) som heter “innhold”, en vanlig egenskap ved de fleste glass. Metodene i en klasse defineres på samme måte som funksjoner. Den metoden vi har lagd her, __init__ (som står for “initiering”), er en spesiell metode som inneholder alle egenskaper som objekter av klassen Glass alltid får. Parameteren i denne funksjonen/metoden er “self”. Dette er en litt merkelig konstruksjon. “self” brukes nemlig for å henvis til at dette er en egenskap ved objektet selv. Det tar litt tid å bli vant til at vi må henvise til objektet selv inni klassen som er oppskriften på objektene. Men når du har sett nok eksempler på hvordan klasser blir konstruert, får du antakelig en forståelse av det. La oss legge til en metode til, som sjekker innholdet i glasset:

class Glass:
    def __init__(self):
        self.innhold = 0            
    def sjekkInnhold(self):
        return self.innhold

La oss nå lage et glass-objekt og sjekke innholdet:

vannglass = Glass()              # laget et vannglass av typen "Glass"
print(vannglass.sjekkInnhold())  # skriver ut innholdet i glasset
0

Underveisoppgave

Lag en metode “fyll” som legger til innhold i glasset. Test metoden ved å legge til 5 (dl) og sjekke innholdet.

Når du har gjort oppgaven ovenfor, kan vi legge til enda en metode som tømmer glasset:

Men hva skjer hvis glasset er fullt eller tomt? Prøv å løse dette problemet i oppgaven nedenfor:

Underveisoppgave

Legg inn en ny egenskap ved glasset som du kaller “kapasitet”. Denne egenskapen skal si noe om hvor mye volum glasset rommer. Fyll også ut det som mangler i metodene “fyll” og “tøm” nedenfor. Metodene skal si fra om glasset er fullt eller tomt. Dersom glasset er tomt, skal innholdet settes til 0, og dersom glasset er fullt, skal innholdet settes til kapasiteten til glasset. Skriv gjerne også ut en melding om at glasset er fullt eller tomt.

    def fyll(self, mengde):
        self.mengde = mengde
        self.innhold += self.mengde
        if #...
            
    def tøm(self, mengde):
        self.mengde = mengde
        self.innhold -= self.mengde
        if # ...

Eksempel: Objekter i spill#

Moderne spill lages med objektorientert kode. En av årsakene er at vi lettere kan gjenbruke kode. Ta for eksempel skilpaddene i Mario. De har noen felles egenskaper, og det er derfor nyttig å kunne plassere dem rundt omkring ved å lage nye objekter fra en klasse istedenfor å gjenta masse kode. Vi kan også ta hensyn til små variasjoner, som farge på skallet, evnen til å gjøre skade eller helsepoeng (HP).

koopa

I programmet nedenfor lager vi en skilpaddeklasse med noen egenskaper og to metoder, “harm” og “heal”. Gå gjennom linje for linje og prøv å forstå hvordan programmet fungerer.

Underveisoppgave

Legg inn et vilkår i programmet ovenfor som skriver ut at skilpadden er død hvis den går under 0 i hp. Lag også en attributt/egenskap som sier noe om skilpadden lever eller ikke.

Eksempel: Vektorobjekt#

Her skal vi se på en klasse som lager et objekt med egenskapene til en matematisk vektor med tre komponenter: \(\vec{v} = [x, y, z]\). Vi ønsker at vi skal kunne regne ut lengden til denne vektoren, og at vi skal kunne addere vektoren med en annen vektor. Lengden av en vektor kalles også for normen til vektoren, og er definert slik:

\(|\vec{v}| = \sqrt{x^2 + y^2 + z^2}\)

En vektorklasse med en metode for addisjon kan se slik ut:

Underveisoppgave

Legg en metode i vektorklassen ovenfor som returnerer lengden/normen til vektoren. Test ut ved å sjekke at normen til vektoren \(\vec{u} = [1, 2, 2]\) er 3.

Arv#

Hvis vi ønsker å lage en klasse som har alle egenskaper til en annen klasse, i tillegg til noen ekstra egenskaper, kan vi la klassen arve egenskaper fra den andre klassen. La oss lage en termosklasse som arver fra glassklassen (kalt superklasse). Klassen som arver, kaller vi en subklasse.

class Termos(Glass):
    def __init__(self, kapasitet, isolasjonsverdi, temperatur):
        super().__init__(kapasitet) # Her arver termosen kapasitet fra klassen Glass (superklassen)
        self.isolasjonsverdi = isolasjonsverdi
        self.temperatur = temperatur
    def økTemperatur(self):
        self.temperatur += 5/self.isolasjonsverdi
    def senkTemperatur(self):
        self.temperatur -= 10/self.isolasjonsverdi
    def hentTemperatur(self):
        print(self.temperatur)

termos = Termos(10, 1.25, 70)
termos.fyll(10)

for timer in range(5):
    termos.senkTemperatur()
    termos.tøm(1)
    termos.hentTemperatur()
termos.sjekkInnhold()
Glasset er fullt!
62.0
54.0
46.0
38.0
30.0
5

Underveisoppgave

Forklar hvordan programmet ovenfor fungerer.