6. Klasser
Programmeringsteknik
Versionen från 29 juni 2007 kl. 19.18 (redigera) KTH.SE:u1w7eri0 (Diskussion | bidrag) ← Gå till föregående ändring |
Versionen från 3 juli 2007 kl. 19.16 (redigera) (ogör) KTH.SE:u1w7eri0 (Diskussion | bidrag) Gå till nästa ändring → |
||
Rad 1: | Rad 1: | ||
- | ==Klasser== | ||
- | |||
==Objektorientering== | ==Objektorientering== | ||
+ | |||
+ | Objektorienterad programmering är ett sätt att kombinera data | ||
+ | och funktioner för att bilda ''objekt''. Objekten är ofta modeller | ||
+ | av verkliga ting. Om vi vill skriva ett program för att simulera | ||
+ | ett rymdskepp kan vi till exempel ha hastighet och lägeskoordinater | ||
+ | som data. Rymdskeppets funktioner kan vara att accelerera i en viss | ||
+ | riktning och att rotera. | ||
+ | |||
+ | För att kunna använda objekt i sitt program måste man först definiera | ||
+ | en ''klass''. Klassen beskriver vilka data ett objekt ska kunna | ||
+ | innehålla och vilka funktioner det ska ha. Om vi definierat en klass | ||
+ | för rymdskepp kan vi sedan skapa hur många rymdskepps-objekt vi vill! | ||
+ | |||
+ | '''Fråga: Vi vill skriva ett program för att lägga patiens. Vilken av följande klasser ska vi definiera i programmet?''' | ||
+ | # Poäng | ||
+ | # Spader | ||
+ | # Kort | ||
+ | '''Svar:'''<span style="color:white">Klassen Kort, så att vi kan skapa många kort-objekt som kan användas i patiensen. </span> | ||
+ | |||
+ | Det stora exemplet i det här avsnittet kommer att handla om ett virtuellt | ||
+ | husdjur. Ett husdjur kan ju ha många egenskaper, men vi väljer ut två att | ||
+ | ta med i vår klass: ''namn'' och ''skick'' (ett heltal som talar om hur den känner | ||
+ | sig just nu). Användaren får själv välja namn på sitt husdjur, och husdjurets | ||
+ | skick ska påverkas av hur den behandlas. | ||
+ | |||
+ | |||
==Attribut== | ==Attribut== | ||
+ | |||
+ | De variabler som används för att lagra data som hör till objektet | ||
+ | kallas ''attribut''. Våra husdjursobjekt ska alltså ha attributen | ||
+ | <code>namn</code> och <code>skick</code>. Om man har flera objekt | ||
+ | av samma typ är attributens värde helt oberoende av varandra. | ||
+ | Två olika husdjur får ha olika namn och olika skick. | ||
+ | |||
+ | Det finns en synlig skillnad mellan attribut och vanliga variabler. | ||
+ | Inuti klassen använder man alltid ordet ''self'' när man vill komma åt | ||
+ | ett attribut. Man kan till exempel skriva så här: | ||
+ | <pre> | ||
+ | self.namn = "Fido" | ||
+ | </pre> | ||
+ | |||
+ | Med ''self'' menar man objektet självt. | ||
+ | |||
+ | |||
+ | '''Fråga: Anta att vi jobbar med ett program för vitvaruhandeln. Vilka av följande alternativ skulle passa som attribut för ett spis-objekt?''' | ||
+ | # bredd | ||
+ | # energiklass | ||
+ | # ugnsvolym | ||
+ | '''Svar:'''<span style="color:white">Alla alternativen skulle passa bra som attribut! </span> | ||
+ | |||
+ | |||
==Metoder== | ==Metoder== | ||
+ | |||
+ | Funktionerna som hör till ett objekt kallas ''metoder''. För att en | ||
+ | funktion ska bli en metod måste den definieras inuti klassen. | ||
+ | Den första parametern i en metod måste alltid vara ''self''. | ||
+ | Via self kan metoden använda objektets attribut. | ||
+ | |||
+ | Säg att vi vill ha en metod som ger vårt husdjur bannor (i uppfostrande | ||
+ | syfte). Metoden ska visa bannorna, och även minska värdet på skick eftersom | ||
+ | husdjuret blir på sämre humör. | ||
+ | |||
+ | <pre> | ||
+ | def banna(self): | ||
+ | |||
+ | print "- Fy på dig", self.namn, "!" | ||
+ | self.skick -= 3 | ||
+ | </pre> | ||
+ | |||
+ | Som synes skriver man en metod precis som en funktion, sånär som | ||
+ | på ordet self. Samma regler för parametrar och returvärden gäller. | ||
+ | |||
+ | Husdjursklassen ska så småningom få metoder som gör följande: | ||
+ | * skapar ett husdjursobjekt och ger attributen värden | ||
+ | * visar i vilket skick husdjuret är | ||
+ | * bannar husdjuret | ||
+ | * matar husdjuret | ||
+ | * leker med husdjuret | ||
+ | * tar avsked av husdjuret | ||
+ | |||
+ | '''Fråga: I en internetbutik vill vi ha ett objekt som representerar en kundvagn. Vilka av följande kan tänkas bli metoder i ett kundvagns-objekt?''' | ||
+ | # lägga ner en vara i kundvagnen | ||
+ | # beräkna totalpriset för alla varor i kundvagnen | ||
+ | # räkna ut dagens vinst för internetbutiken | ||
+ | '''Svar:'''<span style="color:white">Alla utom sista alternativet - det hör | ||
+ | inte till själva kundvagnen.</span> | ||
+ | |||
+ | |||
==Konstruktorn== | ==Konstruktorn== | ||
- | TODO | + | |
+ | ''Konstruktorn'' är en speciell metod som man skriver för att ''initiera'' | ||
+ | objekt, dvs ge objektets attribut de värden de ska ha från början. | ||
+ | Konstruktorn anropas automatiskt varje gång ett objekt skapas. | ||
+ | I Python måste man döpa sin konstruktor till __init__ (alltså init | ||
+ | med två understrykningstecken både före och efter). | ||
+ | |||
+ | Konstruktorn kommer att se ut så här: | ||
+ | |||
+ | <pre> | ||
+ | def __init__(self, djurnamn): | ||
+ | self.namn = djurnamn | ||
+ | self.skick = 0 | ||
+ | </pre> | ||
+ | |||
+ | Den här konstruktorn har två parametrar, self (som ju alltid måste vara med) | ||
+ | och djurnamn. Raden <code>self.namn = djurnamn</code> skapar attributet ''namn'' och | ||
+ | initierar det till värdet av parametern djurnamn. På samma sätt skapar | ||
+ | raden <code>self.skick = 0</code> attributet ''skick'' och initierar | ||
+ | det till noll. Varje gång man gör ett nytt objekt kommer konstruktorn att anropas. | ||
+ | |||
+ | '''Fråga: Vilket av följande måste en konstruktor ha?''' | ||
+ | # parametern self | ||
+ | # en parameter för varje attribut | ||
+ | # ett returvärde | ||
+ | '''Svar:'''<span style="color:white">Parametern self är det enda som måste vara med. Attributen kan få värden via parametrar (som namn ovan), men det är inte nödvändigt. Konstruktorn ska inte ha något returvärde.</span> | ||
+ | |||
+ | |||
+ | ==Klassen== | ||
+ | |||
+ | För att kunna skapa ett objekt måste man först definiera en klass. | ||
+ | Det är i klassen man skriver de metoder som objektet ska ha. | ||
+ | Klasser brukar ha namn som börjar med versal, så att man lätt | ||
+ | ska kunna se att det är en klass. Så här långt har vi hunnit i vår husdjursklass hittills: | ||
+ | |||
+ | <pre> | ||
+ | class Husdjur(object): | ||
+ | # Ett virtuellt husdjur | ||
+ | |||
+ | # Konstruktorn | ||
+ | def __init__(self, djurnamn): | ||
+ | self.namn = djurnamn | ||
+ | self.skick = 0 | ||
+ | |||
+ | # Ger husdjuret bannor. Skick minskas. | ||
+ | def banna(self): | ||
+ | |||
+ | print "- Fy på dig", self.namn, "!" | ||
+ | self.skick -= 3 | ||
+ | |||
+ | </pre> | ||
+ | |||
+ | Med en klass är det likadant som med en funktion - det händer | ||
+ | inget förrän man använder den i huvudprogrammet. För att skapa | ||
+ | ett Husdjurs-objekt kan vi skriva: | ||
+ | |||
+ | <pre> | ||
+ | djur = Husdjur("Muffin") | ||
+ | </pre> | ||
+ | |||
+ | Det som händer här är att konstruktorn <code>__init__</code> | ||
+ | anropas, så att attributen skapas och initieras. Sen returneras | ||
+ | ett Husdjurs-objekt, som lagras i variabeln <code>djur</code> | ||
+ | |||
+ | Nu har vi ett husdjursobjekt i variabeln <code>djur</code>. Hur | ||
+ | anropar vi en av djurets metoder? Just nu finns bara metoden | ||
+ | <code>banna</code> att välja på: | ||
+ | |||
+ | <pre> | ||
+ | djur.banna() | ||
+ | </pre> | ||
+ | |||
+ | När vi vill komma åt ett attribut inuti klassen använder vi ju en punkt, | ||
+ | och ett liknande skrivsätt använder man alltså när man vill anropa en | ||
+ | metod från ett objekt. | ||
+ | |||
+ | '''Fråga: Kan man skriva Husdjur.banna()?''' | ||
+ | |||
+ | '''Svar:'''<span style="color:white">Nej, man kan bara banna ett husdjursobjekt, inte hela klassen. </span> | ||
+ | |||
+ | |||
+ | |||
+ | ==Exempel: Husdjursprogrammet== | ||
+ | |||
+ | Här följer hela programmet, först Husdjurs-klassen, och sedan huvudprogrammet. | ||
+ | Lägg märke till att alla metoderna i klassen är indenterade. | ||
+ | <pre> | ||
+ | class Husdjur(object): | ||
+ | # Ett virtuellt husdjur | ||
+ | |||
+ | # Konstruktorn, initierar attributen namn och skick. | ||
+ | def __init__(self, djurnamn): | ||
+ | self.namn = djurnamn | ||
+ | self.skick = 0 | ||
+ | |||
+ | # Visar husdjurets namn och skick | ||
+ | def visaSkick(self): | ||
+ | print self.namn, "är ", | ||
+ | if self.skick > 5: | ||
+ | print "glad: (*_*)" | ||
+ | elif self.skick > 0: | ||
+ | print "trött: (-z-)" | ||
+ | else: | ||
+ | print "hungrig: (*o*)" | ||
+ | |||
+ | |||
+ | # Ger husdjuret bannor. Skick minskas. | ||
+ | def banna(self): | ||
+ | |||
+ | print "- Fy på dig", self.namn, "!" | ||
+ | self.skick -= 3 | ||
+ | |||
+ | # Ger husdjuret mat. Skick ökar. | ||
+ | def mata(self, mat): | ||
+ | |||
+ | for i in range(mat): | ||
+ | print "GLUFS", | ||
+ | self.skick += mat | ||
+ | |||
+ | # Leker med husdjuret. Skick kan öka eller minska. | ||
+ | def leka(self): | ||
+ | |||
+ | if self.skick < 0: | ||
+ | self.skick -= 1 | ||
+ | print self.namn, " vill inte leka." | ||
+ | else: | ||
+ | self.skick += 1 | ||
+ | print "~~~~~~~~~~~ WHEEEEEEE! ~~~~~~~~~~~" | ||
+ | |||
+ | # Skriver ut avskedet. | ||
+ | def avsked(self): | ||
+ | |||
+ | print "Hejdå,", self.namn, "kommer att sakna dig!" | ||
+ | |||
+ | # Här slutar Husdjursklassen | ||
+ | |||
+ | |||
+ | # -------- Här börjar huvudprogrammet ----------- | ||
+ | djurnamn = raw_input("Vad vill du döpa ditt husdjur till? ") | ||
+ | djur = Husdjur(djurnamn) | ||
+ | djur.visaSkick() | ||
+ | svar = raw_input(" Vill du \n banna \n mata \n leka med \n ditt husdjur? " ) | ||
+ | while svar: | ||
+ | if svar[0]=="m": | ||
+ | bullar = input("Hur många bullar? ") | ||
+ | djur.mata(bullar) | ||
+ | elif svar[0]=="b": | ||
+ | djur.banna() | ||
+ | elif svar[0]=="l": | ||
+ | djur.leka() | ||
+ | else: | ||
+ | print "Hursa? " | ||
+ | djur.visaSkick() | ||
+ | svar = raw_input(" Vill du \n banna \n mata \n leka med \n ditt husdjur? " ) | ||
+ | djur.avsked() | ||
+ | </pre> | ||
+ | |||
+ | Provkör programmet och svara på följande frågor. | ||
+ | |||
+ | * '''Fråga: Hur många objekt skapas i programmet?''' | ||
+ | |||
+ | '''Svar:'''<span style="color:white">Bara ett - variabeln djur. </span> | ||
+ | |||
+ | * '''Fråga: När metoden visaSkick skriver ut att husdjuret är trött - vilka värden har attributet skick då?''' | ||
+ | |||
+ | '''Svar:'''<span style="color:white">Attributet skick har något av värdena 1,2,3,4 eller 5</span> | ||
+ | |||
+ | * '''Fråga: Hur avslutar man programmet?''' | ||
+ | |||
+ | '''Svar:'''<span style="color:white">När man trycker på Retur avslutas programmet. Lägg gärna till en print-sats som upplyser användaren om det! </span> | ||
+ | |||
+ | * '''Fråga: Hur många metoder finns det i klassen Husdjur?''' | ||
+ | |||
+ | '''Svar:'''<span style="color:white">Det finns sex metoder, inklusive konstruktorn.</span> | ||
+ | |||
+ | * '''Fråga: Kan man få programmet att krascha?''' | ||
+ | |||
+ | '''Svar:'''<span style="color:white">Javisst, prova att skriva tre (istället för 3) när du matar husdjuret med bullar. Här skulle det behövas lite felhantering!</span> | ||
Versionen från 3 juli 2007 kl. 19.16
Innehåll |
Objektorientering
Objektorienterad programmering är ett sätt att kombinera data och funktioner för att bilda objekt. Objekten är ofta modeller av verkliga ting. Om vi vill skriva ett program för att simulera ett rymdskepp kan vi till exempel ha hastighet och lägeskoordinater som data. Rymdskeppets funktioner kan vara att accelerera i en viss riktning och att rotera.
För att kunna använda objekt i sitt program måste man först definiera en klass. Klassen beskriver vilka data ett objekt ska kunna innehålla och vilka funktioner det ska ha. Om vi definierat en klass för rymdskepp kan vi sedan skapa hur många rymdskepps-objekt vi vill!
Fråga: Vi vill skriva ett program för att lägga patiens. Vilken av följande klasser ska vi definiera i programmet?
- Poäng
- Spader
- Kort
Svar:Klassen Kort, så att vi kan skapa många kort-objekt som kan användas i patiensen.
Det stora exemplet i det här avsnittet kommer att handla om ett virtuellt husdjur. Ett husdjur kan ju ha många egenskaper, men vi väljer ut två att ta med i vår klass: namn och skick (ett heltal som talar om hur den känner sig just nu). Användaren får själv välja namn på sitt husdjur, och husdjurets skick ska påverkas av hur den behandlas.
Attribut
De variabler som används för att lagra data som hör till objektet
kallas attribut. Våra husdjursobjekt ska alltså ha attributen
namn
och skick
. Om man har flera objekt
av samma typ är attributens värde helt oberoende av varandra.
Två olika husdjur får ha olika namn och olika skick.
Det finns en synlig skillnad mellan attribut och vanliga variabler. Inuti klassen använder man alltid ordet self när man vill komma åt ett attribut. Man kan till exempel skriva så här:
self.namn = "Fido"
Med self menar man objektet självt.
Fråga: Anta att vi jobbar med ett program för vitvaruhandeln. Vilka av följande alternativ skulle passa som attribut för ett spis-objekt?
- bredd
- energiklass
- ugnsvolym
Svar:Alla alternativen skulle passa bra som attribut!
Metoder
Funktionerna som hör till ett objekt kallas metoder. För att en funktion ska bli en metod måste den definieras inuti klassen. Den första parametern i en metod måste alltid vara self. Via self kan metoden använda objektets attribut.
Säg att vi vill ha en metod som ger vårt husdjur bannor (i uppfostrande syfte). Metoden ska visa bannorna, och även minska värdet på skick eftersom husdjuret blir på sämre humör.
def banna(self): print print "- Fy på dig", self.namn, "!" self.skick -= 3
Som synes skriver man en metod precis som en funktion, sånär som på ordet self. Samma regler för parametrar och returvärden gäller.
Husdjursklassen ska så småningom få metoder som gör följande:
- skapar ett husdjursobjekt och ger attributen värden
- visar i vilket skick husdjuret är
- bannar husdjuret
- matar husdjuret
- leker med husdjuret
- tar avsked av husdjuret
Fråga: I en internetbutik vill vi ha ett objekt som representerar en kundvagn. Vilka av följande kan tänkas bli metoder i ett kundvagns-objekt?
- lägga ner en vara i kundvagnen
- beräkna totalpriset för alla varor i kundvagnen
- räkna ut dagens vinst för internetbutiken
Svar:Alla utom sista alternativet - det hör inte till själva kundvagnen.
Konstruktorn
Konstruktorn är en speciell metod som man skriver för att initiera objekt, dvs ge objektets attribut de värden de ska ha från början. Konstruktorn anropas automatiskt varje gång ett objekt skapas. I Python måste man döpa sin konstruktor till __init__ (alltså init med två understrykningstecken både före och efter).
Konstruktorn kommer att se ut så här:
def __init__(self, djurnamn): self.namn = djurnamn self.skick = 0
Den här konstruktorn har två parametrar, self (som ju alltid måste vara med)
och djurnamn. Raden self.namn = djurnamn
skapar attributet namn och
initierar det till värdet av parametern djurnamn. På samma sätt skapar
raden self.skick = 0
attributet skick och initierar
det till noll. Varje gång man gör ett nytt objekt kommer konstruktorn att anropas.
Fråga: Vilket av följande måste en konstruktor ha?
- parametern self
- en parameter för varje attribut
- ett returvärde
Svar:Parametern self är det enda som måste vara med. Attributen kan få värden via parametrar (som namn ovan), men det är inte nödvändigt. Konstruktorn ska inte ha något returvärde.
Klassen
För att kunna skapa ett objekt måste man först definiera en klass. Det är i klassen man skriver de metoder som objektet ska ha. Klasser brukar ha namn som börjar med versal, så att man lätt ska kunna se att det är en klass. Så här långt har vi hunnit i vår husdjursklass hittills:
class Husdjur(object): # Ett virtuellt husdjur # Konstruktorn def __init__(self, djurnamn): self.namn = djurnamn self.skick = 0 # Ger husdjuret bannor. Skick minskas. def banna(self): print print "- Fy på dig", self.namn, "!" self.skick -= 3
Med en klass är det likadant som med en funktion - det händer inget förrän man använder den i huvudprogrammet. För att skapa ett Husdjurs-objekt kan vi skriva:
djur = Husdjur("Muffin")
Det som händer här är att konstruktorn __init__
anropas, så att attributen skapas och initieras. Sen returneras
ett Husdjurs-objekt, som lagras i variabeln djur
Nu har vi ett husdjursobjekt i variabeln djur
. Hur
anropar vi en av djurets metoder? Just nu finns bara metoden
banna
att välja på:
djur.banna()
När vi vill komma åt ett attribut inuti klassen använder vi ju en punkt, och ett liknande skrivsätt använder man alltså när man vill anropa en metod från ett objekt.
Fråga: Kan man skriva Husdjur.banna()?
Svar:Nej, man kan bara banna ett husdjursobjekt, inte hela klassen.
Exempel: Husdjursprogrammet
Här följer hela programmet, först Husdjurs-klassen, och sedan huvudprogrammet. Lägg märke till att alla metoderna i klassen är indenterade.
class Husdjur(object): # Ett virtuellt husdjur # Konstruktorn, initierar attributen namn och skick. def __init__(self, djurnamn): self.namn = djurnamn self.skick = 0 # Visar husdjurets namn och skick def visaSkick(self): print self.namn, "är ", if self.skick > 5: print "glad: (*_*)" elif self.skick > 0: print "trött: (-z-)" else: print "hungrig: (*o*)" print # Ger husdjuret bannor. Skick minskas. def banna(self): print print "- Fy på dig", self.namn, "!" self.skick -= 3 # Ger husdjuret mat. Skick ökar. def mata(self, mat): print for i in range(mat): print "GLUFS", self.skick += mat # Leker med husdjuret. Skick kan öka eller minska. def leka(self): print if self.skick < 0: self.skick -= 1 print self.namn, " vill inte leka." else: self.skick += 1 print "~~~~~~~~~~~ WHEEEEEEE! ~~~~~~~~~~~" # Skriver ut avskedet. def avsked(self): print print "Hejdå,", self.namn, "kommer att sakna dig!" # Här slutar Husdjursklassen # -------- Här börjar huvudprogrammet ----------- djurnamn = raw_input("Vad vill du döpa ditt husdjur till? ") djur = Husdjur(djurnamn) djur.visaSkick() svar = raw_input(" Vill du \n banna \n mata \n leka med \n ditt husdjur? " ) while svar: if svar[0]=="m": bullar = input("Hur många bullar? ") djur.mata(bullar) elif svar[0]=="b": djur.banna() elif svar[0]=="l": djur.leka() else: print "Hursa? " djur.visaSkick() svar = raw_input(" Vill du \n banna \n mata \n leka med \n ditt husdjur? " ) djur.avsked()
Provkör programmet och svara på följande frågor.
- Fråga: Hur många objekt skapas i programmet?
Svar:Bara ett - variabeln djur.
- Fråga: När metoden visaSkick skriver ut att husdjuret är trött - vilka värden har attributet skick då?
Svar:Attributet skick har något av värdena 1,2,3,4 eller 5
- Fråga: Hur avslutar man programmet?
Svar:När man trycker på Retur avslutas programmet. Lägg gärna till en print-sats som upplyser användaren om det!
- Fråga: Hur många metoder finns det i klassen Husdjur?
Svar:Det finns sex metoder, inklusive konstruktorn.
- Fråga: Kan man få programmet att krascha?
Svar:Javisst, prova att skriva tre (istället för 3) när du matar husdjuret med bullar. Här skulle det behövas lite felhantering!
Test
TODO
Inlämningsuppgift 3
TODO