Fler exempel med klasser
Följande exempel består av två klasser. Klassen Punkt
är en modell för en punkt i ett tvådimensionellt rum. Klassen Stracka
är en modell för ett linjesegment mellan två punkter. Koden nedan är kommenterad, läs gärna kommentarerna för att förstå hur klasserna fungerar.
import math
class Punkt:
""" Klassen representerar en punkt i ett tvådimensionellt rum """
def __init__(self, x: float, y: float):
# Attributen är offentliga, eftersom vilket värde som helst kan användas som värde för x och y.
self.x = x
self.y = y
# Denna klassmetod returnerar en ny punkt vid origo (0, 0)
# Det är möjligt att returnera en ny instans av klassen inifrån klassen
@classmethod
def origo(cls):
return Punkt(0, 0)
# Klassmetoden skapar en ny punkt baserad på den givna punkten
# Den nya punkten är en spegelbild av den givna punkten på en eller båda axlarna.
# Till exempel är punkten (1, 3) speglad på x-axeln (1, -3)
@classmethod
def spegelbild(cls, punkt, spegla_x: bool, spegla_y: bool):
x = punkt.x
y = punkt.y
if spegla_x:
y = -y
if spegla_y:
x = -x
return Punkt(x, y)
def __str__(self):
return f"({self.x}, {self.y})"
class Stracka:
""" Klassen modellerar en sträcka i ett tvådimensionellt rum """
def __init__(self, borjan: Punkt, slut: Punkt):
# Dessa attribut är offentliga eftersom två valfria punkter kan accepteras
self.borjan = borjan
self.slut = slut
# Denna metod använder Pythagoras sats för att beräkna längden på sträckan
def langd(self):
summa = (self.slut.x - self.borjan.x) ** 2 + (self.slut.y - self.borjan.y) ** 2
return math.sqrt(summa)
# Metoden returnerar mitten av sträckan
def medelpunkt(self):
medelx = (self.borjan.x + self.slut.x) / 2
medely = (self.borjan.y + self.slut.y) / 2
return Punkt(medelx, medely)
def __str__(self):
return f"{self.borjan} ... {self.slut}"
punkt = Punkt(1,3)
print(punkt)
origo = Punkt.origo()
print(origo)
punkt2 = Punkt.spegelbild(punkt, True, True)
print(punkt2)
stracka = Stracka(punkt, punkt2)
print(stracka.langd())
print(stracka.medelpunkt())
print(stracka)
(1, 3) (0, 0) (-1, -3) 6.324555320336759 (0.0, 0.0) (1, 3) ... (-1, -3)
Standardvärden för parametrar
I Python-programmering kan du i allmänhet ange ett standardvärde för alla parametrar. Standardvärden kan användas i både funktioner och metoder.
Om en parameter har ett standardvärde behöver du inte inkludera ett värde som ett argument när du anropar funktionen. Om ett argument anges ignoreras standardvärdet. Om inte, används standardvärdet.
Default-värden används ofta i konstruktörer. Om man kan förvänta sig att all information inte är tillgänglig när ett objekt skapas är det bättre att inkludera ett standardvärde i definitionen av konstruktörsmetoden än att tvinga klienten att ta hand om problemet. Detta gör det enklare att använda klassen ur klientens synvinkel, men det säkerställer också objektets integritet. Med ett fastställt standardvärde kan vi t.ex. vara säkra på att ett "tomt" värde alltid är detsamma, såvida inte klienten specifikt vill ange något annat. Om ett standardvärde inte anges är det upp till kunden att tillhandahålla ett "tomt" värde. Det kan t.ex. vara en tom sträng ""
, det speciella tomma objektet None
eller strängen "inte angivet"
.
Låt oss ta en titt på ännu en klass som representerar en studerande. När ett nytt Studerande-objekt skapas måste klienten ange ett namn och ett studerandenummer. Studerandenumret är privat och ska inte ändras i efterhand. Dessutom har ett Studerande-objekt attribut för studiepoäng och anteckningar, vilka har standardvärden som anges i konstruktorn. Nya värden kan skickas som argument till konstruktören, men de kan också utelämnas så att standardvärdena används istället. Titta gärna på kommentarerna i koden för att bättre förstå vad varje metod gör.
class Studerande:
""" Modellerar en endaste studerande """
def __init__(self, namn: str, studerandenummer: str, studiepoang:int = 0, anteckningar:str = ""):
# Kallar sättar-metoden
self.namn = namn
if len(studerandenummer) < 5:
raise ValueError("Studerandenumret ska ha minst 5 tecken")
self.__studerandenummer = studerandenummer
# Kallar sättar-metoden
self.studiepoang = studiepoang
self.__anteckningar = anteckningar
@property
def namn(self):
return self.__namn
@namn.setter
def namn(self, namn):
if namn != "":
self.__namn = namn
else:
raise ValueError("Namnet kan inte vara tomt")
@property
def studerandenummer(self):
return self.__studerandenummer
@property
def studiepoang(self):
return self.__studiepoang
@studiepoang.setter
def studiepoang(self, sp):
if sp >= 0:
self.__studiepoang = sp
else:
raise ValueError("Studiepoäng kan inte vara ett negativt tal")
@property
def anteckningar(self):
return self.__anteckningar
@anteckningar.setter
def anteckningar(self, anteckningar):
self.__anteckningar = anteckningar
def sammanfattning(self):
print(f"Studerande {self.__namn} ({self.studerandenummer}):")
print(f"- studiepoäng {self.__studiepoang}")
print(f"- anteckningar: {self.anteckningar}")
# Skickar endast namnet och studerandenumret
studerande1 = Studerande("Sam Studerande", "12345")
studerande1.sammanfattning()
# Skickar namnet, studerandenummer och studiepoäng
studerande2 = Studerande("Saul Studerande", "54321", 25)
studerande2.sammanfattning()
# Skickar alla uppgifter
studerande3 = Studerande("Sara Studerande", "99999", 140, "tillägstid i tenter")
studerande3.sammanfattning()
# Skickar anteckningar, men inte studiepoäng
# Obs: parametern måste nu bli namngiven när argumenten inte är i ordning
studerande4 = Studerande("Saga Studerande", "98765", anteckningar="avlägsen studieår 20-21")
studerande4.sammanfattning()
Studerande Sam Studerande (12345):
- studiepoäng 0
- anteckningar:
Studerande Saul Studerande (54321):
- studiepoäng 25
- anteckningar:
Studerande Sara Studerande (99999):
- studiepoäng 140
- anteckningar: tillägstid i tenter
Studerande Saga Studerande (98765):
- studiepoäng 0
- anteckningar: avlägsen studieår 20-21
OBS: Det finns ingen sättar-metod för attributet studerande_nummer
eftersom det inte är meningen att studerandenumret ska ändras.
Det finns en ganska betydande hake när man använder standardvärden för parametrar. Följande exempel som modellerar ännu en typ av studerande kommer att belysa detta mer:
class Studerande:
def __init__(self, namn, gjorda_kurser=[]):
self.namn = namn
self.gjorda_kurser = gjorda_kurser
def tillsatt_prestation(self, kurs):
self.gjorda_kurser.append(kurs)
studerande1 = Studerande("Sam Studerande")
studerande2 = Studerande("Saul Studerande")
studerande1.tillsatt_prestation("ItP")
studerande1.tillsatt_prestation("Tira")
print(studerande1.gjorda_kurser)
print(studerande2.gjorda_kurser)
['ItP', 'Tira'] ['ItP', 'Tira']
Om du lägger till slutförda kurser i Sams lista läggs dessa kurser också till i Sauls lista. Faktum är att dessa två är exakt samma lista, eftersom Python återanvänder referensen som lagras i standardvärdet. Att skapa de två nya Studerande-objekten i exemplet ovan är likvärdigt med följande:
kurser = []
studerande1 = Studerande("Sam Studerande", kurser)
studerande2 = Studerande("Saul Studerande", kurser)
Standardvärdena för parametrar bör aldrig vara instanser av mer komplicerade, föränderliga datastrukturer, t.ex. listor. Problemet kan kringgås genom att göra följande ändringar i konstruktorn för klassen Studerande
:
class Studerande:
def __init__(self, namn, gjorda_kurser=None):
self.namn = namn
if gjorda_kurser is None:
self.gjorda_kurser = []
else:
self.gjorda_kurser = gjorda_kurser
def tillsatt_prestation(self, kurs):
self.gjorda_kurser.append(kurs)
studerande1 = Studerande("Sam Studerande")
studerande2 = Studerande("Saul Studerande")
studerande1.tillsatt_prestation("ItP")
studerande1.tillsatt_prestation("Tira")
print(studerande1.gjorda_kurser)
print(studerande2.gjorda_kurser)
['ItP', 'Tira'] []
Den stora finalen
Fastän följande övning avslutar den här delen av materialet, så har de tekniker som krävs för att lösa den redan behandlats i avsnittet som heter Objekt som attribut. Du behöver inte använda @property
-dekoratorn eller standardvärden för parametrar i den här övningen. Den här övningen är mycket lik övningarna "en presentask" och "den kortaste personen i rummet".
Svara avslutningsvis på följande frågeformulär:
Log in to view the quiz
Se dina poäng genom att klicka på cirkeln nere till höger av sidan.