5.3 `__str__` og pen objektutskrift
Gjøre et objekt pent utskrivbart med `__str__`, og skrive utskriftsmetoder som delegerer til underobjektenes utskrift.
__str__ står i 3 av 6 moderne eksamenssett (50 %) — og dendukker aldri opp alene. Den er en deloppgave inne i Oppgave 4, den store klassemodelleringen, der bestillingen er formulert som «gi klassen en metode som gjør at objektet kan skrives pent ut».
Sjangeren er F — stor klassemodellering, altså å bygge flere samarbeidende klasser fra en beskrevet oppgave. Deloppgaven er liten, typisk 3–5 poeng, men den er gratis når mønsteret sitter.
Dette skal du kunne — bokas midterste av tre prioritetsnivåer. Nivået over
heter «må sitte» og gjelder konstruktør og innkapsling; dette ligger et hakk under, fordi det er færre poeng og et enklere mønster.
I tillegg møter du her det som blir kjernen i hele Del 6: delegering, altså at en klasse som holder mange objekter, ber hvert av dem om å skrive seg selv ut i stedet for å gjøre jobben selv. Det mønsteret er fast delkrav i den store oppgaven, og navngivingen av det har en egen regel du skal lære nå.
Forkunnskaper — sist du var her
Kapitlet bygger på kap. 5.1 — Klasser og objekter og
kap. 5.2 — Innkapsling, og brukerstr(...)-konverteringen fra kap. 3.3 — Strenger.
De to tingene du trenger å ha helt klart, friskes opp med kjørt kode.
1. str(tall) gjør et tall om til tekst, slik at det kan skjøtes sammen med
annen tekst med +:
navn = "Sult" aar = 1890 print(navn + " (" + str(aar) + ")")Utskrift:
Sult (1890)Uten str(...) rundt tallet stopper programmet, og siste linje i feilmeldingen er TypeError: can only concatenate str (not "int") to str.
2. En metode når objektets verdier med self._x, og returnerer med return:
class Bok:
def __init__(self, tittel, aar):
self._tittel = tittel self._aar = aar
def hent_tittel(self):
return self._tittel
b = Bok("Sult", 1890)
print(b.hent_tittel())Utskrift:
SultNå setter vi de to sammen: en metode som bygger en tekst av objektets egne verdier.
Løkke 1 — Hva skjer når du skriver ut et objekt? (~10 min)
Et bibliotek har et Bok-objekt, og du vil bare se hva som står i det. Det nærliggende er å skrive print(b).
Det virker ikke slik du håper. Uten videre gir Python deg noe i denne stilen:
<__main__.Bok object at 0x104a2f130>Blokken er merket som ikke-kjørbar fordi tallet på slutten er en adresse i maskinens minne og blir forskjellig hver gang programmet kjøres. Det er maskinens svar på «hvilket objekt dette er», og det er ubrukelig for et menneske.
Løsningen er å fortelle Python hvordan objektet skal se ut som tekst. Det
gjør du med spesialmetoden __str__.
Spesialmetoden som returnerer en tekst som beskriver objektet. Python kaller den automatisk når objektet skal skrives ut.
Navnet har to understreker på hver side, som __init__, og du kaller den aldri selv:
class Bok:
def __init__(self, tittel, aar):
self._tittel = tittel self._aar = aar
def __str__(self):
return self._tittel + " (" + str(self._aar) + ")"
b = Bok("Sult", 1890)
print(b)Utskrift:
Sult (1890)Metoden har self som eneste parameter, og den returnerer — den skriver ikke ut. Bruker du print inni i stedet for return, går det galt på en måte som forklares i advarselen lenger nede.
Bokas ellevte kodemønster. Malen er kort og alltid den samme:
def __str__(self):
return "..." + self._tekstfelt + " " + str(self._tallfelt)Blokken er en mal med plassholdernavn og er derfor merket som ikke-kjørbar.
Tre regler:
1. return, aldri print. Metoden leverer en tekst; det er den som kaller,
som bestemmer om teksten skal vises.
2. str(...) rundt hvert tall. Tekst pluss tall stopper programmet.
Tekstfelt trenger det ikke, men det skader ikke å ta det med.
3. Mellomrom og skilletegn skrives inn selv. + skjøter uten å legge til
noe, i motsetning til komma i et print-kall.
Formen på teksten bestemmer du. Ber oppgaven om et bestemt format, følg det tegn for tegn — det er den slags detalj som rettes strengt.
Gi klassen Medlem på et treningssenter en __str__ som gjør atprint(medlem) viser navn, medlemsnummer og antall besøk på én linje.
Metoden bygger én tekst av de tre verdiene, med skilletegn skrevet inn for hånd:
class Medlem:
def __init__(self, navn, nummer):
self._navn = navn self._nummer = nummer self._besok = 0
def registrer_besok(self):
self._besok = self._besok + 1
def __str__(self):
return self._navn + " (nr " + str(self._nummer) + "), " + str(self._besok) + " besok"
m = Medlem("Ada", 104)
m.registrer_besok()
m.registrer_besok()
print(m)Utskrift:
Ada (nr 104), 2 besokLegg merke til de tre str(...)-kallene. self._navn er allerede tekst og
trenger ingen, men self._nummer og self._besok er tall. Uten konverteringen stopper programmet med TypeError: can only concatenate str (not "int") to str.
Slik ville sensor sett på det: tre ting gir uttelling hver for seg — at
metoden heter __str__ med riktige understreker, at den bruker return, og at tallene er konvertert. Hadde du glemt ett str(...), ville de to andre fortsatt telt.
Merk at teksten er skrevet uten æ, ø og å, som all kode i denne boka. «besok»
i stedet for «besøk» er den vanlige omskrivingen.
(Innstegsoppgave — gjengivelse.) Klassen Rett i en kantine harself._navn og self._pris.
a) Skriv __str__ slik at print(rett) gir for eksempelFiskesuppe: 89 kr.
b) Hvorfor må prisen gjennom str(...)?
c) Hva ville print(rett) gitt hvis klassen ikke hadde noen __str__?
Løkke 2 — __str__ mot en skriv-metode (~10 min)
Det finnes to måter å få et objekt til å vise seg fram på, og eksamensoppgaver ber om begge. Forskjellen er liten i kode og stor i bruk.
En __str__ returnerer en tekst. En skriv-metode skriver den ut. Den første kan brukes videre — legges i en liste, skjøtes med annen tekst, sendes til en annen metode. Den andre er ferdig i det øyeblikket den kjører.
De to måtene __str__ blir kalt på — begge automatisk, ingen av dem av deg.
print(objekt) kaller __str__ og skriver resultatet. str(objekt) kaller__str__ og gir deg teksten, slik at du kan bruke den videre:
class Bok:
def __init__(self, tittel):
self._tittel = tittel
def __str__(self):
return "Bok: " + self._tittel
b = Bok("Sult")
linje = str(b)
print(linje + " | " + str(b))Utskrift:
Bok: Sult | Bok: SultDet er dette som gjør __str__ mer verdt enn en skriv-metode: teksten kan brukes til noe. Du kan skjøte den, sammenligne den eller legge den i en liste.
En vanlig metode som skriver ut i stedet for å returnere:
class Bok:
def __init__(self, tittel, aar):
self._tittel = tittel self._aar = aar
def skriv(self):
print(self._tittel, self._aar)
b = Bok("Sult", 1890)
b.skriv()Utskrift:
Sult 1890Navnet er fritt — skriv, skriv_ut, vis. Metoden returnerer ingenting, og verdien kan derfor ikke brukes videre.
Legg merke til komma i print-kallet. Komma skiller argumentene med ett
mellomrom og konverterer tall automatisk, så du slipper både + og str(...).
Det er den store praktiske forskjellen fra __str__, der du må skrive begge deler selv.
Ber oppgaven om «en metode som skriver ut objektet», er dette svaret. Ber den om
«at objektet kan skrives pent ut med print», er svaret __str__.
To varianter, og begge stopper programmet — eller gjør noe verre.
Variant 1: print i stedet for return.
def __str__(self):
print(self._tittel)Metoden skriver ut tittelen og returnerer None. Når print(b) da skal skrive det __str__ ga tilbake, stopper programmet, og siste linje i feilmeldingen erTypeError: __str__ returned non-string (type NoneType). Utskriften kommer altså, men programmet krasjer rett etterpå — en forvirrende kombinasjon første gang du ser den.
Variant 2: returnere et tall.
def __str__(self):
return self._aarSamme type feilmelding, med (type int) til slutt. __str__ skal returnere en tekst, uansett hva feltet er. Løsningen er return str(self._aar).
Begge blokkene er merket som ikke-kjørbare, fordi feilen er plantet med vilje.
Motgiften: les metoden din og spør «gir siste linje her en tekst?». Er
svaret nei, mangler det enten et return eller en str(...).
Gi klassen Sykkel både en __str__ og en skriv-metode, og vis når hver av dem er nyttig.
Klassen får begge, og bruken viser forskjellen:
class Sykkel:
def __init__(self, kode, stativ):
self._kode = kode self._stativ = stativ
def __str__(self):
return self._kode + " @ " + self._stativ
def skriv(self):
print("Sykkel", self._kode, "staar i", self._stativ)
s = Sykkel("R31", "Blindern")
print(s)
s.skriv()
linjer = []
linjer.append(str(s))
linjer.append("R48 @ Majorstuen")
print(len(linjer), linjer[0])Utskrift:
R31 @ Blindern
Sykkel R31 staar i Blindern
2 R31 @ BlindernDe to første linjene ser like nyttige ut, men bare den ene teksten kan gjenbrukes.
Nederst legges den i en liste, og det kunne like gjerne vært en fil, en sammenligning eller en lengre rapport. Skriv-metoden har ingen slik verdi å gi fra seg.
Slik ville sensor sett på det: ber oppgaven om «en metode som gjør at
objektet kan skrives ut med print», er __str__ det riktige svaret, og en skriv-metode gir bare delvis uttelling. Ber den om «en metode som skriver ut opplysningene», er skriv-metoden riktig. Les hvilket av de to verbene som står der.
Merk @-tegnet i teksten. Det er et helt vanlig tegn i en streng, og det er
lov å bruke det som skilletegn. Æ, ø og å er det derimot ikke, som ellers i bokas kode.
Hva skriver programmet ut?
class Vare:
def __init__(self, navn, antall, pris):
self._navn = navn self._antall = antall self._pris = pris
def __str__(self):
return self._navn + " x" + str(self._antall)
def hent_verdi(self):
return self._antall * self._pris
v = Vare("skrue", 4, 3)
print(v)
print(v, v.hent_verdi())
print(str(v) + "!")En kollektivrute skal kunne skrives ut på formen Rute 20: Blindern - Toyen (14 passasjerer).
a) Skriv klassen Rute med konstruktør som tar rutenummer, startsted og
endested, og et passasjerantall som starter på 0.
b) Skriv __str__ som gir nøyaktig formen over.
c) Legg til paa(self, antall) og vis at utskriften følger med.
Løkke 3 — Delegering: la hvert objekt skrive seg selv (~12 min)
Nå kommer mønsteret som er fast delkrav i den store oppgaven.
Et bibliotek holder mange bøker. Skal biblioteket skrive ut hele samlingen sin, har det to valg: enten grave i hver boks verdier selv, eller be hver bok om å skrive seg selv.
Det siste heter delegering, og det er alltid riktig svar. Grunnen er den samme som i kap. 5.2: boka vet hvordan en bok skal vises, og biblioteket skal slippe å vite det.
Bokas tolvte kodemønster, og kjernen i Oppgave 4:
class Container:
def __init__(self):
self._elementer = []
def legg_til(self, e):
self._elementer.append(e)
def skriv_alle(self):
for e in self._elementer:
print(e)Blokken er en mal med plassholdernavn og er merket som ikke-kjørbar.
Løkka går gjennom samlingen og lar print(e) kalle hvert underobjekts__str__. Ytterklassen skriver ikke ett eneste felt selv.
Alternativet — å skrive print(e.hent_tittel(), e.hent_aar()) inne i løkka —
gir dårligere uttelling, fordi visningen da er duplisert: endrer boka format, må biblioteket endres også. Og verst av alt er print(e._tittel), som i tillegg er feilkode #11, direkte tilgang til en instansvariabel utenfra.
Legg merke til at metoden i malen heter skriv_alle, ikke skriv. Det er en bindende regel i denne boka, og den er verdt å ta med til eksamen.
Grunnen er dels lesbarhet: de to metodene gjør ulike ting. bok.skriv() viser
én bok; bibliotek.skriv_alle() viser alle. To ulike jobber bør ha to
ulike navn.
Dels er den praktisk. En metode som heter det samme som den den kaller, er vanskelig å lese — og et verktøy som leser koden, kan ikke se forskjell påself.skriv() og bok.skriv(). Det ser ut som om metoden kaller seg selv, og en metode som kaller seg selv, er rekursjon, som er utenfor pensum i dette emnet.
Bruk disse navneparene:
| Elementets metode | Containerens metode |
|---|---|
skriv() | skriv_alle() |
hent_navn() | hent_alle_navn() eller navneliste() |
antall() | totalt_antall() |
__str__ | skriv_alle(), som bruker print(e) |
La klassen Bibliotek holde flere Bok-objekter i en liste, og gi den en metode som skriver ut hele samlingen ved å be hver bok om å vise seg selv.
To klasser, der den ytre bare holder styr på samlingen:
class Bok:
def __init__(self, tittel, aar):
self._tittel = tittel self._aar = aar
def __str__(self):
return self._tittel + " (" + str(self._aar) + ")"
class Bibliotek:
def __init__(self, navn):
self._navn = navn self._boker = []
def legg_til(self, bok):
self._boker.append(bok)
def skriv_alle(self):
print("Samling:", self._navn)
for b in self._boker:
print(" -", b)
bib = Bibliotek("Deichman")
bib.legg_til(Bok("Sult", 1890))
bib.legg_til(Bok("Markens grode", 1917))
bib.skriv_alle()Utskrift:
Samling: Deichman
- Sult (1890)
- Markens grode (1917)Linjen print(" -", b) er hele delegeringen. b er et Bok-objekt, ogprint kaller boka sin egen __str__. Bibliotek vet ikke — og trenger ikke å vite — at en bok vises med tittel og årstall i parentes.
Prøv tanken: skal bøkene senere vises med forfatter i tillegg, endrer du én
metode i Bok, og Bibliotek merker ingenting. Det er den samme gevinsten som i
kap. 5.2, nå mellom to klasser.
Slik ville sensor sett på det: fem ting gir uttelling. self._boker = [] i
konstruktøren, append i legg_til, løkka i skriv_alle, at utskriften delegeres i stedet for å hentes felt for felt, og at metoden heter noe annet enn elementets. Hadde du skrevet print(" -", b.hent_tittel()), ville strukturen vært riktig og trekket lite — men delegeringspoenget hadde gått tapt.
— naturlig pausepunkt —
Hva skriver programmet ut?
class Spill:
def __init__(self, tittel, maks):
self._tittel = tittel self._maks = maks
def __str__(self):
return self._tittel + " (" + str(self._maks) + ")"
class Klubb:
def __init__(self):
self._spill = []
def legg_til(self, s):
self._spill.append(s)
def skriv_alle(self):
for s in self._spill:
print(s)
print("Antall:", len(self._spill))
k = Klubb()
k.legg_til(Spill("Kolonier", 4))
k.legg_til(Spill("Sjakk", 2))
k.skriv_alle()En resirkuleringsstasjon har flere containere, hver med et materiale og en fyllingsgrad i prosent.
a) Skriv klassen Container med __str__ på formen glass: 40 %.
b) Skriv klassen Stasjon som holder containerne i en liste, medlegg_til(self, c) og en metode som skriver ut alle.
c) Hva skal metoden i b) hete, og hvorfor ikke skriv?
Løkke 4 — Delegering med en ordbok (~8 min)
Underobjektene ligger ikke alltid i en liste. Skal du kunne slå opp på et navn eller et nummer, er en ordbok fra
kap. 3.2 et bedre valg — og det er formen den store oppgaven ofte bruker.
Delegeringen er akkurat den samme; bare løkka ser litt annerledes ut.
Løkka over en ordbok gir deg nøklene. Objektet henter du med et oppslag:
class Bok:
def __init__(self, tittel):
self._tittel = tittel
def __str__(self):
return "Bok: " + self._tittel
boker = {}
boker["sult"] = Bok("Sult")
boker["vaar"] = Bok("Vaar")
for n in boker:
print(n, "->", boker[n])Utskrift:
sult -> Bok: Sult vaar -> Bok: VaarRekkefølgen følger den de ble satt inn i. Verdien boker[n] er et helt vanlig objekt, så print kaller dets __str__ som før.
Nøkkelen er ofte navnet, og verdien objektet. Da har du både oppslag og
gjennomløping i samme struktur — derfor er ordboka så vanlig i Oppgave 4.
Et treningssenter holder salene sine i en ordbok fra salnavn til Sal-objekt.
Skriv de to klassene med __str__ og en utskriftsmetode som delegerer, pluss en metode som finner én sal på navn.
Ordboka gir både oppslag og gjennomløping:
class Sal:
def __init__(self, navn, kapasitet):
self._navn = navn self._kapasitet = kapasitet
def hent_navn(self):
return self._navn
def __str__(self):
return self._navn + " (" + str(self._kapasitet) + " plasser)"
class Senter:
def __init__(self, sted):
self._sted = sted self._saler = {}
def legg_til(self, sal):
self._saler[sal.hent_navn()] = sal
def finn(self, navn):
if navn in self._saler:
return self._saler[navn]
return None
def skriv_alle(self):
print("Senter:", self._sted)
for n in self._saler:
print(" -", self._saler[n])
senter = Senter("Toyen")
senter.legg_til(Sal("Speilsal", 20))
senter.legg_til(Sal("Spinning", 14))
senter.skriv_alle()
print(senter.finn("Spinning"))
print(senter.finn("Basseng"))Utskrift:
Senter: Toyen
- Speilsal (20 plasser)
- Spinning (14 plasser)
Spinning (14 plasser)
NoneFire ting er verdt å merke seg.
legg_til bruker salens egen aksessor til å finne nøkkelen:self._saler[sal.hent_navn()] = sal. Senteret bestemmer altså ikke navnet selv, det spør salen. Å skrive sal._navn her ville vært feilkode #11.
finn sjekker med if navn in self._saler: før den slår opp. Uten sjekken stopper programmet på en nøkkel som ikke finnes — det er feilkode #14, å slå opp noe som ikke er lagt inn.
Siste linje skriver None, fordi finn("Basseng") ikke fant noe. None er
Pythons ord for «ingen verdi», og print viser det med stor forbokstav.
Og skriv_alle heter ikke skriv, etter navneregelen.
Slik ville sensor sett på det: dette er en typisk 12–15-poengs deloppgave i
Oppgave 4, og poengene ligger spredt: ordboka i konstruktøren, innsettingen med riktig nøkkel, if navn in ...-sjekken, return None-grenen, løkka, og delegeringen. Mangler én av dem, står de andre.
Hva skriver programmet ut?
class Medlem:
def __init__(self, navn, timer):
self._navn = navn self._timer = timer
def hent_timer(self):
return self._timer
def __str__(self):
return self._navn + "/" + str(self._timer)
class Sentral:
def __init__(self):
self._medlemmer = {}
def legg_til(self, m, nokkel):
self._medlemmer[nokkel] = m
def totalt_antall_timer(self):
total = 0 for n in self._medlemmer:
total = total + self._medlemmer[n].hent_timer()
return total
def skriv_alle(self):
for n in self._medlemmer:
print(n, self._medlemmer[n])
s = Sentral()
s.legg_til(Medlem("Ada", 12), "ada")
s.legg_til(Medlem("Nora", 7), "nora")
s.legg_til(Medlem("Ada", 3), "ada")
s.skriv_alle()
print(s.totalt_antall_timer())En brettspillklubb har medlemmer, og hvert medlem har et navn og en liste over spill det eier.
a) Skriv klassen Medlem med __str__ på formen Ada (2 spill), og en
metode legg_til_spill(self, tittel).
b) Skriv klassen Klubb som holder medlemmene i en ordbok fra navn tilMedlem-objekt, med meld_inn(self, medlem) og skriv_alle(self).
c) Legg til en metode i Klubb som gir det samlede antall spill i klubben.
d) Hvorfor kan ikke metoden i c) hete det samme som noen metode i Medlem?
Fem feil koster nesten alle poengene som mistes på objektutskrift:
- __str__ uten return. Bruker du print inni, returnerer metoden None,
og programmet stopper med
TypeError: __str__ returned non-string (type NoneType).
- __str__ som returnerer et tall. Samme feilmelding med (type int).
Løsningen er return str(self._x).
- Glemt str(...) rundt et tall i skjøtingen. Programmet stopper med
TypeError: can only concatenate str (not "int") to str.
- Ikke delegere. Å skrive ut underobjektets felt for felt i ytterklassen
dupliserer visningen, og med e._tittel blir det i tillegg feilkode #11.
- Containerens metode heter det samme som elementets. skriv som kaller
skriv ser ut som om den kaller seg selv. Bruk skriv_alle.
Og én lesefelle: komma i print gir ett mellomrom, + gir ingenting.
Blander du dem, blir formatet feil selv om alt annet er riktig.
Begrepsbank
Begrepsbanken er flashcard- og repetisjonsstoff — den gjentar det du nettopp har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder kjernestoffet.
En metode med to understreker på hver side av navnet, som Python kaller automatisk — du kaller den aldri selv.
I denne boka finnes bare to: __init__, som kjører når objektet lages, og__str__, som kjører når objektet skal bli tekst.
Blander du dem, er symptomet lett å kjenne igjen: skriver du __str__ der__init__ skulle stått, får objektet ingen verdier i det hele tatt.
At en klasse ber et underobjekt om å gjøre jobben, i stedet for å gjøre den selv.
I dette kapitlet er jobben utskrift: Bibliotek lar hver Bok vise seg selv med sin egen __str__. Senere delegeres også telling, søk og oppdatering.
Kjennetegnet i koden er en løkke der kroppen er ett kall på et underobjekt, og ingen felt hentes ut. Det motsatte — at ytterklassen graver i underobjektets verdier — er både dårligere kode og dårligere uttelling.
En metode i denne boka kaller aldri en metode med samme navn — verken på seg selv eller på et underobjekt.
Elementet har skriv(), containeren har skriv_alle(). Elementet harantall_spill(), containeren har totalt_antall_spill().
Regelen har to grunner: navnene beskriver ulike jobber, og en metode som ser ut som om den kaller seg selv, ligner på rekursjon, som er utenfor pensum i dette emnet.
Når en oppgave oppgir hvordan utskriften skal se ut, er formatet en del av oppgaven og rettes deretter.
Skriv formatet av på papir før du koder, og marker hvert mellomrom, hvert skilletegn og hver parentes. Rute 20: Blindern - Toyen (14 passasjerer) inneholder fem slike detaljer.
Er formatet ikke oppgitt, velger du selv — men velg noe som er lett å lese, og hold det likt for alle objektene av samme klasse.
Skillet som avgjør om en metode skal bruke return eller print.
En metode som lager en tekst, returnerer den, og den som kaller, bestemmer hva som skjer videre. En metode som viser noe, skriver ut, og da er saken avgjort.
__str__ er alltid av den første typen. Det er nettopp derfor den er mer verdt enn en skriv-metode: teksten kan legges i en liste, skjøtes med annen tekst eller sammenlignes.
Det Python viser når en klasse mangler __str__: klassenavnet og et sekskantsifret tall, som <__main__.Bok object at 0x104a2f130>.
Tallet er hvor objektet ligger i maskinens minne, og det er forskjellig hver gang programmet kjøres. Derfor kan en slik utskrift aldri være fasit i en sporingsoppgave.
Ser du den i din egen kjøring, betyr det bare at klassen mangler __str__.
Skal __str__ sette sammen mange biter, blir linjen lang. To ryddige måter:
Sett parenteser rundt hele uttrykket og del over flere linjer — Python leser innholdet i en parentes som én sammenhengende linje. Eller bygg teksten i steg med en lokal variabel og returner den til slutt.
Begge er like riktige. Velg den som gjør formatet lettest å kontrollere mot bestillingen.
Pythons ord for «ingen verdi». Skrives ut med stor forbokstav.
Du møter den to steder i dette kapitlet: som returverdi fra en metode som glemtereturn, og som ærlig svar fra en søkemetode som ikke fant noe.
Det siste er riktig og ønsket. return None når et søk mislykkes, er bedre enn å returnere en tom tekst — den som kaller, kan da sjekke med if svar != None:.
En klasse hvis viktigste jobb er å holde mange objekter av en annen klasse:Bibliotek med bøker, Klubb med medlemmer, Senter med saler.
Den kjennes igjen på tre trekk: en samling i konstruktøren ([] eller {}), enlegg_til-metode, og én eller flere metoder som løper gjennom samlingen.
Hver eneste Oppgave 4 inneholder minst én slik klasse. Mønsteret er derfor verdt å kunne i fingrene, og det bygges ferdig i
kap. 6.2.
Valget avgjøres av ett spørsmål: skal du slå opp på et navn eller et nummer?
Er svaret ja, bruk en ordbok med det navnet som nøkkel og objektet som verdi. Er svaret nei — du skal bare gå gjennom alle — er en liste enklere.
En ordbok kan aldri ha to like nøkler. Legger du inn samme navn to ganger,
overskrives det første objektet uten en advarsel. Det er verdt å huske både
når du koder og når du sporer.
Formen containeren bruker når objektet selv vet hva det heter:self._saler[sal.hent_navn()] = sal.
Containeren spør altså objektet i stedet for å bestemme navnet selv. Alternativetself._saler[sal._navn] = sal er feilkode #11, direkte tilgang til en instansvariabel utenfra.
Dette er den vanligste formen feilkode #11 tar når to klasser samarbeider — og den vanligste i den store oppgaven.
if navn in self._saler: før self._saler[navn].Uten sjekken stopper programmet på en nøkkel som ikke finnes, og siste linje i feilmeldingen er KeyError med nøkkelen som mangler. Det er feilkode #14.
Standardformen på en søkemetode er derfor tredelt: sjekk, returner objektet hvis det finnes, og returner None ellers.
__str__ husker ingenting. Den leser instansvariablene i det øyeblikket den kalles, og bygger teksten på nytt.Derfor endrer utskriften seg av seg selv når objektet endres — du trenger ikke å kalle noe for å «oppdatere» teksten.
Det er også grunnen til at __str__ aldri skal lagre noe i en instansvariabel.
Metoden skal lese og returnere, ingenting annet.
Les verbet i oppgaveteksten.
«Objektet skal kunne skrives pent ut med print» eller «gi klassen en metode som gjør objektet utskrivbart» betyr __str__.
«Skriv en metode som skriver ut opplysningene om …» betyr en vanlig
skriv-metode.
Er du i tvil, skriv __str__ — den kan alltid brukes av en skriv-metode etterpå, mens det ikke går den andre veien.
Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.
Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Universitetet i Oslo. Dette er ikke offisielt studiemateriell. Les mer.