Tilbake
1.4

1.4 Input og input-valideringsløkke

Lese brukerinput, konvertere til tall, og løkken som spør på nytt til verdien er lovlig — et fast ledd i programmeringsoppgavene.

40 min
7 oppgaver
Inputinput-valideringsløkke
Din fremgang i kapitlet
0 / 7 oppgaver
Forkunnskaper:

- kap. 1.1 — Variabler, datatyper og konvertering: at tekst må gjøres om med int eller float før du regner, og at .isdigit() sjekker om en tekst er sifre alene.
- kap. 1.2 — Boolsk logikk og betingelser: sammenligninger, and/or, og at and kortslutter.
- kap. 1.3 — Løkker: while og løkketerminering.

Tar du med deg to setninger derfra, la det være disse: int('abc') stopper programmet med ValueError, og en while-løkke stopper bare hvis noe i kroppen endrer betingelsen.

Om def og return: kapitlet pakker valideringsløkka inn i en funksjon, fordi det er slik eksamensoppgaven ber om den («skriv les_time() som …»). Selve håndverket kommer i kap. 2.1; her holder lesemåten fra kap. 1.2: def navn(): starter en oppskrift, og return svar sender svar tilbake til den som kalte den.

Løkke 1 — Å spørre brukeren (~8 min)

En billettautomat på en ferge spør hvor mange passasjerer det er. Brukeren skriver noe, og programmet regner videre. Det er hele mekanismen, og den har én funksjon: input.

Det som gjør den vanskeligere enn den ser ut, er at brukeren kan skrive hva som helst — tre, -2, ingenting i det hele tatt. Programmet må tåle alt sammen.

`input(melding)`

Skriver ut meldingen, venter på at brukeren skriver en linje og trykker enter, og gir linja tilbake.

Programmet stopper helt mens det venter. Ingenting annet skjer før brukeren har trykket enter.

Meldingen er valgfri: input() uten argument venter uten å skrive noe. Men da vet ikke brukeren hva han skal gjøre, så på eksamen skal du alltid ha med en melding.

Ledetekst

Meldingen input skriver ut, kalles en ledetekst (på engelsk prompt). Den skrives uten linjeskift, så brukeren skriver på samme linje.

Derfor slutter en god ledetekst alltid med et mellomrom: input('Antall passasjerer: '). Uten mellomrommet klistrer svaret seg inntil kolonet.

Ledeteksten skal si hva som forventes, ikke bare hva som spørres om. «Time (0–23): » er bedre enn «Time: », fordi den forteller brukeren hva som er lovlig før han gjetter feil.

`input()` gir alltid tekst

Uansett hva brukeren skriver, er resultatet en streng. Skriver han 7, får du teksten '7', ikke tallet 7.

Konsekvensen er den samme som ved filinnlesing: du kan ikke regne, sammenligne eller sortere før du har konvertert. input('Alder: ') + 1 gir TypeError, og input('Alder: ') * 2 gjentar teksten i stedet for å doble tallet.

Dette er felle #1 i bokas feilregister — glemt int() eller float() — og den mest kostbare enkeltfeilen i faget.

Linjeskiftet brukeren trykker, er derimot ikke med. input fjerner det selv.

`int(input(...))` og `float(input(...))`

Den vanlige måten å lese et tall på: antall = int(input('Antall: ')).

Den innerste funksjonen kjøres først — brukeren spørres, og teksten han skrev sendes rett videre til int.

Men: skriver brukeren noe som ikke er et helt tall, stopper programmet med ValueError før du får sjekket noe som helst. Derfor er denne formen bare trygg når du på forhånd vet at inndata er gyldige. I alle andre tilfeller må du sjekke først — det er hele poenget med resten av kapitlet.

✏️Eksempel 1: Fergebilletten

Automaten spør om antall passasjerer og skriver ut prisen, som er 95 kroner per person. Hva skjer hvis du glemmer konverteringen?

Først den gale veien:

# ingen utskrift her — funksjonen bare defineres; den kalles i kjøringen under
def vis_pris():
    antall = input('Antall passasjerer: ')
    print('Pris:', antall * 95)

Kjørt med vis_pris().

Kjøring:

Antall passasjerer: 3
Pris: 33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333

Ingen feilmelding — bare teksten 3 gjentatt 95 ganger. Det er felle #1 i sin mest forvirrende form.

Med konvertering blir det som det skal:

# ingen utskrift her — funksjonen bare defineres; den kalles i kjøringen under
def vis_pris():
    antall = int(input('Antall passasjerer: '))
    print('Pris:', antall * 95)

Kjørt med vis_pris().

Kjøring:

Antall passasjerer: 3
Pris: 285

Legg merke til at ledeteksten og brukerens svar står på samme linje. Det er slik en terminal ser ut: 3 er det brukeren skrev.

📝Oppgave 1

(Innstegsoppgave — minimal sporing. Sjanger B — kodesporing, altså «hva skriver programmet ut?».) Brukeren skriver 12 og trykker enter. Hva skriver programmet ut?

svar = input('Tall: ')
print(svar + svar)
print(int(svar) + int(svar))

Løkke 2 — Løkka som spør på nytt (~14 min)

Brukeren skriver feil. Ikke av vrangvilje, men fordi han ikke leste ledeteksten, eller fordi han traff feil tast. Et program som stopper med en feilmelding første gang det skjer, er ubrukelig — og på eksamen er det poengtap.

Løsningen er alltid den samme: spør igjen, og igjen, til svaret er lovlig. Det mønsteret heter en input-valideringsløkke, og det er ett av mønstrene du skal kunne skrive fra bunnen.

Gyldighetstest

Det boolske uttrykket som avgjør om et svar kan godtas. Skriv den ut for deg selv i ord før du skriver koden — det er der oppgaven faktisk løses.

De tre formene som går igjen på eksamen:

- Intervall: verdien skal ligge mellom to grenser.
- Lengde: teksten skal ha et bestemt antall tegn.
- Format: teksten skal bestå av bare sifre, eller begynne med bestemte tegn.

Testen brukes i to former: som «godta hvis …» i en if, og som «spør på nytt hvis …» i while-betingelsen. Den siste er den negerte av den første, og der oppstår halvparten av feilene.

Intervalltest

«Verdien skal ligge mellom to grenser.» Skrives som en kjedet sammenligning: 0 <= time <= 23.

Den negerte formen, altså «spør på nytt», er time < 0 or time > 23. Legg merke til at and blir til or når du negerer — dette er den vanligste tankefeilen i valideringsløkker.

Vær presis på om grensene er med. «Time mellom 0 og 23» betyr som regel at både 0 og 23 er lovlige, altså <= i begge ender. Er oppgaveteksten uklar, skriver du kort hva du antar — sensor godtar rimelige antakelser når de er skrevet ned.

Lengdetest

«Teksten skal ha nøyaktig så mange tegn.» Skrives len(tekst) != 7 som spør-på-nytt-betingelse, eller len(tekst) == 7 som godkjenning.

len teller tegn, og et mellomrom er også et tegn. Skriver brukeren AB 12345, er lengden 8 og ikke 7.

Kombiner gjerne lengde og format: et lovlig kjennemerke kan kreve både riktig antall tegn og at de siste er sifre.

`.isdigit()` som port før konvertering
tekst.isdigit() er True bare når hvert eneste tegn er et siffer. Både '-5', '3.5', '12 ' og den tomme teksten gir False.

Nytten er å slippe unna ValueError. Sjekk først, konvertér etterpå:

if svar.isdigit() and int(svar) <= 23:

Fordi and kortslutter — se kap. 1.2 — kjøres int(svar) bare når teksten faktisk er sifre. Bytter du om rekkefølgen på de to sidene, krasjer programmet på nøyaktig den inndataen testen skulle beskytte mot.

Merk begrensningen: .isdigit() godtar ikke negative tall. Skal negative verdier være lovlige, må du håndtere minustegnet selv.

Sjekk før konvertering — rekkefølgeregelen
Test teksten mens den fortsatt er tekst. Konvertér først når den er godkjent.

Snur du rekkefølgen — int(input(...)) først og sjekk etterpå — er det for sent: programmet stopper på ValueError før sjekken i det hele tatt blir kjørt.

Dette er den ene setningen som skiller en valideringsløkke som virker fra en som ser ut som den virker. Skriv den på kladdearket før du begynner på en sjanger H-deloppgave.

📜Input-valideringsløkka

Bokas kanoniske mønster for sjanger H, og et av dem du skal kunne skrive fra bunnen. Fire faste deler:

1. Spør én gang før løkka.
2. while med den negerte gyldighetstesten — «så lenge svaret IKKE er lovlig».
3. Feilmelding og nytt spørsmål inne i løkka.
4. Returnér den godkjente verdien etter løkka, konvertert til riktig type.

# ingen utskrift her — funksjonen bare defineres; den kalles i kjøringen under
def les_time():
    svar = input('Time (0-23): ')
    while not svar.isdigit() or int(svar) > 23:
        print('Ugyldig time. Skriv et helt tall mellom 0 og 23.')
        svar = input('Time (0-23): ')
    return int(svar)

Kjørt med print('Du valgte time', les_time()).

Kjøring:

Time (0-23): abc
Ugyldig time. Skriv et helt tall mellom 0 og 23.
Time (0-23): 30
Ugyldig time. Skriv et helt tall mellom 0 og 23.
Time (0-23): 14
Du valgte time 14

Brukeren skrev først abc, deretter 30, og til slutt 14. Løkka spurte tre ganger og godtok først det siste svaret.

Legg merke til tre ting. Spørsmålet står to steder — én gang før løkka og én gang inne i den; det er prisen for denne formen. .isdigit() står først i betingelsen, så int(svar) aldri kjøres på noe som ikke er sifre. Og konverteringen skjer i return, etter at svaret er godkjent.

Den nedre grensen trengs ikke her: .isdigit() er allerede usann for '-1', så negative tall kommer aldri gjennom.

📜Valideringsløkka med `while True:` og `break`

Den andre gyldige formen, som slipper å gjenta spørsmålet. Begge gir full pott — velg den du husker best under press.

# ingen utskrift her — funksjonen bare defineres; den kalles i kjøringen under
def les_time():
    while True:
        svar = input('Time (0-23): ')
        if svar.isdigit() and int(svar) <= 23:
            return int(svar)
        print('Ugyldig time. Skriv et helt tall mellom 0 og 23.')

Kjørt med print('Du valgte time', les_time()).

Kjøring:

Time (0-23): 40
Ugyldig time. Skriv et helt tall mellom 0 og 23.
Time (0-23): 9
Du valgte time 9

Brukeren skrev først 40, som er utenfor intervallet, og deretter 9.

Her står gyldighetstesten i sin positive form — «godta hvis …» — og det er ofte lettere å tenke riktig. return inne i løkka avslutter både løkka og funksjonen, så noe eget break trengs ikke.

Skal funksjonen ikke returnere, men bare sette en variabel, bruker du break i stedet for return og henter verdien etter løkka.

📝Oppgave 2
Sjanger B

Brukeren skriver -3, deretter 0, deretter 5. Hvor mange ganger vises ledeteksten, og hva returnerer funksjonen?

def les_antall():
    svar = input('Antall: ')
    while not svar.isdigit():
        print('Skriv et positivt heltall.')
        svar = input('Antall: ')
    return int(svar)

📝Oppgave 3
Eksamensnivå, sjanger H

En resirkuleringsstasjon registrerer leveringer.

a) Skriv les_kilo() som spør brukeren om antall kilo, og gjentar spørsmålet til svaret er et helt tall mellom 1 og 500. Funksjonen skal returnere tallet.
b) Forklar med én setning hvorfor .isdigit() må stå før konverteringen i betingelsen.

📝Oppgave 4
Sjanger D

Funksjonen skal spørre om et kjennemerke og gjenta spørsmålet til teksten er nøyaktig sju tegn lang.

def les_kjennemerke():
    svar = input('Kjennemerke: ')
    while KODE1:
        print('Kjennemerket skal ha sju tegn.')
        svar = input('Kjennemerke: ')
    return svar

Blokken er merket som ikke-kjørbar fordi KODE1 er en plassholder, ikke gyldig Python.

Hvilket alternativ er riktig?

a) len(svar) != 7
b) len(svar) == 7
c) svar != 7
d) len(svar) > 7

Løkke 3 — Å la brukeren si «ferdig» (~10 min)

En annen fast form: brukeren skal legge inn så mange verdier han vil, og selv bestemme når det er nok. Da trenger du en avtalt verdi som betyr «stopp». Den kalles en sentinel.

Sentinel

En avtalt verdi som betyr «nå er jeg ferdig» — en vaktpost på slutten av inndataene.

Den vanligste sentinelen er tom input: brukeren trykker bare enter. Da er svaret den tomme teksten '', og løkkebetingelsen blir while navn != '':.

Sentinelen må være en verdi som ikke kan forveksles med gyldige data. 0 er en dårlig sentinel for et antall, fordi null kan være et ekte svar; -1 eller tom input er trygge.

Si alltid i ledeteksten hva sentinelen er. «Navn (blank linje for å avslutte): » — ellers vet ikke brukeren hvordan han kommer seg ut.

Tom input som avslutning

Trykker brukeren bare enter, gir input den tomme teksten ''. Den har lengde 0 og teller som usann i en betingelse — se kap. 1.2.

Derfor er while navn != '': og while navn: to skrivemåter for det samme. Begge er gyldige; den første er tydeligst for en leser.

Merk forskjellen fra et mellomrom: skriver brukeren mellomrom og enter, er teksten ' ', som har lengde 1 og er sann. Vil du behandle den som tom, må du fjerne mellomrommene først.

Feilmelding som forteller hva som er galt

Når et svar avvises, skal programmet si hva som forventes — ikke bare at noe var galt.

«Ugyldig» hjelper ingen. «Skriv et helt tall mellom 1 og 500» lar brukeren rette seg.

På eksamen er feilmeldingen ofte eksplisitt nevnt i oppgaveteksten («skriv en feilmelding og spør på nytt»), og da er den et poeng i seg selv. Den koster én linje.

Gyldighetstesten som egen funksjon

Er testen sammensatt, skiller du den ut: def gyldig_temp(tekst): som returnerer True eller False, og en while not gyldig_temp(svar): som bruker den.

Det gir tre fordeler sensor belønner: løkka blir kort og lesbar, testen kan gjenbrukes av senere deloppgaver, og du kan teste den for seg selv uten å måtte skrive inn noe.

Gjenbruk av egne funksjoner er et gjennomgående krav i dette faget — senere deloppgaver bygger på de tidligere, og kopiert kode gir dårligere uttelling enn et funksjonskall.

Å returnere den validerte verdien

En valideringsfunksjon skal returnere den godkjente verdien, ikke skrive den ut. Da kan den gjenbrukes overalt i programmet.

Returtypen skal være den kalleren trenger: return int(svar) når verdien skal regnes med, return svar når det er en tekst.

Dette er et gjennomgående sensorkrav i faget: senere deloppgaver bygger på de tidligere, og en funksjon som bare skriver ut, kan ikke gjenbrukes. En funksjon skal gjøre én ting.

✏️Eksempel 2: Innsamlingen som stopper på blank linje (eksamensnivå)

En bruktbutikk registrerer varer til den ansatte er ferdig. For hver vare spørres det om navn (blank linje avslutter) og pris. Til slutt skrives antall varer og totalsummen ut.

# ingen utskrift her — funksjonen bare defineres; den kalles i kjøringen under
def registrer_varer():
    antall = 0
    total = 0
    navn = input('Vare (blank linje avslutter): ')
    while navn != '':
        pris = input('Pris for ' + navn + ': ')
        while not pris.isdigit():
            print('Prisen skal være et helt antall kroner.')
            pris = input('Pris for ' + navn + ': ')
        antall += 1
        total += int(pris)
        navn = input('Vare (blank linje avslutter): ')
    return antall, total

Kjørt med a, s = registrer_varer() print('Antall:', a, 'Total:', s).

Kjøring:

Vare (blank linje avslutter): stol
Pris for stol: 250
Vare (blank linje avslutter): lampe
Pris for lampe: billig
Prisen skal være et helt antall kroner.
Pris for lampe: 120
Vare (blank linje avslutter): 
Antall: 2 Total: 370

Brukeren registrerte stol til 250, deretter lampe med et ugyldig prissvar (billig) før han skrev 120, og avsluttet med en blank linje.

Tre ting er verdt å merke seg.

Den ytre løkka er sentinelløkka: den stopper på tom input. Den indre er valideringsløkka for prisen. De er to helt uavhengige mønstre, nøstet i hverandre.

Akkumulatorene antall og total settes før den ytre løkka, akkurat som i kap. 1.3. Sto de inne i løkka, ville de nullstilt seg for hver vare.

Funksjonen returnerer to verdier, skilt med komma, og kalleren pakker dem ut med a, s = .... Den formen står grundig forklart i Del 2.

Uttelling: sensor er ute etter at (1) løkka faktisk gjentar spørsmålet ved ugyldig svar, (2) sentinelen er nevnt i ledeteksten, og (3) verdiene konverteres før de summeres. Alt tre er billige poeng.

📝Oppgave 5
Sjanger B

Brukeren skriver 4, deretter 7, deretter blank linje. Hva skriver programmet ut?

sum = 0
svar = input('Tall (blank avslutter): ')
while svar != '':
    sum = sum + int(svar)
    svar = input('Tall (blank avslutter): ')
print(sum)

📝Oppgave 6
Eksamensnivå, sjanger H

En værstasjon skal registrere døgnets målinger.

a) Skriv les_temperatur() som spør om en temperatur i hele grader, godtar verdier fra 50-50 til og med 50, og gjentar spørsmålet med feilmelding ellers. Negative verdier skal altså være lovlige — og da kan du ikke bruke .isdigit() alene.
b) Forklar med én setning hvordan du løser at .isdigit() avviser minustegnet.

📝Oppgave 7
Eksamensnivå, sjanger B

Hva er galt med denne funksjonen, og hva skjer når brukeren skriver abc?

def les_alder():
    svar = input('Alder: ')
    while not svar.isdigit():
        print('Skriv et helt tall.')
    return int(svar)

a) Beskriv med én setning hva som skjer.
b) Skriv den rettede funksjonen.

API- og konstruksjonsliste
Repetisjon — de seks setningene som må sitte

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.