Osa 8

Klasser och objekt

I föregående avsnitt arbetade vi med listor, tupler, ordlistor och strängar. Dessa är alla ganska speciella fall i Python-programmering. Pythons syntax har en unik, fördefinierad metod för att skapa ett objekt som tillhör var och en av dessa typer:

# Listor deklareras med hakparenteser
lista = [1,2,3]

# Strängar deklareras med citationstecken
strang = "Hej alla!"

# Ordlistor deklareras med klammerparenteser
ordlista = {"ett": 1, "två:": 2}

# tuplar deklareras med parenteser
tupel = (1,2,3)

När någon annan typ av objekt deklareras måste vi anropa en speciell initialiseringsfunktion som kallas konstruktor. Låt oss ta en titt på hur man arbetar med bråk genom Fraction-klassen.

# vi använder klassen Fraction från modulen fractions
from fractions import Fraction

# vi skapar några nya bråktal
halv = Fraction(1,2)

tredjedel = Fraction(1,3)

tredje = Fraction(3,11)

# vi skriver ut
print(halv)
print(tredjedel)
print(tredje)

# vi kan också räkna med bråk
print(halv + tredjedel)
Exempelutskrift

1/2 1/3 3/11 5/6

Som du kan se ser metodanrop för konstruktorer lite annorlunda ut än de vanliga metodanrop som vi har stött på tidigare. För det första är de inte kopplade till något objekt med punktnotation (eftersom konstruktoranropet behövs för att skapa ett objekt i första hand). Konstruktorsmetoden skrivs också med stor bokstav: [half = Fraction(1,2)]. Låt oss titta närmare på hur objekt konstrueras genom att bekanta oss med begreppet klass.

En klass är ritningen på ett objekt

Vi har redan använt termen klass i materialet många gånger. I exemplet ovan importerade vi t.ex. klassen Fraction från modulen fractions. Nya bråktalsobjekt skapades genom att kalla på konstruktorsmetoden för klassen Fraction.

En klassdefinition innehåller strukturen och funktionaliteterna för alla objekt som representerar den givna klassen. Därför kallas klasser ibland för objektens ritningar. En klassdefinition berättar alltså för oss vilken typ av data ett objekt innehåller och definierar de metoder som kan användas på objektet. Objektorienterad programmering är ett programmeringsparadigm där programmets funktionalitet är knuten till användningen av klasser och objekt som skapas baserat på dessa.

En klassdefinition kan användas för att skapa flera objekt. Som tidigare nämnts är objekt oberoende av varandra. Ändringar som görs i ett objekt påverkar i allmänhet inte de andra objekten som hör till samma klass. Varje objekt har sin egen unika uppsättning av attribut. Det kan vara bra att tänka på denna förenkling av förhållandet mellan klass och objekt:

  • En klass definierar variablerna
  • När ett objekt skapas tilldelas dessa variabler värden

Vi kan alltså använda ett objekt av typen Fraction för att komma åt täljaren och nämnaren i ett bråktal:

from fractions import Fraction

tal = Fraction(2,5)

# Skriv ut täljaren
print(tal.numerator)

# ... och sedan nämnaren
print(tal.denominator)
Exempelutskrift

2 5

Klassdefinitionen för Fraction innehåller deklarationer för variablerna numerator och denominator. Varje objekt som skapas baserat på klassen har sina egna specifika värden som tilldelas dessa variabler.

På samma sätt innehåller objekt som skapats baserat på klassen date sina egna unika värden för datumets år, månad och dag:

from datetime import date

jul = date(2020, 12, 24)
midsommar = date(2020, 6, 20)

# Vi skriver ut bägges månad
print(jul.month)
print(midsommar.month)
Exempelutskrift

12 6

Definitionen av klassen date innehåller deklarationer av variablerna year, month och day. När ett nytt datumobjekt skapas baserat på klassen tilldelas dessa variabler värden. Varje objekt har sina egna unika värden utgående från de tilldelade värdena.

Funktioner som arbetar med objekt

Att skicka ett objekt som ett argument till en funktion borde vara bekant vid det här laget eftersom vi har gjort det redan många gånger i den här kursen. Låt oss ta en titt på följande exempel. Här har vi en funktion som kontrollerar om date-objektet som skickas som argument infaller på en helg:

def redan_veckoslut(dag: date):
    veckodag = dag.isoweekday()
    return veckodag == 6 or veckodag == 7

Denna funktion använder metoden isoweekday, som definieras i klassdefinitionen för klassen date, och returnerar ett heltalsvärde enligt följande: om det angivna datumet är en måndag returnerar den 1, och om det är en tisdag returnerar den 2, och så vidare.

jul = date(2020, 12, 24)
midsommar = date(2020, 6, 20)

print(redan_veckoslut(jul))
print(redan_veckoslut(midsommar))
Exempelutskrift

False True

Metoder vs variabler

När du arbetar med ett objekt av typen date kanske du märker att det finns en liten skillnad mellan hur man kommer åt variablerna i objektet jämfört med hur man anropar objektets metoder:

dag = date(2020, 12, 24)

# vi anropar metoden
veckodag = dag.isoweekday()

# vi använder en variabel
manad = dag.month

print("Veckodag:", veckodag)
print("Månad:", kuukausi)
Exempelutskrift

Veckodag: 4 Månad: 12

Veckodagen som datumet infaller på är tillgänglig via metoden isoweekday:

veckodag = dag.isoweekday()

Detta är ett metodanrop, alltså finns det parenteser efter namnet på metoden. Om du lämnar bort parenteserna uppstår inget fel, men resultatet blir konstigt:

veckodag =  dag.isoweekday
print("Veckodag:", veckodag)
Exempelutskrift

Veckodag: <built-in method isoweekday of datetime.date object at 0x10ed66450>

Månaden för ett date-objekt är en variabel, alltså kan man komma åt det tilldelade värdet med en referens.

manad = dag.month

Lägg märke till att det inte finns parenteser här. Att sätta in parenteser skulle orsaka ett fel, eftersom det inte är frågan om en metod:

manad = dag.month()
Exempelutskrift
Traceback (most recent call last): File "", line 1, in TypeError: 'int' object is not callable
Loading
Loading
Du har nått slutet av den här delen! Fortsätt till nästa del:

Se dina poäng genom att klicka på cirkeln nere till höger av sidan.