Ønsker du å dykke ned i verden av objektorientert programmering med Python? Start din reise i dag med å utforske Pythons magiske `__init__`-metode.
I denne veiledningen vil vi gå gjennom fundamentet for Python-klasser og objekter, og deretter fokusere på `__init__`-metodens funksjonalitet.
Etter å ha fullført denne veiledningen, vil du være i stand til å besvare følgende spørsmål:
- Hva er egentlig instansvariabler eller instansattributter?
- Hvordan bistår `__init__`-metoden i initialiseringen av instansattributter?
- Hvordan setter vi standardverdier for attributter?
- Hvordan kan vi utnytte klassemetoder som konstruktører for å skape objekter?
La oss komme i gang!
Python Klasser og Objekter
Klasser er selve hjertet i objektorientert programmering i Python. De gir oss muligheten til å designe og definere attributter og metoder, og dermed koble data og tilhørende funksjonalitet sammen.
Når vi først har konstruert en klasse, kan vi bruke den som en tegning eller mal for å generere objekter (instanser).
👩🏫 La oss ta et praktisk eksempel! Vi skal skape en `Employee`-klasse, hvor hvert objekt av denne klassen vil ha følgende attributter:
- `fullt_navn`: Den ansattes fulle navn, i formatet fornavn etternavn.
- `emp_id`: Den ansattes identifikasjonsnummer.
- `avdeling`: Avdelingen den ansatte tilhører.
- `erfaring`: Antall år den ansatte har jobbet.
Hva betyr egentlig dette? 🤔
Hver ansatt vil representeres som en forekomst, eller et objekt, av `Employee`-klassen. Hvert objekt vil ha sin unike verdi for `full_name`, `emp_id`, `department` og `experience`.
Disse attributtene er også kjent som instansvariabler, og vi vil veksle mellom bruken av ordene attributter og instansvariabler.
Vi skal legge til attributter om litt. For nå lager vi en enkel `Employee`-klasse slik:
class Employee: pass
Bruken av `pass` (som en plassholder) hindrer feil under kjøring av skriptet.
Selv om den nåværende `Employee`-klassen ikke er spesielt nyttig, er den likevel en gyldig klasse. Dette lar oss skape objekter av `Employee`-klassen:
employee_1 = Employee() print(employee_1) #Output: <__main__.Employee object at 0x00FEE7F0>
Vi kan også tilføye attributter og initiere dem med verdier som vist nedenfor:
employee_1.full_name="Amy Bell" employee_1.department="HR"
Men denne måten å legge til instansattributter på er ikke bare ineffektiv, den er også utsatt for feil. Det tillater heller ikke bruken av klassen som en mal for å skape objekter. Her kommer `__init__`-metoden inn i bildet.
Forståelsen av `__init__`-metoden i Python
Vi bør ha muligheten til å initialisere instansvariablene ved opprettelsen av et objekt, og dette er nøyaktig hva `__init__`-metoden hjelper oss med. `__init__`-metoden kalles hver gang et nytt objekt av klassen skapes, for å tildele startverdier til instansvariablene.
Hvis du har erfaring med programmering i språk som C++, vil du se at `__init__`-metoden fungerer på samme måte som konstruktører.
Definere `__init__`-metoden
La oss inkludere `__init__`-metoden i `Employee`-klassen:
class Employee: def __init__(self, full_name,emp_id,department,experience): self.full_name = full_name self.emp_id = emp_id self.department = department self.experience = experience
Parameteren `self` refererer til selve forekomsten av klassen, og `self.attribute` initialiserer forekomstattributtet til verdien på høyre side.
Vi kan nå lage objekter slik:
employee_2 = Employee('Bella Joy','M007','Marketing',3) print(employee_2) # Output: <__main__.Employee object at 0x017F88B0>
Når vi skriver ut ansattobjektene, får vi ingen særlig nyttig informasjon bortsett fra klassen de tilhører. La oss legge til en `__repr__`-metode som definerer en representasjonsstreng for klassen:
def __repr__(self): return f"{self.full_name},{self.emp_id} fra {self.department} med {self.experience} års erfaring."
Etter at `__repr__` er lagt til `Employee`-klassen, får vi:
class Employee: def __init__(self, full_name,emp_id,department,experience): self.full_name = full_name self.emp_id = emp_id self.department = department self.experience = experience def __repr__(self): return f"{self.full_name},{self.emp_id} fra {self.department} med {self.experience} års erfaring."
Nå har medarbeiderobjektene en mer informativ representasjonsstreng:
print(employee_2) # Output: Bella Joy,M007 fra Marketing med 3 års erfaring.
Noen Konvensjoner
Før vi går videre, er det et par punkter å merke seg:
- Vi benyttet `self` som den første parameteren i `__init__`-metoden for å referere til selve klasseforekomsten, og `self.attribute_name` for å initialisere de forskjellige attributtene. Bruken av `self` er en allmenn konvensjon (selv om du i teorien kan bruke et annet navn).
- Når vi definerer `__init__`-metoden, setter vi parameternavnene i `__init__`-definisjonen til å samsvare med navnene på attributtene. Dette forbedrer lesbarheten i koden.
Hvordan legge til Standardverdier for Attributter
I eksemplet vi har kodet til nå, er alle attributtene obligatoriske. Det betyr at et objekt bare kan skapes hvis vi sender inn verdier for alle feltene til konstruktøren.
Prøv å opprette et objekt av `Employee`-klassen uten å gi verdi for attributtet `experience`:
employee_3 = Employee('Jake Lee','E001','Engineering')
Du vil få følgende feilmelding:
Traceback (most recent call last): File "main.py", line 22, in <module> employee_3 = Employee('Jake Lee','E001','Engineering') TypeError: __init__() missing 1 required positional argument: 'experience'
Men hvis du vil gjøre visse attributter valgfrie, kan du gjøre dette ved å definere standardverdier for disse attributtene når du definerer `__init__`-metoden.
Her gir vi standardverdien 0 for attributtet `experience`:
class Employee: def __init__(self, full_name,emp_id,department,experience=0): self.full_name = full_name self.emp_id = emp_id self.department = department self.experience = experience def __repr__(self): return f"{self.full_name},{self.emp_id} fra {self.department} med {self.experience} års erfaring."
Objektet `employee_3` blir opprettet uten en verdi for `experience`-attributtet; standardverdien 0 blir brukt for `experience`.
employee_3 = Employee('Jake Lee','E001','Engineering') print(employee_3.experience) # Output: 0
Alternative Klassekonstruktører ved hjelp av Klassemetoder
Til nå har vi sett hvordan man definerer `__init__`-metoden og setter standardverdier for attributter der det er nødvendig. Vi vet også at vi må sende inn verdier for de obligatoriske attributtene i konstruktøren.
Noen ganger kan imidlertid verdiene for disse instansvariablene (eller attributtene) være tilgjengelige i en annen datastruktur, som for eksempel en tuppel, en ordbok eller en JSON-streng.
Så, hva gjør vi?
La oss ta et eksempel. Anta at vi har verdiene for instansvariablene lagret i en Python-ordbok:
dict_fanny = {'name':'Fanny Walker','id':'H203','dept':'HR','exp':2}
Vi kan enkelt få tilgang til ordboken og hente alle attributtene slik:
name = dict_fanny['name'] id = dict_fanny['id'] dept = dict_fanny['dept'] exp = dict_fanny['exp']
Etter dette kan du lage et objekt ved å sende disse verdiene til klassekonstruktøren:
employee_4 = Employee(name, id, dept, exp) print(employee_4) # Output: Fanny Walker,H203 fra HR med 2 års erfaring.
Husk at du må gjøre dette for hvert nytt objekt du lager. Denne tilnærmingen er ineffektiv, og vi kan absolutt gjøre det bedre. Men hvordan?
I Python kan vi benytte klassemetoder som konstruktører for å skape objekter av klassen. For å definere en klassemetode, bruker vi `@classmethod`-dekoratøren.
La oss definere en metode som analyserer ordboken, henter ut instansvariabelverdiene og bruker dem til å konstruere `Employee`-objekter.
@classmethod def from_dict(cls,data_dict): full_name = data_dict['name'] emp_id = data_dict['id'] department = data_dict['dept'] experience = data_dict['exp'] return cls(full_name, emp_id, department, experience)
Når vi skal lage objekter ved hjelp av data fra ordboken, kan vi bruke klassemetoden `from_dict()`.
💡 Merk deg bruken av `cls` i klassemetoden istedenfor `self`. Akkurat som vi bruker `self` for å referere til instansen, brukes `cls` for å referere til klassen. Klassemetoder er også knyttet til klassen, og ikke til objektene.
Så, når vi kaller klassemetoden `from_dict()` for å skape objekter, kaller vi den på `Employee`-klassen:
emp_dict = {'name':'Tia Bell','id':'S270','dept':'Sales','exp':3} employee_5 = Employee.from_dict(emp_dict) print(employee_5) # Output: Tia Bell,S270 fra Sales med 3 års erfaring.
Hvis vi nå har en ordbok for hver av de n ansatte, kan vi bruke klassemetoden `from_dict()` som en konstruktør for å initiere objekter, uten å manuelt hente ut instansvariabelverdiene fra ordboken.
📝 Et notat om klassevariabler
Her definerte vi klassemetoden som er knyttet til klassen, og ikke individuelle forekomster. På samme måte som klassemetoder, kan vi også ha klassevariabler.
Akkurat som klassemetoder er klassevariabler knyttet til klassen og ikke en bestemt forekomst. Når et attributt har en fast verdi for alle forekomster av klassen, kan vi vurdere å definere det som en klassevariabel.
Ofte Stilte Spørsmål
1. Hvorfor trenger du `__init__`-metoden i Python?
`__init__`-metoden i en klassedefinisjon lar oss initiere attributtene eller instansvariablene til alle forekomster av klassen. `__init__`-metoden kalles hver gang en ny forekomst av klassen skapes.
2. Kan du ha flere `__init__`-metoder i en Python-klasse?
Meningen med å ha flere `__init__`-metoder i en Python-klasse ville være å gi flere konstruktører som kan opprette objekter. Men du kan ikke definere flere `__init__`-metoder. Hvis du definerer flere `__init__`-metoder, vil den siste implementeringen overskrive den første. Du kan imidlertid bruke `@classmethod`-dekoratøren til å definere klassemetoder som kan benyttes som konstruktører for å initiere objekter.
3. Hva skjer hvis du ikke definerer `__init__`-metoden i en klasse?
Hvis du ikke definerer `__init__`-metoden, kan du fortsatt initiere objekter. Du må imidlertid legge til instansvariabler manuelt og tilordne verdier til hver av dem. Du vil ikke ha muligheten til å sende inn verdiene for instansvariablene i konstruktøren. Dette er ikke bare utsatt for feil, men undergraver også hele ideen med at en klasse skal fungere som en mal som vi kan skape objekter fra.
4. Er det mulig å ha standardverdier for argumenter i `__init__`-metoden?
Ja, det er absolutt mulig å angi standardverdier for ett eller flere attributter når du definerer `__init__`-metoden. Å legge til standardverdier bidrar til å gjøre disse attributtene valgfrie i konstruktøren. Attributtene vil bruke standardverdiene når vi ikke sender inn verdier for dem i konstruktøren.
5. Kan du endre attributter utenfor `__init__`-metoden?
Ja, du kan når som helst oppdatere verdien til et attributt utenfor `__init__`-metoden. Du kan også dynamisk legge til nye attributter til en forekomst etter at du har skapt den spesifikke forekomsten.
Konklusjon
I denne veiledningen lærte vi hvordan vi kan benytte `__init__`-metoden for å initialisere verdiene til instansvariabler. Selv om dette er enkelt, kan det bli repeterende, særlig når du har mange attributter.
Hvis du er interessert, kan du utforske modulen `dataclass`. I Python 3.7 og nyere kan du benytte den innebygde `dataclass`-modulen for å skape dataklasser som lagrer data. I tillegg til standardimplementasjoner av `__init__` og andre ofte brukte metoder, tilbyr de mange gode funksjoner for typetips, komplekse standardverdier og optimalisering.
Neste skritt er å lære mer om `if __name__ == «__main__’` i Python.