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)
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)
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)
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))
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)
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)
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()
Se dina poäng genom att klicka på cirkeln nere till höger av sidan.