Ännu en onsdag, och med det ett nytt avsnitt av…
Förra veckan tittade vi på Objekt, och vi ska spinna vidare lite på det spåret och titta på andra avancerade datatyper.
Ett objekt kommunicerar man med genom metoder, men i praktiken kan man säga att alla avancerade datatyper är en form av objekt även om de inte har några metoder.
I förra inlägget nämnde jag datetime-objektet i Python. Det är ett bra exempel på ett objekt, så jag tänkte att vi ska gå igenom hur vi skulle kunna göra vårt eget!
Först definierar vi attributen:
År, månad, dag, timme, minut, sekund – alla kan lagras som heltal
Och några förslag på metoder:
“lagra nuvarande tid” – hämta datum och klockslag från systemet och lagra dessa i objektet.
“lagra <attribut>” – sätt ett av attributen ovan
“hämta <attribut>” – hämta ett av attributen ovan
“hämta datetime” – returnerar en sträng som representerar hela objektet (såväl datum som klockslag).
“hämta månad som sträng” – returnerar en sträng som motsvarar namnet på månaden, t.ex. “Januari”.
Det mesta här är relativt enkelt. Det handlar om getters och setters, som vi sett tidigare. Det som blir lite mer invecklat är “lagra nuvarande tid”, “hämta datetime” och “hämta månad som sträng” eftersom dessa behöver byggas upp av beräkningar.
Källkod för de enkla bitarna:
class Datumtid: # Konstruktor, tom än så länge men om man anropar den med "true" ska den kunna hämta in och lagra nuvarande tid från systemet. def __init__(self, nu=false): #if nu: <--------------------------- Lägg till senare # SET-metoder def setYear(self, tal): self._year = int(tal) def setMonth(self, tal): self._month = int(tal) def setDay(self, tal): self._day = int(tal) def setHour(self, tal): self._hour = int(tal) def setMinute(self, tal): self._minute = int(tal) def setSecond(self, tal): self._second = int(tal) # GET-metoder def getYear(self): return self._year def getMonth(self): return self._month def getDay(self): return self._day def getHour(self): return self._hour def getMinute(self): return self._minute def getSecond(self): return self._second # Get-metod, string def __str__(self): datum = str(self._year)+"-"+str(self._month)+"-"+str(self._day) tid = str(self._hour)+":"+str(self._minute)+":"+str(self._day) return datum+", "+tid
Nu har vi inga kollar över huvud taget för att kolla att man anger rätt data. År kan vi bortse från, men övriga set-funktioner bör vara begränsade som följer:
Månad (1-12), dag (1-31), timme (<24), minut (<60), sekund (<60). Vi lägger till detta i nästa steg (med något som heter “range”). Nu vill vi skriva en funktion för att hämta in nuvarande tid och lagra i vårt objekt.
För att lösa detta problem kan man göra på olika sätt. Det går att hämta “antalet millisekunder sedan 1970-01-01 kl 00:00:00:000”. Men gör vi det måste vi konvertera ett väldigt stort tal till en stor mängd små tal, vilket är lite bökigt. Särskilt eftersom detta problem redan har lösts smart i Pythons befintliga datetime-objekt! Så vi fuskar lite istället. Vi importerar “datetime”, och anropar datetime.now(), och får då ett datetime-objekt. Detta omvandlar vi sedan för att få en lista innehållande de heltal vi vill ha:
import datetime date = datetime.datetime.now() datelist = list(date.timetuple()) print(str(datelist))
Koden ovan skriver ut en lista, t.ex.: [2014, 11, 5, 10, 16, 41, 2, 309, -1]
De värden vi vill ha är de sex första (se beskrivning av datetime-objektet om du vill veta vad de övriga gör).
Nu ska vi lägga in dessa beräkningar i konstruktorn, för att man ska kunna sätta vårt DatumTid-objekt till nuvarande tidpunkt när det skapas:
def __init__(self, nu=false): if nu: date = datetime.datetime.now() datelist = list(date.timetuple()) this._year = datelist[0] this._month = datelist[1] this._day = datelist[2] this._hour = datelist[3] this._minute = datelist[4] this._second = datelist[5]
Om man nu skapar ett DatumTid-objekt, t.ex. genom att skriva “temp = DatumTid(True)” kommer nuvarande tid hämtas från systemet och lagras i objektet.
Nu har vi ett problem kvar! Vi vill kunna skriva ut månadsnamnet istället för motsvarande siffra. För att göra detta tänkte vi använda oss av en avancerad datatyp, en “hash-tabell”. I Python kallas dessa “Dictionaries”.
Dictionaries
En Dictionary är, enkelt uttryckt, en lista med två värden. Ett sökvärde, och ett datavärde. Om vi döper vår Dictionary till “dict” hämtas datan ut genom att skriva “dict[sökvärde]”.
Vad är då fördelen med Dictionaries/hash-tabeller? Jo, säg att man har en stor mängd data som man vill lagra, och kunna söka snabbt smidigt. Att lägga all denna data i en lång lista är inte så effektivt om man letar efter ett specifikt värde, för om datan t.ex. ligger sist i listan måste man traversera hela listan innan man hittar det.
Det man då kan göra är att skapa en hashfunktion, som på ett eller annat sätt tar en värde från datamängden som invärde och returnerar en nyckel. Om man vill kan man ha mer invecklade nyckelvärden, som i exemplet på hashfunktions-sidan jag länkade, kan man såklart göra så. Men man kan också ha enklare hashnycklar, och de värden vars data råkar ge samma nyckel kan ligga i samma underlista:
“a” –> hash(“a”) –> 1 –> 1 – “a”
“b” –> hash(“b”) –> 1 –> 1 – “a”, “b”
Gör man så här får man fortfarande traversera en lista, men säg att vi hashar hela alfabetet och de övriga bokstäverna får hashnyckel “2”, så blir det lite smidigare beräkningsmässigt att hitta den data man söker.
I vårt fall behöver vi dock inte skapa någon hash-funktion eftersom vi redan vet vilka nycklar vi har och vilken data vi vill ha ut! Därför skapar vi helt enkelt en dictionary som innehåller datan:
import datetime class Datumtid: _months = { 1 : "Januari", 2 : "Februari", 3 : "Mars", 4 : "April", 5 : "Maj", 6 : "Juni", 7 : "Juli", 8 : "Augusti", 9 : "September", 10 : "Oktober", 11 : "November", 12 : "December" } # Konstruktor, om true, lagra nuvarande tid def __init__(self, nu=False): if nu: date = datetime.datetime.now() datelist = list(date.timetuple()) self._year = datelist[0] self._month = datelist[1] self._day = datelist[2] self._hour = datelist[3] self._minute = datelist[4] self._second = datelist[5] # SET-metoder def setYear(self, tal): self._year = int(tal) def setMonth(self, tal): self._month = int(tal) def setDay(self, tal): self._day = int(tal) def setHour(self, tal): self._hour = int(tal) def setMinute(self, tal): self._minute = int(tal) def setSecond(self, tal): self._second = int(tal) # GET-metoder def getYear(self): return self._year def getMonth(self): return self._month def getDay(self): return self._day def getHour(self): return self._hour def getMinute(self): return self._minute def getSecond(self): return self._second # Get-metod, string def __str__(self): datum = str(self._day)+" "+self._months[self._month]+" "+str(self._year) tid = str(self._hour)+":"+str(self._minute)+":"+str(self._day) return datum+", kl "+tid
_months[1] returnerar nu “Januari”. Precis vad vi behövde! Den placeras högst upp i klassen, då det är ett attribut som ska kunna kommas åt från metoderna. I exemplet ovan har jag också justerat utskriftsfunktionen för att skriva ut månadsnamnet istället.
Nu har vi skrivit ett eget, mer invecklat objekt och använt oss av en avancerad datatyp, Dictionary! Vi har också lärt oss hur man definierar hur ett objekt skrivs ut som sträng (__str__(self) ).
Nästa vecka spinner vi vidare lite på ämnet sökning, och tittar på sorteringsfunktioner! Håll ut 😉
Kul att du gillar vår blogg!
Skriv upp dig på vår maillista för att få allt det senaste från m.nu - Nya produkter, kampanjer och mycket mer!
Wohoo! Du är nu med på maillistan!