2.2 Gjenbruk, hjelpefunksjoner og meny/`main`-dispatcher
Bygge kjeder der funksjoner kaller hverandre, bruke hjelpefunksjoner, og skrive en main/meny som binder alt sammen — slik sensor forventer det på de store oppgavene.
- Programmeringsoppgaven er hvert år én kjede av deloppgaver a) til f), der senere ledd skal bygge på de tidligere. Løsningsforslagene i arkivet gjør det konsekvent: analysefunksjonen kaller parse-funksjonen, og main kaller alt. Kopierer du koden fra a) inn i c) i stedet for å kalle den, får du ikke uttelling for gjenbruk.
- Meny- eller main-oppgaven — «lag et program som viser valgene 1, 2 og q og gjør riktig ting» — står i ~50 % (5 av 10 sett). Den er en del av sjanger H, som er «input-validering og meny/main-løkke»; selve input-valideringen er i kap. 1.4.
- Programmeringsdelen teller ~50–60 % av settet, og menyoppgaven er ofte det siste leddet i den — den som binder de andre sammen.
Prioritet: høyeste — dette må sitte. Det gode med kapitlet er at det ikke krever ny Python. Du kan alt du trenger fra kap. 2.1; det som er nytt, er hvordan bitene settes sammen, og det er nettopp det som skiller en besvarelse på C fra en på A. Og C er en god og vanlig karakter.
Lesetid: seks løkker på til sammen ~45 minutter lesetid. Skriver du koden selv underveis, regn ×1,5.
- kap. 2.1 — def, parametere, return, flere returverdier og skillet mellom lokale og globale navn. Dette er det viktigste.
- kap. 1.3 — while-løkka og break, som er hele mekanikken i en meny.
- kap. 1.4 — input(), som alltid gir en streng, og løkka som spør på nytt til svaret er gyldig.
- kap. 1.2 — if/elif/else, som er det menyen dispatcher med.
Dataene i dette kapitlet er lister med tall, brukt slik Del 1 bruker dem: gjennomløp med for, oppslag med priser[i] og lengde med len(...). Å lese dem inn fra en fil kommer i kap. 4.1, og hele kjeden settes sammen på eksamensnivå i kap. 7.7.
Løkke 1 — Hvorfor gjenbruk gir poeng (~7 min)
Tenk deg at du skal lage en liten strømprisapp. Den skal kunne vise den høyeste prisen i døgnet, den skal kunne vise snittprisen, og den skal kunne si om det er dyrt akkurat nå. Alle tre trenger å gå gjennom den samme lista med 24 priser.
Den utsatte løsningen er å skrive den samme løkka tre ganger, én i hver funksjon. Den virker. Men den er tre ganger så lang å skrive under tidspress, den har tre steder å gjøre den samme feilen, og den gir ikke uttelling for det sensor faktisk ser etter.
Alternativet er å skrive løkka én gang, i en funksjon med et navn — og la de andre funksjonene kalle den.
En funksjon du har definert, kan kalles hvor som helst senere i fila — også inne i kroppen til en annen funksjon. Det er ingen ny konstruksjon: det er akkurat det samme kallet som fra toppnivå.
Kravet er bare at funksjonen er definert før kallet kjøres. Siden alle def-ene i et program kjøres før main() kalles, kan funksjonene fritt kalle hverandre uansett rekkefølge i fila.
def snitt(priser):
total = 0
for p in priser:
total = total + p
return total / len(priser)
def er_dyrt_naa(priser, naa):
return naa > snitt(priser)
doegn = [0.42, 0.55, 1.20, 0.98]
print(snitt(doegn))
print(er_dyrt_naa(doegn, 1.05))Utskrift:
0.7875
Trueer_dyrt_naa inneholder ingen løkke. Den låner løkka fra snitt — og blir én linje lang.
En hjelpefunksjon er en liten funksjon som ikke svarer på selve oppgaven, men som gjør en bit av arbeidet flere andre funksjoner trenger: snitt, finn_indeks, beregn_verdi.
Kjennetegnet er at den er kort, har et beskrivende navn og ikke skriver ut noe. Den returnerer, slik at den som kaller, bestemmer hva som skal skje med svaret.
Å innføre en hjelpefunksjon som oppgaven ikke ba om, er alltid tillatt og trekker aldri ned. Sensor sidestiller flere korrekte løsninger, og en oppdeling som gjør besvarelsen lettere å lese, er en fordel.
Står den samme kodesnutten to steder, er det en kopi. Kopier er dyre av tre grunner: de tar tid å skrive for hånd, de gir to steder å gjøre feil, og de gir ikke uttelling for gjenbruk.
Kjenn igjen kopien ved at du kan gi de to snuttene det samme navnet. Da er navnet funksjonen din, og de to stedene blir to kall.
Regelen i praksis: skriver du en løkke du har skrevet før i samme besvarelse, stopp og gi den et navn i stedet.
Strømprisappen skal vise snittprisen, si om prisen akkurat nå er over snittet, og telle hvor mange timer i døgnet som lå over snittet. Skriv de tre funksjonene slik at løkka som regner snittet, bare står ett sted.
def snitt(priser):
if len(priser) == 0:
return None
total = 0
for p in priser:
total = total + p
return total / len(priser)
def er_over_snitt(priser, pris):
return pris > snitt(priser)
def timer_over_snitt(priser):
grense = snitt(priser)
antall = 0
for p in priser:
if p > grense:
antall = antall + 1
return antall
doegn = [0.42, 0.55, 1.20, 0.98, 1.35, 0.61]
print(snitt(doegn))
print(er_over_snitt(doegn, 1.05))
print(timer_over_snitt(doegn))Utskrift:
0.8516666666666667
True
3Tre poenger å ta med seg:
- snitt står én gang. Endrer du senere hvordan snittet regnes, endrer du ett sted.
- timer_over_snitt kaller snitt én gang, før løkka, og lagrer svaret i grense. Hadde kallet stått inne i if-testen, ville snittet blitt regnet ut på nytt for hver eneste pris. Det gir riktig svar, men er unødvendig arbeid — og på en stor datamengde merkes det.
- Ingen av de tre skriver ut noe. Utskriften skjer nederst, der resultatene brukes. Det er den formen som lar neste deloppgave gjenbruke funksjonene.
Legg merke til at snittet skrives som 0.8516666666666667. Flyttall er sjelden pene av seg selv; å runde av til to desimaler i utskriften kommer i kap. 3.4.
(Innstegsoppgave — minimal sporing. Sjanger B — kodesporing, altså «hva skriver programmet ut?».) Tre funksjoner som bygger på hverandre. Hva skriver programmet ut?
def dobbel(x):
return x * 2
def firedobbel(x):
return dobbel(dobbel(x))
def sum_firedobler(verdier):
total = 0
for v in verdier:
total = total + firedobbel(v)
return total
print(firedobbel(3))
print(sum_firedobler([1, 2, 3]))Løkke 2 — Kjeden: fra rådata til svar (~8 min)
Programmeringsoppgaven på eksamen har alltid den samme formen, uansett om domenet er bussruter, bibliotekutlån eller strømpriser:
les inn data → omform dem → analysér → vis eller lagre svaret.
Deloppgavene a) til f) er nettopp disse leddene, én funksjon per ledd. Og de er en kjede: leddet i c) tar imot det leddet i b) ga fra seg.
les_inn(...) -> rådataene som en liste eller tabell
omform(data) -> tallene konvertert, radene delt opp
analyser(data) -> det oppgaven spør etter
skriv_ut(svar) -> utskriften brukeren ser
main() -> kaller de fire, i den rekkefølgenBlokken over er en mal, ikke kjørbar kode.
Tre regler gjør kjeden til en kjede, og alle tre er poenggivende:
1. Hvert ledd tar imot resultatet fra det forrige som parameter. Ingen funksjon henter data på egen hånd.
2. main gjør ingen regning selv. Den henter dataene én gang, sender dem videre og viser resultatet.
3. Ingen kopiert kode mellom leddene. Trenger to ledd det samme, blir det en hjelpefunksjon.
I denne boka lærer du leddene ett om gangen: innlesing fra fil i kap. 4.1, omforming i kap. 3.3, analysen i kap. 7.4 og hele kjeden på eksamensnivå i kap. 7.7. Her øver du på selve koblingen, med lister du får ferdig.
En kjede er en rekke funksjoner der utverdien fra den ene er innverdien til den neste. Kravet er at hvert ledd returnerer noe — et ledd som bare skriver ut, kan ikke ha et neste ledd.
På eksamen ser du kjeden i selve oppgaveteksten: «c) Skriv funksjonen finn_beste(tabell) som bruker les_inn_data fra deloppgave a)». Der er kjeden ikke et forslag, men et krav.
Klarte du ikke a)? Skriv likevel c) som om a) virket, og kall funksjonen. Sensor gir uttelling for riktig struktur i c) selv om a) mangler eller er feil.
Data som flere funksjoner trenger, sendes inn som parameter — ikke hentes på nytt inne i hver funksjon.
Det høres selvsagt ut, men den vanligste strukturfeilen i besvarelser er nettopp at hver funksjon åpner og leser fila på nytt. Da blir programmet tregt, og du har skrevet den samme innlesingskoden fire ganger.
Regelen, som du skal ha med deg til Del 7: main leser dataene én gang og sender dem videre. Alle analysefunksjonene tar dataene som parameter og returnerer et svar.
En treningslogg har lengden på hver økt i minutter. Skriv en liten kjede: en funksjon som gjør minutter om til timer, en som regner totalen, en som lager en rapportlinje, og en main som binder dem sammen.
def til_timer(minutter):
return minutter / 60
def total_minutter(oekter):
total = 0
for m in oekter:
total = total + m
return total
def rapport(oekter):
minutter = total_minutter(oekter)
timer = til_timer(minutter)
return 'Trent ' + str(minutter) + ' minutter, altså ' + str(timer) + ' timer'
def main():
logg = [45, 30, 90, 60]
print(rapport(logg))
main()Utskrift:
Trent 225 minutter, altså 3.75 timerSe hvordan hvert ledd bare gjør sitt:
- til_timer kan ingenting om treningslogger. Den gjør ett tall om til et annet, og kunne like gjerne vært brukt på reisetid.
- total_minutter er den eneste som har en løkke.
- rapport regner ingenting selv. Den kaller de to andre og setter sammen teksten.
- main har dataene, kaller rapport og skriver ut. Ingen regning.
Sensorblikk: legg merke til str(...) rundt tallene i tekstsammensetningen. Uten den stopper programmet med TypeError, fordi + mellom en streng og et tall ikke er definert. Penere utskrift enn dette kommer i kap. 3.4 — her er poenget koblingen mellom funksjonene.
Merk også at kallet er main() helt til slutt, uten noen vaktsetning rundt. Sensor gir ingen uttelling for if __name__-konstruksjonen, og boka bruker den ikke.
Et bibliotek fører hvor mange dager hver utlånt bok har vært ute. Boka er forfalt når den har vært ute i mer enn 28 dager.
a) Skriv er_forfalt(dager) som returnerer True eller False.
b) Skriv antall_forfalte(utlaan) som teller hvor mange av tallene i lista som er forfalte — og som bruker funksjonen fra a).
c) Skriv gebyr(utlaan) som returnerer 30 kroner per forfalt bok, og som bruker funksjonen fra b).
Løkke 3 — Hvem eier dataene? (~7 min)
Nå kommer det strukturvalget som skiller en besvarelse som henger sammen, fra en som bare nesten gjør det: hvor dataene bor.
Svaret er kort. Dataene bor i main, og sendes ned til funksjonene som parameter. Funksjonene sender svar opp igjen med return. Ingenting går sidelengs.
main er navnet på funksjonen som styrer programmet: den skaffer dataene, kaller de andre funksjonene i riktig rekkefølge og viser resultatet.Den er ikke noe spesielt for Python — det er bare et navn, og du kaller den selv med main() nederst i fila. Boka bruker aldri vaktsetningen if __name__, fordi den ikke gir uttelling på eksamen.
Kjennetegnet på en god main er at den er kort og lesbar: hvert kall er ett ledd i kjeden, og du ser hele programmets gang på skjermen samtidig.
En main som inneholder løkker og regnestykker, har overtatt jobben til funksjonene under. Da er den vanskelig å lese, og deloppgavene kan ikke vurderes hver for seg.
Regelen: main delegerer. Den har data, kall og utskrift — ingen for-løkke som regner ut noe, ingen betingelse som avgjør et faglig spørsmål.
def main():
priser = [0.42, 0.55, 1.20, 0.98]
print('Høyeste:', hoyeste(priser))
print('Snitt:', snitt(priser))Utskrift: ingen — blokken definerer bare main. Kalles den, skriver den to linjer.
Fire linjer, og du ser hele programmet. Det er malen.
Den vanligste strukturfeilen i besvarelser er at hver funksjon skaffer dataene selv. På eksamen ser det slik ut: finn_beste() åpner fila, leser den og analyserer; så åpner lag_rapport() den samme fila på nytt.
Det gir tre problemer, og de koster poeng hver for seg:
- Innlesingskoden står fire steder i stedet for ett, og hver kopi kan ha sin egen feil.
- Funksjonene kan ikke gjenbrukes på andre data — de er låst til det ene filnavnet.
- Sensor ser ikke kjeden, som er nettopp det som gir uttelling for gjenbruk.
Riktig form er alltid den samme: main skaffer dataene én gang og sender dem videre som parameter. Fillesingen kommer i kap. 4.1, men vanen legger du deg til nå, mens dataene fremdeles er en ferdig liste.
Her endrer den første funksjonen lista den får inn: linja verdier[i] = verdier[i] + 10 skriver en ny verdi over element nummer i i lista. Resten av listeapparatet kommer i kap. 3.1 — her trenger du bare å vite at elementet blir overskrevet. Hva skriver programmet ut?
def legg_til_ti(verdier):
for i in range(len(verdier)):
verdier[i] = verdier[i] + 10
return verdier
def tell_over(verdier, grense):
antall = 0
for v in verdier:
if v > grense:
antall = antall + 1
return antall
tall = [5, 20, 15]
nye = legg_til_ti(tall)
print(tell_over(nye, 20))
print(tell_over(tall, 20))Løkke 4 — Konstanter (~5 min)
Noen verdier hører til hele programmet, ikke til én funksjon: prisen per forfalte dag, listen over gyldige distrikter, mva-satsen. De kalles konstanter, og fasitene i arkivet håndterer dem på to måter — begge godkjent.
En konstant defineres helt til venstre i fila, utenfor alle funksjoner, og skrives med store bokstaver: GEBYR_PER_BOK = 30, MAKS_LAAN = 28.
Store bokstaver er ikke et krav fra Python — det er et signal til leseren om at verdien ikke endres underveis. Konstanten kan leses fritt inne i funksjonene, akkurat som beskrevet i kap. 2.1.
GEBYR_PER_BOK = 30
def gebyr(antall_forfalte):
return antall_forfalte * GEBYR_PER_BOK
print(gebyr(3))Utskrift:
90Den andre formen er å sende konstanten inn som en parameter med standardverdi: def gebyr(antall, sats=30).
Fordelen er at funksjonen blir uavhengig av resten av fila og kan gjenbrukes med en annen sats. Ulempen er én parameter til å holde styr på.
def gebyr(antall_forfalte, sats=30):
return antall_forfalte * sats
print(gebyr(3))
print(gebyr(3, 45))Utskrift:
90
135Begge former gir full pott. Arkivets løsningsforslag bruker begge — noen ganger en global liste over distrikter, andre ganger den samme lista sendt inn som argument. Velg én og vær konsekvent i besvarelsen.
En kommune tar 240 kroner i årsgebyr per resirkuleringsdunk, men satsen kan bli endret.
a) Skriv funksjonen arsgebyr(antall_dunker) med satsen som en konstant på modulnivå.
b) Skriv den samme funksjonen på nytt, denne gangen med satsen som en parameter med standardverdi, og vis et kall som overstyrer satsen til 260.
Løkke 5 — Menyløkka (~12 min)
Nå setter vi det siste leddet på plass: programmet som spør brukeren hva det skal gjøre, og fortsetter å spørre til brukeren vil avslutte.
Menyoppgaven står i omtrent halvparten av settene (5 av 10), alltid som siste deloppgave, og den er lett å score på — for den er nesten identisk hver gang. Lær mønsteret én gang, og skriv det ned nesten uten å tenke.
while True:
vis valgene
valg = input('Valg: ')
if valg == '1':
kall funksjon 1
elif valg == '2':
kall funksjon 2
elif valg == 'q':
break
else:
si fra at valget er ugyldigBlokken over er en mal, ikke kjørbar kode.
Fem detaljer avgjør om mønsteret virker, og hver av dem er en felle som er testet på eksamen:
1. while True: — løkka skal gå til brukeren selv sier stopp, ikke et fast antall ganger.
2. break i avslutningsgrenen — det er den eneste veien ut. Uten den går programmet for alltid (felle #8 — en input-løkke som ikke terminerer riktig).
3. Valget er en streng. input() gir alltid tekst, så testen er valg == '1' med fnutter — ikke valg == 1 (felle #1 — glemt konvertering). Sammenligner du mot tallet 1, er ingen gren noen gang sann.
4. else-grenen fanger alt annet, så programmet ikke bare tier ved en skrivefeil.
5. Menyen vises på nytt hver runde, fordi den står inne i løkka.
while True: er en løkke der betingelsen alltid er sann. Den stopper bare når kroppen kjører et break — og det er nettopp det du vil ha i en meny, der antall runder bestemmes av brukeren.break avslutter løkka umiddelbart og hopper til første linje etter den. Står break inne i en funksjon, fortsetter funksjonen etter løkka; det er return som avslutter selve funksjonen.
runde = 0
while True:
runde = runde + 1
print('Runde', runde)
if runde == 3:
break
print('Ferdig etter', runde, 'runder')Utskrift:
Runde 1
Runde 2
Runde 3
Ferdig etter 3 runderHer er tellevariabelen der bare for å vise mekanikken. I en ekte meny er det brukerens svar som avgjør når break kjøres.
input() returnerer alltid en streng, uansett hva brukeren skriver. Skriver brukeren 1, får du tegnet '1', ikke tallet 1.Derfor testes menyvalg mot strenger: if valg == '1':. Testen if valg == 1: er ikke en feilmelding — den er noe verre, nemlig en test som alltid er usann, slik at menyen bare svarer «ugyldig valg» uansett hva brukeren gjør.
Vil du likevel ha et tall, konverterer du selv med int(valg) — men da må du først være sikker på at teksten faktisk er et tall, ellers krasjer programmet. Det er tema i kap. 1.4.
En dispatcher er koden som ser på valget og sender arbeidet videre til riktig funksjon. Det er en helt vanlig if/elif/else, men rollen er verdt et eget navn: dispatcheren skal bare fordele.
Hver gren består derfor av ett kall, eventuelt med en utskrift rundt. Regner grenene selv, har dispatcheren overtatt jobben til funksjonene — samme feil som en main som regner.
Grenene testes ovenfra og ned, og bare den første sanne kjøres. Rekkefølgen spiller derfor ingen rolle så lenge valgene er ulike.
Menyen trenger ett valg som betyr «ferdig». I dette faget skrives det som 'q' (for quit) eller '0', og det skal stå i menyteksten — brukeren kan ikke gjette.
Verdien som betyr «stopp», kalles en sentinel: en avtalt verdi som ikke er data, men et signal. Den samme ideen brukes når en løkke leser verdier til brukeren skriver tom tekst.
Avslutningsgrenen inneholder break, og gjerne en kort avskjedslinje før den.
Alt brukeren kan finne på å skrive, som ikke er et av valgene, havner i else. Der skriver du en kort beskjed og lar løkka gå en runde til — du skal ikke avslutte programmet fordi noen bommet på tasten.
Uten else skjer det ingenting synlig ved en skrivefeil: menyen dukker bare opp igjen, og brukeren tror programmet hang seg. Det er en av de tingene sensor ser etter i menyoppgaven, og den koster deg én linje.
Sett sammen alt: to analysefunksjoner, en funksjon som viser valgene, og menyløkka som dispatcher. Brukeren skal kunne velge 1 for høyeste pris, 2 for snittpris, og q for å avslutte.
Analysefunksjonene er de samme som før — hoyeste og snitt, begge med tomtest og return. Menyen legges i sin egen funksjon, og selve valglista i en til:
def vis_valg():
print('1 - høyeste pris i døgnet')
print('2 - snittpris i døgnet')
print('q - avslutt')
def hovedmeny(priser):
while True:
vis_valg()
valg = input('Valg: ')
if valg == '1':
print('Høyeste:', hoyeste(priser))
elif valg == '2':
print('Snitt:', snitt(priser))
elif valg == 'q':
print('Ha det.')
break
else:
print('Ugyldig valg, prøv igjen.')Utskrift: ingen når blokken bare defineres. Under ser du en kjøring, der hoyeste og snitt er de samme funksjonene som tidligere i kapitlet.
Kjøring:
1 - høyeste pris i døgnet
2 - snittpris i døgnet
q - avslutt
Valg: 1 <- skrevet av brukeren
Høyeste: 1.2
1 - høyeste pris i døgnet
2 - snittpris i døgnet
q - avslutt
Valg: x <- skrevet av brukeren
Ugyldig valg, prøv igjen.
1 - høyeste pris i døgnet
2 - snittpris i døgnet
q - avslutt
Valg: 2 <- skrevet av brukeren
Snitt: 0.7875
1 - høyeste pris i døgnet
2 - snittpris i døgnet
q - avslutt
Valg: q <- skrevet av brukeren
Ha det.I kjøringen over skrev brukeren 1, deretter x (en skrivefeil), deretter 2 og til slutt q. Linjene som er merket med en pil, er det brukeren tastet inn; pilen er lagt til her for lesbarhet og står selvsagt ikke på skjermen. Alt annet er programmets egen utskrift.
Fire ting å legge merke til:
- vis_valg er en egen funksjon. Menyløkka blir kortere og lettere å lese, og valglista står ett sted.
- hovedmeny regner ingenting. Den kaller hoyeste og snitt — den er en dispatcher.
- Skrivefeilen x fanges av else og koster ingenting: løkka går en runde til.
- Prisene sendes inn som parameter. hovedmeny vet ikke hvor de kommer fra, og kan derfor brukes uendret når dataene i Del 4 kommer fra en fil.
Sensorblikk: har du fått med while True, break i q-grenen og fnuttene rundt '1', er hovedstrukturen på plass — og strukturen er det som veier tyngst. Mangler else-grenen, er det et lite trekk, ikke et sammenbrudd.
Se på menyløkka under.
def meny(verdier):
vis_valg()
valg = input('Valg: ')
if valg == 1:
print(hoyeste(verdier))
if valg == 2:
print(snitt(verdier))a) Nevn de tre feilene som gjør at menyen ikke virker som en meny.
b) Skriv den rettede versjonen.
Fire feil går igjen, og alle fire er lette å unngå når du kjenner dem:
1. Ingen break (felle #8 — input-løkka terminerer ikke riktig). Menyen kjører for alltid, og programmet må avbrytes utenfra. Sjekk alltid at det finnes minst én vei ut av while True:.
2. Sammenligning mot tall (felle #1 — glemt konvertering). if valg == 1: er aldri sann, fordi input() gir strengen '1'. Alle grenene bommer, og menyen svarer «ugyldig valg» på alt.
3. if i stedet for elif. Med flere selvstendige if-er testes alle grenene hver runde. Det gir sjelden feil svar her, men det er unødvendig arbeid, og hvis en gren endrer valg, kan to grener kjøre.
4. Menyteksten står utenfor løkka. Da vises valgene bare første gang, og brukeren må huske dem resten av økta.
En femte, som ikke koster poeng, men tid: å legge selve regningen inn i menygrenene i stedet for å kalle funksjonene. Da har du skrevet analysen to ganger — én gang i deloppgaven og én gang i menyen.
Løkke 6 — main binder alt sammen (~6 min)
Til slutt trenger programmet et startpunkt: én funksjon som skaffer dataene og setter menyen i gang. Det er main, og den er kort.
Dette er også formen den siste deloppgaven på eksamen ber om: «Skriv main som leser inn dataene og lar brukeren velge blant funksjonene du har laget.»
main har tre linjer i ånden, uansett hvor stor oppgaven er:1. skaff dataene — i Del 4 ved å lese en fil, her ved å ha en ferdig liste,
2. kall menyen eller kjeden, med dataene som argument,
3. la funksjonene gjøre resten.
Nederst i fila står main() alene, uten innrykk. Det er den ene linja som faktisk starter programmet — alt over er definisjoner som venter.
Bind sammen alt fra kapitlet: analysefunksjonene, menyen, og en main som eier dataene. Vis også hva som skjer når brukeren avslutter med det samme.
Selve main er nesten pinlig kort — og det er meningen:
def main():
doegnpriser = [0.42, 0.55, 1.20, 0.98, 1.35, 0.61]
print('Strømpriser for døgnet, 6 timer registrert.')
hovedmeny(doegnpriser)Utskrift: ingen når blokken bare defineres. Under ser du en kjøring der brukeren avslutter med det samme, med hovedmeny, hoyeste og snitt som tidligere i kapitlet.
Kjøring:
Strømpriser for døgnet, 6 timer registrert.
1 - høyeste pris i døgnet
2 - snittpris i døgnet
q - avslutt
Valg: q <- skrevet av brukeren
Ha det.Legg merke til hva main ikke gjør: den har ingen løkke, ingen if, ingen regning. Den eier dataene, sier fra hva programmet er, og gir stafettpinnen videre.
Sensorblikk: rekkefølgen i fila er likegyldig for Python — alle def-ene kjøres før main() kalles, så main kan godt stå øverst. Det som ikke er likegyldig, er at kallet main() står helt til venstre, uten innrykk. Er det rykket inn ved et uhell, er det en del av funksjonen over, og programmet gjør ingenting.
Programmet under kjøres, og brukeren skriver 2, deretter q.
def vis():
print('1 - dobbel')
print('2 - trippel')
print('q - slutt')
def dobbel(x):
return x * 2
def trippel(x):
return x * 3
def meny(tall):
while True:
vis()
valg = input('Valg: ')
if valg == '1':
print(dobbel(tall))
elif valg == '2':
print(trippel(tall))
elif valg == 'q':
break
meny(7)a) Hvor mange ganger skrives menyteksten ut?
b) Hvilke andre linjer skrives ut, og i hvilken rekkefølge?
En turnering har lagret poengsummen til hver spiller i lista poeng, og navnene i lista navn, slik at navn[i] hører til poeng[i].
a) Skriv beste(navn, poeng) som returnerer navnet på spilleren med flest poeng.
b) Skriv antall_over(poeng, grense) som returnerer hvor mange spillere som har mer enn grense poeng.
c) Skriv hovedmeny(navn, poeng) som gjentatt viser valgene 1 (vis beste spiller), 2 (vis hvor mange som har over 20 poeng) og q (avslutt), og som kaller funksjonene fra a) og b).
d) Skriv main som har dataene og starter menyen.
De fem som koster mest på programmeringsoppgaven:
1. Kopiert kode i stedet for kall. Den samme løkka i to deloppgaver gir riktig svar, men ikke uttelling for gjenbruk — og sensor ser uttrykkelig etter at senere deloppgaver bruker de tidligere.
2. Hver funksjon skaffer dataene selv. Innlesingskoden havner fire steder, funksjonene kan ikke brukes på andre data, og kjeden forsvinner. main skaffer dataene én gang.
3. main som gjør jobben selv. Løkker og regnestykker i main betyr at deloppgavene ikke kan vurderes hver for seg. main delegerer.
4. Menyløkke uten break (felle #8 — input-løkka terminerer ikke riktig), eller med sammenligning mot tall i stedet for streng (felle #1 — glemt konvertering, valg == 1 er aldri sann).
5. Funksjoner som skriver ut i stedet for å returnere. Da kan ikke neste ledd bruke svaret, og hele kjeden stopper. Utskriften hører i menyen eller i main.
Én ting til, som ikke er en feil, men et valg som lønner seg: skriv én kort setning om det du antar (hva som skjer ved poenglikhet, om grensen er > eller >=). Sensor ber uttrykkelig om at antagelser skrives ned, og det koster deg ti sekunder.
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 Norges teknisk-naturvitenskapelige universitet. Dette er ikke offisielt studiemateriell. Les mer.