Klasser og objekter#
Læringsutbytte
Etter å ha arbeidet med dette temaet, skal du kunne:
gjøre rede for hva som menes med objektorientert programmering
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 på 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.
Løsningsforslag
leonardo = Turtle()
leonardo.shape("turtle")
leonardo.color("blue")
leonardo.backward(100)
leonardo.left(90)
leonardo.forward(100)
leonardo.right(90)
leonardo.forward(100)
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.
Løsningsforslag
class Glass:
def __init__(self):
self.innhold = 0
def fyll(self, mengde):
self.mengde = mengde
self.innhold += self.mengde
def sjekkInnhold(self):
return self.innhold
vannglass = Glass()
vannglass.fyll(5)
print(vannglass.sjekkInnhold())
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 # ...
Løsningsforslag
class Glass:
def __init__(self, kapasitet):
self.kapasitet = kapasitet
self.innhold = 0
def fyll(self, mengde):
self.mengde = mengde
self.innhold += self.mengde
if self.innhold >= self.kapasitet:
print("Glasset er fullt!")
self.innhold = self.kapasitet
def tøm(self, mengde):
self.mengde = mengde
self.innhold -= self.mengde
if self.innhold <= 0:
print("Glasset er tomt!")
self.innhold = 0
def sjekkInnhold(self):
return self.innhold
mittGlass = Glass(5)
mittGlass.fyll(6)
mittGlass.tøm(1)
mittGlass.sjekkInnhold()
print("Glasset inneholder:", mittGlass.sjekkInnhold(), "dl.")
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).
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.
Løsningsforslag
class Skilpadde:
def __init__(self):
self.artsnavn = "Chelonia mydas"
self.farge = "green"
self.levende = True
if self.farge == "green":
self.hp = 15
elif self.farge == "red":
self.hp = 20
def harm(self, skade):
self.hp -= skade
if self.hp <= 0:
self.levende = False
self.hp = 0
print("Skilpadden døde.")
def heal(self):
self.hp += 5
skilpadde1 = Skilpadde()
skilpadde1.farge = "green"
print("HP:", skilpadde1.hp)
skilpadde1.harm(13)
print("HP:", skilpadde1.hp)
skilpadde1.harm(16)
print("HP:", skilpadde1.hp)
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.
Løsningsforslag
class Vektor:
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
def norm(self):
lengde = (self.x**2 + self.y**2 + self.z**2)**0.5
return lengde
def add(self, vektor):
x = self.x + vektor.x
y = self.y + vektor.y
z = self.z + vektor.z
return [x, y, z]
u = Vektor(1,2,2)
v = Vektor(4,4,4)
print(u.norm())
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.