1 of 55

Föreläsning 6

Objektorienterad programmering

2 of 55

Dagens agenda

  1. Återkoppling från kursnämndsmötet
  2. Intro till objektorienterad programmering
  3. Klassdefinition & objekt
  4. Hantera flera objekt
    1. Spara objekten
    2. Jämföra & sortera objekten
  5. Publika & privata attribut samt klass variabler
  6. Större program
  7. Arv och överlagring

2

3 of 55

Återkoppling från kursnämndsmötet

  • Överlag rätt nöjda, kul!
  • Oklart kring KS:ar i P3 - jag återkommer!
  • Jag ska försöka tala om vilken slide jag är på i ppt:n för de i zoom.
  • Ni får jättegärna plugga tillsammans och hjälpa varandra! Men visa inte hela lösningar (tex. skicka inte filen med lösningen).
  • När ska labbarna redovisas?
    • Jag har föreslagit datum som jag tror kommer passa många, men det är helt upp till er att planera så att ni hinner bli klara. Ni måste inte redovisa under omtentaveckan (men det kan vara smidigt om ni inte har andra kurser så blir ni klara innan jul).
  • Labb 0 var svårare för några än vad jag hade förstått, ska kolla på det tills nästa år!

3

4 of 55

Objektorienterad programmering

4

5 of 55

Objektorienterad programmering

Objektorienterad programmering är ett sätt att samla data (variabler) med funktioner som hör till datan i en klass.

5

En klass kan ses som en ritning eller mall för det den beskriver. Den data som hör ihop med en klass kallar vi för attribut och de funktioner som hör ihop med klasserna kallar vi för metoder

Attributen är alltså någon sorts egenskap som klassen har, medan metoderna är saker som klassen kan göra eller saker vi kan göra med vår objekt.

6 of 55

Klasser & Objekt

6

Snigelobjekt1

class Pepparkakssnigel

Skapar snigelobjekt

Snigelobjekt2

Snigelobjekt3

7 of 55

Klasser & Objekt

7

class Snigel

mario.hoppa(1)

Låt snigeln ”mario” hoppa ett skutt genom att kalla på metoden hoppa med parametern 1.

8 of 55

Exempel på metoder som du redan sett

8

Klass

Exempel på objekt

Metodanrop

list

lista = [23, 54, 12]

lista.sort()

dictionary

dict = {‘katt’: ‘cat’, ‘hund’ : ‘dog’}

dict.keys()

9 of 55

Skapa egna klasser

9

10 of 55

Att bygga en egen klass

Vi bestämmer vilka egenskaper objekten ska ha och vad som kan göras med dem med hjälp av metoderna i klassen. På så sätt kan vi bygga våra egna datastrukturer.

10

class Spelare:

def __init__(self, namnet, poängen):

self.namn = namnet

self.poäng = poängen

def mer_poäng(self):

self.poäng += 1

Vilka egenskaper ska objekten ha?

Vad ska vi kunna göra med objekten?

11 of 55

Att skapa objekt med attribut

Vi kan skapa objekt genom att skriva klassens namn och skicka med värdena på de attribut (egenskaper) som behövs som parametrar. Tänk på att spara objektet på någon sätt, en variabel eller i en lista är ofta lämpligt.

11

spelare1 = Spelare(”Lille-skutt", 23)

spelare2 = Spelare(”Skal-man", 25)

Vi kommer åt värdena i attributen genom objekten:

spelare1.namn 

spelare2.poäng

12 of 55

Konstruktorn: __init__

Det är i konstruktorn (__init__) som vi initierar värden på attributen, den anropas automatiskt när vi skapar objekt:

12

spelare1 = Spelare(”Lille-skutt", 23)

spelare2 = Spelare(”Skal-man", 25)

class Spelare:

def __init__(self, namnet, poängen):

self.namn = namnet

self.poäng = poängen

När vi skriver så här anropas __init__ (utan att vi explicit behöver skriva __init__())

13 of 55

Metoder

Alla metoder i klassen måste ha self som parameter. self står för objektet själv, det som metoden anropas på och skickas därför inte med i anropet.

13

class Spelare:

def __init__(self, namnet, poängen):

self.namn = namnet

self.poäng = poängen

def mer_poäng(self):

self.poäng += 1

spelare1 = Spelare(”Lille-skutt", 23)

spelare1.mer_poäng()

Nu kommer Lille-skutts poäng uppdateras med +1

14 of 55

Att skriva ut objekt

14

class Spelare:

def __init__(self, namnet, poängen):

self.namn = namnet

self.poäng = poängen

def mer_poäng(self):

self.poäng += 1

spelare1 = Spelare(”Lille-skutt", 23)

print(spelare1)

Det här kommer bli lite otydligt…

15 of 55

Vi behöver en __str__ metod!

15

class Spelare:

def __init__(self, namnet, poängen):

self.namn = namnet

self.poäng = poängen

def __str__ (self):

return self.namn + " fick " + str(self.poäng) + " poäng"

def mer_poäng(self):

self.poäng += 1

__str__ talar om hur objektet ska se ut när det skrivs ut.

__str__ MÅSTE returnera en sträng. Det är en fördefinerad metod som ska bete sig på samma sätt i alla klasser.

16 of 55

Fördefinierade metoder: __init__ & __str__

16

Dessa anropas automatiskt när vi agerar på olika sätt. �

Alla klasser bör ha dessa två metoder (__str__ kan dock bytas ut mot __repr__) med undantag från abstrakta klasser som bara samlar funktioner men där vi inte tänkt skapa objekt. (Vi kommer dock troligtvis inte ha några abstrakta klasser i den här kursen).�

  • __init__ kallas för konstruktorn och anropas när vi skapar klassen (den hjälper till att konstruerar objekt)
  • __str__ anropas automatiskt när vi försöker skriva ut objektet med print() eller om vi försöker göra om objektet till en sträng med str().

17 of 55

Polymorfism

17

Med polymorfism menas här möjligheten att ha en metod med samma namn i olika klasser och få olika resultat.

Exempel:  metoden __str__

print(objekt)

skriver ut olika saker beroende på objektets klass

Jättemånga klasser har en __str__-metod men de skriver nästan alltid ut olika saker!

18 of 55

En klass med kontakterna i telefonboken!

18

class Kontakt:

"""En klass som representerar en kontakt i en telefonbok"""

def __init__(self, namn, tel, pnr):

self.namn = namn

self.telefonnummer = tel

self.pnr = pnr

def __str__(self):

"""Returnerar en sträng som är redo att skrivas in i textfilen."""

return self.namn + ', ' + self.telefonnummer + ', ' + self.pnr + '\n'

Observera: vi behöver inte döpa attributen till samma sak som parametrarna!

Attributet heter telefonnummer men namnet på parametern som vi lägger in när vi skapar objekt kallas för tel.

Vilka attribut har Kontakt?

19 of 55

Namnge klasser

19

  1. Klassens namn ska ha en stor begynnelsebokstav för att enkelt kunna skilja den från en funktion.
  2. Även om vi tänk ha flera objekt så är det bra att döpa klassen till vad ett objekt av klassen representerar. Vi skapa ett objekt i taget med anropet till konstruktorn.
  3. Metoder döps efter vad de gör.

Komihåg: vi kallar på både funktioner och klasser genom att skriva deras namn följt av en parentes!

Vi skapade flera sniglar, men varje snigel var av klassen snigel()

Samma som för funktioner!

20 of 55

Funktioner

Funktioner är definierade utanför klassen och generella.

T.ex. vill vi ha funktioner för felhantering, menyn, inläsning från fil, skapande av objekt och för vårt huvudprogram.

Metoder

Metoder är definierade inne i klassen och specifika för klassen och dess objekt.

En grundregel är ett en metod bör använda objektets attribut på något sätt.

20

vs.

21 of 55

Skapa egna metoder

21

Vad kommer skrivas ut?

22 of 55

Använd en menyfunktion

22

I många av våra program vill vi ha en meny, men den bör vara utanför klassen.

Funktioner i menyn kommer dock troligtvis använda metoder i klassen.

23 of 55

Varför är klasser bra att ha?

23

Klasser är ett sätt att strukturera kod. De gör det lättare att återanvända kod och tillåter oss att skapa egna datastruktuer vilket gör det lättare att hålla koll på våra värden.

Vissa språk är byggda kring idéen om klasser, de kallas för objektorienterade. Java är ett sådant språk.

Python uppmuntrar till att använda klasser, men som ni märkt går det bra att programmera i python utan att använda klasser.

24 of 55

Att ha flera objekt

24

25 of 55

Många objekt

25

Klasser är väldigt bra om vi vill skapa många objekt (vilket vi ofta vill göra).

Tidigare har vi använt matriser (listor i listor) eller dictionaries med värden som är listor, för att kunna lagra flera värden, men nu kan vi istället lagra objekt i listor. Det blir då lättare att hålla koll på vilka värden som finns, eftersom vi har attribut istället där vi kan lagra olika saker.

26 of 55

Spara flera objekt

26

Låt oss titta på våra kontaktobjekt igen!

Observera: vi måste spara objekten någon stans! I detta fall i ett dictionary.

27 of 55

Skriva ut objekt i en lista eller dictionary

27

class Tal():

def __init__(self, tal):

self.tal = tal

def __str__(self):

return "från str: " + str(self.tal)

def __repr__(self):

return "från repr: " + str(self.tal)

def main():

lista=[]

dict = {}

for i in range(5):

objekt = Tal(i)

lista.append(objekt)

dict[i] = objekt

print('lista', lista)

print('dict', dict)

print('Element i lista:')

for element in lista:

print(element)

print('\nElement i dictionary:')

for nyckel in dict.keys():

print(dict[nyckel])

main()

Kolla vilken strängmetod som används för vilken utskrift!

28 of 55

Läsa från och spara på fil

Precis som vi sparat data på fil och läst från fil tidigare kan vi vilja göra detta även med data som vi lagrar i objekt.

28

def skapa_telefonbok(filnamn):

telefonbok = {}

with open(filnamn, 'r') as fil:

for rad in fil:

kontakt = rad.split(',')

namn = kontakt[0].strip()

tel = kontakt[1].strip()

pnr = kontakt[2].strip()

kontakt = Kontakt(namn, tel, pnr)

telefonbok[namn] = kontakt

return telefonbok

def spara_telefonbok(filnamn, telefonbok):

with open(filnamn, 'w') as fil:

for nyckel in telefonbok.keys():

fil.write(str(telefonbok[nyckel]))

29 of 55

Jämföra objekt

29

För att kunna sortera våra objekt behöver vi definiera hur de kan jämföras. Det kan vi göra med hjälp av de inbyggda funktionerna __lt__, __gt__ och __eq__.

  • __lt__ - less than
  • __gt__ - greater than (behövs inte om vi har __lt__)
  • __eq__ - equal, använder vi för att tala om när objekt är lika

def __lt__ (self, other):

if self.namn < other.namn:

return True

else:

return False

När kan det vara bra att kunna jämföra objekt?

  • Användbart i olika villkor som krävs för programmets logik.
  • Nödvändigt för att kunna sortera objekten!

30 of 55

Jämföra objekt

30

Vi definierar att bilarna ska jämföras baserat på snabbhet

Det är viktigt att definiera __lt__ eller __gt__ för att kunna använda sort() om objekten ligger i en lsita.

31 of 55

Olika typer av attribut och variabler

31

32 of 55

Publika och privata attribut

Vi väljer om vi vill definiera attribut som publika eller privata.

  • Publika attribut kommer vi enkelt åt och kan ändra utanför klassen.
  • Privata attribut kan vi bara nå på ett smidigt sätt inne klassen. I Python skapar vi privata attribut genom att skriva __ framför attributnamnet.

32

class Kontakt:

"""En klass som representerar en kontakt i en telefonbok"""

def __init__(self, namn, tel, pnr):

self.namn = namn

self.telefonnummer = tel

self.__personnummer = pnr

gurra = Kontakt('Katten Gustaf', '098 889 98', '1976-01-08')

print(gurra.namn)

print(gurra._personnummer)

33 of 55

Komma åt privata attribut – poängen är att vi inte ska komma åt dem!

För att komma åt privata attribut utanför klassen behöver vi definiera åtkomstmetoder (get) och ändringsmetoder (set).

  • Get-metoden (du kan döpa den till något annat) returnerar värdet på attributet.
  • Set-metoden uppdaterar värdet på attributet.

33

class Kontakt:

"""En klass som representerar en kontakt i en telefonbok"""

def __init__(self, namn, tel, pnr):

self.namn = namn

self.telefonnummer = tel

self.__personnummer = pnr

def uppdatera_personnummer(self, ny_pnr):

self.__personnummer = ny_pnr

def visa_personnummer(self):

return self.__personnummer

uppdatera_personnummer är en set-metod

visa_personnummer är en get-metod

34 of 55

När är det bra att ha privata attribut?

Ibland vill vi inte kunna ändra vissa attribut i andra klasser, det kan förstöra logiken i vårt program.

Privata attribut är ett sätt att kapsla in koden.

34

Detta kommer bli användbart i vår!

35 of 55

Klassatribut

35

class Långord:

VOKALER = "aeiouyåäö" # VOKALER är ett klassattribut

def __init__(self, ordet):

self.ordet = ordet

def antal_vokaler(self):

antal = 0

for bokstav in self.ordet:

if bokstav in Långord.VOKALER:

antal += 1

return antal

def main():

ordobjekt = Långord("boendeparkeringstillstånd")

print(ordobjekt.antal_vokaler())

main()

Obs.

klassattribut kan vara både KONSTANTER och variabler!

36 of 55

Klassatribut

  • Ett klassattribut är en variabel eller konstant som är gemensam för alla objekt i en klass.
  • Om värdet ändras för ett objekt ändras det för alla.
  • Klassattribut går också att komma åt oberoende av objekten.

36

Du kan exempelvis komma åt VOKALER (från exemplet innan) genom att skriva Långord.VOKALER utanför klassen.

37 of 55

Större program

37

38 of 55

Större program

I större program behöver vi ofta fler klasser för att enklare strukturera upp koden.

Om vi skriver ett program för en hotellkedja behöver vi kanske en klass som representerar ett hotell och en annan klass som representerar ett rum…

38

Hotell-klassen

Attribut

  • chef (str)
  • adress (str)
  • rummslista (lista)
  • frukostbufe (bool)

Rum-klassen

Attribut

  • rumsnummer (int)
  • storlek (int)
  • antal_sängar (int)
  • uthyrt (bool)

Det är vanligt att lägga alla klasser i en separat fil

39 of 55

Lägga klasserna i en separat fil…

Det är vanligt att göra en egen modul av klasserna (lägga dem i en separat fil) som du kan importera in i ditt huvudprogram.

39

if __name__ == "__main__":

main()

Om du vill testa klassen så är det väldigt bra att använda if __name__ == ”__main__” syntaxen!

Komihåg: koden som ligger under if __name__ = ”__main__” kommer bara att köras om du kör programfilen som kodraden ligger i, inte om du importerar filen!

40 of 55

Återanvänd din kod!

  • Samma satser om igen? 
    • Skriv en slinga eller en funktion!

  • Samma funktioner i nytt program?
    • Skriv en modul och importera den!

  • Samma data som skickas in i alla funktionerna?
    • Skriv en klass!

  • Flera klasser med liknande attribut och metoder?
    • Skriv en superklass och låt klasserna ärva från den!

40

41 of 55

Arv

41

Kapitel 10 i Möbius

42 of 55

Arv

Subklassen ärver alla attribut och metoder från superklassen!

42

class Subklass(Superklass):

class Katt(Djur):

Exempel

43 of 55

Superklassen object

Alla klasser som vi skriver ärver från superklassen object!

43

class Minklass:

class Minklass(object):

Om vi definierar en klass som heter Minklass

Så kommer Python översätta det till Minklass(object)

44 of 55

Rum-klassen

Lyxsvit

44

Attribut

  • rumsnummer (int)
  • storlek (int)
  • antal_sängar (int)
  • uthyrt (bool)

Metoder

  • __init__
  • __str__
  • hyra_ut
  • är_ledigt

Det är vanligt med metoder som frågar om ett attribut ”är”. Dessa returnerar True eller False.

Attribut

  • rumsnummer (int)
  • storlek (int)
  • antal_sängar (int)
  • uthyrt (bool)
  • havsutsikt (bool)
  • fler_rum (bool)

Metoder

  • __init__
  • __str__
  • hyra_ut
  • är_ledigt

Observera: lyxsviten har ytterligare några attribut

45 of 55

Överlagring

När vi låter en klass ärva så ärvs alla attribut och metoder vilket är bra. Men i vissa fall vill vi kanske att attributen och/eller metoderna ska bete sig lite annorlunda, då behöver vi överlagra dem.

Det alltid den metoden närmast som är den som gäller.

45

def __str__(self):

sträng = 'Rum ' + self.rumsnummer + ' är '

if self.uthyrt:

sträng += 'uthyrt.'

else:

sträng += 'ledigt.'

def __str__(self):

sträng = 'Svit ' + self.rumsnummer + ' är '

if self.uthyrt:

sträng += 'uthyrt.'

else:

sträng += 'ledigt.'

Rum

Lyxsvit

Varför är dessa olika?

46 of 55

Överlagring

Det alltid den metoden närmast som är den som gäller.

46

Object – klassen som omsluter

alla andra klasser

Rum

Lyxsvit

Om vi har ett lyxsvitobjekt så kommer lyxsvit-str-metoden köras om vi skriver ut objektet

47 of 55

Komma åt superattributen i subklassen

För att slippa initialisera superklassens attribut igen kan vi komma åt dem genom att använda funktionen super().

47

def __init__(self, nr, storlek=2, sängar=1, uthyrt=False):

self.rumsnummer = nr

self.storlek = storlek

self.antal_sängar = sängar

self.uthyrt = uthyrt

def __init__(self, nr, storlek, sängar, uthyrt, havsutsikt, fler_rum):

super().__init__(nr, storlek, sängar, uthyrt)

self.havsutsikt = havsutsikt

self.fler_rum = fler_rum

Rum

Lyxsvit

48 of 55

Arv med geometriska former

48

a

a

a

b

a

b

h

Parallellogram:

Area = h*b

Omkrets = 2*(a+b)

Rektangel:

Area = a*b

Omkrets = 2*(a+b)

Kvadrat:

Area = a*a

Omkrets = 4*a

Vad ärver från vad???

49 of 55

Arv med geometriska former

  • Parallellogram är den mest generella figuren - den får bli superklass
  • Rektangel är en sorts parallellogram med räta vinklar - vi låter den vara subklass till Parallellogram
  • Kvadrat är en sorts rektangel med lika sidor - den får vara subklass till Rektangel

49

50 of 55

Parallellogram

50

class Parallellogram(object):

def __init__(self, a, b, h):

self.kant1 = a

self.basKant = b

self.hojd = h

def area(self):

return self.hojd*self.basKant

def omkrets(self):

return 2*(self.kant1+self.basKant)

a

b

h

51 of 55

Rektangel

51

from parallellogram import Parallellogram

class Rektangel(Parallellogram):

def __init__(self, a, b):

self.kant1 = a

self.basKant = b

def area(self):

return self.kant1*self.basKant

a

b

Varför räcker det med att definiera area (förut hade vi med omkrets)?

52 of 55

Kvadrat

52

from rektangel import Rektangel

class Kvadrat(Rektangel):

def __init__(self,a):

self.kant1 = a

self.basKant = a

a

a

Varför behöver vi inte definiera area och omkrets?

53 of 55

Arv från en inbyggd klass - Exception

53

class Sjutton(Exception):

pass

def skriv_tal(antal):

for i in range(antal):

if i == 17:

Raise Sjutton

else:

print(i)

def main():

try:

skriv_tal(25)

except Sjutton:

print("Det var som sjutton!")

main()

Vad händer här?

Vi ärver alla egenskaper från klassen Exception, men kallar vårt exception (hemmasnickrade undantag för Errors) Sjutton

54 of 55

Arv från en inbyggd klass - list

54

class Inköpslista(list):

def __str__(self):

sträng = ""

for vara in self:

sträng += " * " + str(vara) + "\n"

return sträng

Vad händer om vi skapar en lista med Ägg, Smör och Mjölk?

55 of 55

Labb 2

Lösenordskollaren

55

Deadline: Fredag 24/11