Slik bruker du arv og polymorfisme i Python

Lær arv og polymorfisme i Python. Subklasser, super(), method overriding og isinstance() forklart.

Videoforhåndsvisning

Opprett konto for å se video

Det er helt gratis og tar under 30 sekunder

Opprett gratis kontoHar du konto? Logg inn

Du har en Operator-klasse med navn, gadget og armor. Nå trenger du en Defender-klasse som har alt det samme, pluss et skjold og en forsterkningsmetode. Du kan kopiere all koden fra Operator og legge til det nye, men da ender du opp med duplisert kode som må vedlikeholdes to steder. Arv i Python lar deg bygge nye klasser oppå eksisterende, uten å gjenta deg selv.

Slik fungerer arv i Python

Arv betyr at en ny klasse (subklassen, eller barneklassen) tar over egenskaper og metoder fra en eksisterende klasse (superklassen, eller foreldreklassen). Du angir hvilken klasse du arver fra ved å sette den i parentes etter klassenavnet:

  • class Defender(Operator): betyr at Defender arver alt fra Operator.
  • Defender får automatisk tilgang til alle egenskaper og metoder som Operator har.
  • Du kan legge til nye egenskaper og metoder som bare finnes i Defender.

Det sparer deg for kode og holder strukturen ryddig. Endrer du noe i Operator, får alle subklasser endringen automatisk.

super() kaller foreldreklassens konstruktør

Når subklassen har sin egen __init__, må du sørge for at foreldreklassens __init__ også kjøres. Det gjør du med super():

  • def __init__(self, name, gadget, shield): tar inn parameterne for Defender.
  • super().__init__(name, gadget) kaller Operators __init__ med name og gadget.
  • self.shield = shield legger til den nye egenskapen som bare Defender har.

super() finner automatisk foreldreklassen og kaller dens __init__. Du slipper å hardkode klassenavnet. Det gjør koden mer fleksibel, spesielt hvis du senere endrer arvehierarkiet.

Uten super()-kallet ville Defender-objekter mangle egenskapene name og gadget. Foreldreklassens __init__ kjøres ikke automatisk når du definerer en egen __init__ i subklassen.

Legg til nye metoder i subklassen

Subklassen arver alle metoder fra foreldreklassen, men du kan fritt legge til nye. En Defender kan for eksempel ha en reinforce-metode som øker armor-verdien:

  • def reinforce(self): øker self.armor med 30.
  • Metoden sjekker om armor overstiger 100, og kapper den i så fall.
  • Denne metoden finnes bare på Defender-objekter, ikke på Operator-objekter.

Operator-objekter har ingen tilgang til reinforce. Prøver du å kalle operator.reinforce(), får du en AttributeError. Arv går bare en vei: nedover fra forelder til barn.

Overstyr metoder med method overriding

Noen ganger vil du at subklassen skal gjøre noe annerledes enn foreldreklassen. Da overstyrer du metoden ved å definere den på nytt i subklassen med samme navn.

Operator har kanskje en metode use_gadget som printer navnet og gadgeten. Defender kan overstyre den for å inkludere skjoldet i utskriften. Python bruker alltid metoden fra den mest spesifikke klassen. Kaller du defender.use_gadget(), kjører Defenders versjon.

Du kan kombinere overstyring med super() for å utvide i stedet for å erstatte. Kall super().use_gadget() inne i Defenders versjon for å kjøre foreldrens kode først, og legg til skjold-logikken etterpå.

Polymorfisme i Python

Polymorfisme betyr at du kan behandle objekter av forskjellige subklasser gjennom et felles grensesnitt. Har du en liste med Operator-objekter og Defender-objekter, kan du kalle use_gadget() på alle uten å bry deg om hvilken type de er. Python velger riktig versjon av metoden basert på objektets faktiske klasse.

Det fungerer fordi Python bruker det som kalles duck typing: hvis et objekt har metoden du kaller, spiller det ingen rolle hvilken klasse det tilhører. "Hvis det går som en and og kvekker som en and, er det en and." I praksis betyr dette at du kan skrive fleksibel kode som fungerer med flere typer objekter, så lenge de har de metodene du trenger.

isinstance() sjekker typen

Noen ganger trenger du å vite om et objekt er av en bestemt klasse. isinstance(defender, Operator) returnerer True fordi Defender arver fra Operator. isinstance() sjekker hele arvekjeden, ikke bare den direkte klassen.

Bruk isinstance() fremfor type(objekt) == Klasse. type() sjekker bare den eksakte klassen og ignorerer arv. isinstance() gir deg riktig svar selv for subklasser, noe som er avgjørende når du jobber med polymorfisme.

Når bør du bruke arv i Python?

Arv passer når du har en tydelig "er en"-relasjon. En Defender er en Operator med ekstra funksjonalitet. En Sirkel er en Form med en radius. Hvis relasjonen ikke føles naturlig, er arv sannsynligvis feil verktøy.

Et vanlig alternativ er komposisjon, der du bruker et objekt som egenskap i stedet for å arve. En Bil har en Motor, men en Bil er ikke en Motor. I slike tilfeller lager du Motor som en egen klasse og gir Bil en egenskap som holder et Motor-objekt.

Unngå dype arvehierarkier med mange nivåer. To til tre nivåer er vanligvis greit. Går du dypere, blir koden vanskelig å følge fordi du må lete gjennom mange klasser for å forstå hva en metode gjør.

Vanlige feil med arv

Den vanligste feilen er å glemme super().__init__() i subklassens __init__. Uten den mister du foreldreklassens egenskaper, og du får AttributeError når du prøver å bruke dem.

En annen felle er å overstyre en metode uten å kalle super() når du burde utvidet i stedet for å erstatte. Hvis foreldreklassens metode setter viktige variabler, og du erstatter den fullstendig, mister du den logikken.

Neste steg

Nå som du kan arve og overstyre, er neste steg å gjøre klassene dine lettere å feilsøke. Artikkelen om __repr__ og __str__ i Python viser deg hvordan du kontrollerer hva som printes når du inspiserer objekter. For å forstå de ulike metodetypene bedre, forklarer artikkelen om statiske metoder og klassemetoder når du bruker @staticmethod og @classmethod. Pythons offisielle dokumentasjon om arv dekker også multiarv og MRO (Method Resolution Order).

Denne artikkelen bygger på kurset Python – objektorientert programmering på Utdannet.no. I kurset jobber du med arv, super(), method overriding og polymorfisme gjennom praktiske prosjekter, og du bygger klassehierarkier med oppgaver og løsningsforslag underveis.