Vad är arv och klasshierarkier
Vad är arv?
Arv innebär att en klass (subklass) kan ärva kod från en annan klass (superklass). Det betyder att subklassen automatiskt får alla attribut och metoder från superklassen – utan att behöva skriva om dem.
Det är ett sätt att:
- Återanvända kod
- Organisera klasser med gemensamma egenskaper
- Utöka funktionalitet i en mer specifik version av en klass
Exempel: Superklass och subklasser
Vi börjar med en superklass Animal. Sedan skapar vi två subklasser Dog och Cat som ärver från Animal.
# Superklass
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name} makes a sound")
# Subklass
class Dog(Animal):
def bark(self):
print(f"{self.name} says Woof!")
# Subklass
class Cat(Animal):
def meow(self):
print(f"{self.name} says Meow!")
Här är Dog en subklass till Animal och ärver både attributet name och metoden speak().
Använda subklasserna i praktiken
Nu skapar vi objekt från subklasserna och använder både ärvda metoder och deras egna metoder:
dog1 = Dog("Rex")
cat1 = Cat("Misty")
# Ärver metoden från Animal
dog1.speak() # Output: Rex makes a sound
cat1.speak() # Output: Misty makes a sound
# Egna metoder
dog1.bark() # Output: Rex says Woof!
cat1.meow() # Output: Misty says Meow!
När ska man använda arv?
Arv är lämpligt när det finns en ”är en/ett”-relation (på engelska: is a):
- En
Hundär ettDjur. - En
Lärareär enPerson.
Då är det logiskt att skapa en superklass (Djur, Person) och låta andra klasser ärva från den.
Arv gör det enkelt att:
- Organisera kod
- Återanvända funktionalitet
- Undvika upprepningar
När ska man inte använda arv?
Arv kan missbrukas om klasserna inte har en tydlig ”är en/ett”-relation.
Undvik arv när:
- Det bara handlar om delad funktion, men inte en logisk relation. Använd istället komposition (en klass har en annan klass som attribut).
- Subklassen behöver ändra nästan all funktionalitet från superklassen.
- Koden blir svår att förstå – arv kan skapa komplexa beroenden om det inte används tydligt.
Klasshierarkier
När flera klasser är kopplade genom arv kallar vi det en klasshierarki. Det gör det enklare att bygga program där många objekt har gemensamma egenskaper, men också unika delar.
Exempel:
Fordon(superklass)Bil(subklass)Cykel(subklass)Lastbil(subklass)
Överskuggning (Override)
En subklass kan ersätta (överskugga) en metod från superklassen med en egen version.
class Animal:
def speak(self):
print("Some generic animal sound")
class Cat(Animal):
def speak(self):
print("Meow")Här körs Cat-klassens speak() i stället för den som finns i Animal. Det kallas överskuggning, och det är användbart när man vill ändra beteendet hos ärvda metoder.
Översikt
| Begrepp | Förklaring |
|---|---|
| Superklass | Klassen som andra ärver ifrån |
| Subklass | Klassen som ärver egenskaper från en annan |
| Arv | Att en klass får tillgång till en annan klass funktioner och data |
__init__() | Körs automatiskt när ett objekt skapas |
super() | Används i subklassen för att kalla på superklassens metod |
Vad är super() och hur används det?
Varför behöver vi super()?
När en subklass har en egen __init__()-metod, körs inte längre superklassens __init__() automatiskt. Om vi vill att den ska köras också, måste vi anropa den manuellt med super().
Detta är särskilt användbart om superklassen har viktig kod i __init__() eller andra metoder som vi vill återanvända.
Exempel utan super:
class Animal:
def __init__(self, name):
self.name = name
print(f"{name} skapades!")
class Dog(Animal):
def __init__(self, name, breed):
self.name = name # Animal.__init__() körs inte!
self.breed = breedHär skapas ett Dog-objekt, men vi får inte utskriften "skapades!" eftersom vi har ersatt __init__() utan att kalla på superklassens version.
Exempel med super:
class Animal:
def __init__(self, name):
self.name = name
print(f"{name} skapades!")
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # Anropar Animal.__init__()
self.breed = breedNu får vi både:
- Utskriften
"Buddy skapades!" - Egenskapen
breedi subklassen
dog1 = Dog("Buddy", "Golden Retriever")
print(dog1.name) # Buddy
print(dog1.breed) # Golden RetrieverVarför inte bara kopiera koden?
Om du inte använder super() och kopierar koden i varje subklass riskerar du att:
- Duplicera kod (svårare att underhålla)
- Glömma framtida ändringar i superklassen
- Få buggar om superklassens logik ändras
Sammanfattning
| Vad? | Funktion |
|---|---|
super() | Kallar på superklassens version av en metod |
super().__init__() | Kallar på förälderns konstruktor |
| Varför använda? | Återanvänd kod, säkerställ korrekt setup |