2.1 Kommandolinje, brukerinput og eval

Lese argumenter fra kommandolinjen (`sys.argv`), brukerinput og `eval` — grunnlaget for exception-oppgavene.

40 min
7 oppgaver
Kommandolinjebrukerinputeval
Din fremgang i kapitlet
0 / 7 oppgaver
Forkunnskaper. Du trenger tre ting fra Del 1:

- kap. 1.2 — lister og indeksering. sys.argv er en liste, og du plukker ut argumenter med sys.argv[1], sys.argv[2] og utsnitt som sys.argv[1:].
- kap. 1.4 — strenger og f-strenger. Alt som kommer inn fra kommandolinjen eller fra brukeren er tekst, og resultatet skrives ofte ut formatert.
- kap. 1.6 — funksjoner og lambda. Vi bruker samme tanke her: et program skal kunne kjøres med nye tall uten at du redigerer kildekoden.

Har du ikke programmert før, les Del 1 først. Ingenting i dette kapitlet er vanskelig, men alt bygger på at du er trygg på at x[0] er det første elementet i en liste.

Løkke 1 — Kommandolinjen: sys.argv

En målestasjon sender deg temperaturer i Fahrenheit. Du har skrevet et lite program som regner om til celsius, men tallet står midt i koden: hver gang en ny måling kommer, må du åpne fila, finne linja og endre den. Det er tungt, og det er lett å ødelegge noe.

Løsningen er å gi tallet til programmet når du starter det. I terminalen skriver du programnavnet og deretter verdiene, atskilt med mellomrom:

python3 fahrenheit.py 98.6

Python samler alt du skrev på den linja i en liste, og gir deg den gjennom modulen sys.

`sys.argv` — argumentene fra kommandolinjen

Når du starter et program fra terminalen, legger Python alle ordene på kommandolinjen i en liste av strenger og kaller den sys.argv. Du får tilgang til den etter import sys. Element nummer 0 er navnet på programfila; dine egne argumenter ligger fra indeks 1 og utover. Alle elementene er tekst — også de som ser ut som tall.

Kjørt som python3 vis.py 12.5 grader:

import sys
print(sys.argv)
print(sys.argv[0])

Utskrift:

['vis.py', '12.5', 'grader']
vis.py

✏️Eksempel 1: Se hva `sys.argv` faktisk inneholder

Du lager fila vis_argumenter.py og kjører den som python3 vis_argumenter.py 12.5 grader. Hva inneholder sys.argv, hvor mange elementer har den, og hva står på indeks 0 og 1?

Skriv ut alt, så ser du det:

import sys
print('Hele lista:', sys.argv)
print('Antall ord:', len(sys.argv))
print('Programnavn:', sys.argv[0])
print('Første argument:', sys.argv[1])

Utskrift:

Hele lista: ['vis_argumenter.py', '12.5', 'grader']
Antall ord: 3
Programnavn: vis_argumenter.py
Første argument: 12.5

Legg merke til tre ting. Lista har tre elementer selv om du bare ga to argumenter, fordi programnavnet ligger først. Begge argumentene står i anførselstegn i utskriften — de er strenger, ikke tall. Og 12.5 er ikke et flyttall før du selv konverterer det med float.

📝Oppgave 1

(Innstegsoppgave, sjanger A — kodesporing, altså «hva skriver programmet ut?».) Fila lengde.py inneholder koden under, og kjøres som python3 lengde.py 3 4 5. Hva skrives ut?

import sys
print(len(sys.argv))
print(sys.argv[1])

`len(sys.argv)` — hvor mange ord sto på kommandolinjen
len(sys.argv) gir antall elementer i argumentlista, altså programnavnet pluss dine argumenter. Krever programmet to argumenter, skal len(sys.argv) være 3. Dette er den vanlige måten å sjekke om brukeren ga nok argumenter før du prøver å bruke dem.

Kjørt som python3 sjekk.py 7:

import sys
if len(sys.argv) < 3:
    print('For få argumenter')
else:
    print('Nok argumenter')

Utskrift:

For få argumenter
✏️Eksempel 2: Fra streng til tall

Skriv et program fahrenheit.py som tar én temperatur i Fahrenheit på kommandolinjen og skriver den ut i celsius med én desimal. Omregningen er C=(F32)5/9C = (F - 32)\cdot 5/9.

Argumentet må gjennom float før du kan regne med det:

import sys
grader_f = float(sys.argv[1])
grader_c = (grader_f - 32) * 5 / 9
print(f'{grader_f} F er {grader_c:.1f} C')

Utskrift:

98.6 F er 37.0 C

Kjørt som python3 fahrenheit.py 98.6. Merk at grader_f skrives ut som 98.6 — den er et flyttall nå, ikke strengen '98.6'. Hadde du glemt float, ville grader_f - 32 gitt en TypeError, fordi Python nekter å trekke et tall fra en tekst.

📝Oppgave 2

(Midtveisnivå, sjanger A — kodesporing.) Fila summer.py kjøres som python3 summer.py 12 30. Hva skrives ut, linje for linje?

import sys
a = sys.argv[1]
b = sys.argv[2]
print(a + b)
print(int(a) + int(b))

Løkke 2 — Brukerinput med input

Kommandolinjen er raskest når du kjører programmet mange ganger. Men noen ganger vil du at programmet skal spørre underveis — for eksempel når du vet at brukeren skal fylle ut flere felt etter hverandre. Da bruker du input.

Det viktigste å vite er at input alltid gir deg en streng, uansett hva brukeren skriver. Skriver brukeren 5, får du tegnet '5', ikke tallet 5.

`input(melding)` — les én linje fra brukeren
input skriver ut meldingen du gir den (uten linjeskift etterpå), venter til brukeren trykker Enter, og returnerer det som ble skrevet — alltid som en streng. Skal du regne med verdien, må du konvertere den selv med int eller float.

Her skriver brukeren 5:

svar = input('Antall målinger: ')
print(svar, type(svar))

Utskrift:

Antall målinger: 5 <class 'str'>

type(svar) viser str. Legg merke til at ledeteksten Antall målinger: og svaret havner på samme linje, fordi input ikke skriver linjeskift etter meldingen.

✏️Eksempel 3: Flere `input`-kall etter hverandre

Programmet stasjon.py spør om et stasjonsnavn og et antall døgn, og skriver en oppsummering. Brukeren svarer Blindern og deretter 7. Hva skriver programmet ut?

navn = input('Stasjonsnavn: ')
n = int(input('Antall døgn: '))
print(f'{navn}: {n} døgn logget')

Utskrift:

Stasjonsnavn: Antall døgn: Blindern: 7 døgn logget

Sporingen er verdt å gjøre nøyaktig. input('Stasjonsnavn: ') skriver ledeteksten og venter; navn blir strengen 'Blindern'. Neste input skriver sin ledetekst og gir strengen '7', som int gjør til tallet 7. Siden ingen av ledetekstene avsluttes med linjeskift, står de på samme linje som resultatet i utskriften over.

På eksamen får du ikke skrevet inn noe — der er poenget alltid å avgjøre hvilken type verdien har, og hva som skjer hvis konverteringen mislykkes.

📝Oppgave 3

(Midtveisnivå, sjanger A — kodesporing.) Programmet under kjøres, og brukeren skriver først 4, deretter 5. Hva skrives ut?

a = input('a: ')
b = input('b: ')
print(a + b)
print(int(a) * int(b))

`int(streng)` og `float(streng)` — tekst til tall
int('42') gir heltallet 42, og float('3.5') gir flyttallet 3.5. Konverteringen er streng: int godtar bare noe som ser ut som et helt tall, mens float også godtar desimaltall og eksponentform som '1e-3'. Mislykkes konverteringen, avbrytes programmet med feilen ValueError.

print(int('42') + 1)
print(float('3.5') * 2)

Utskrift:

43
7.0

Merk at float('3.5') * 2 gir 7.0 og ikke 7 — resultatet av flyttallsregning er alltid et flyttall.

Løkke 3 — eval og ryddig avslutning med sys.exit

Noen ganger vil du at brukeren skal kunne oppgi en hel formel, ikke bare et tall — for eksempel hvilken funksjon et program skal derivere eller integrere. Da holder det ikke med float: du trenger å gjøre om en tekst til et Python-uttrykk. Det gjør eval.

Og gir brukeren for få argumenter, vil du stoppe programmet med en forståelig beskjed i stedet for å la det kollapse med en IndexError. Det gjør sys.exit.

`eval(uttrykkstreng)` — regn ut et Python-uttrykk som står i en tekst
eval tar en streng, tolker innholdet som et Python-uttrykk og returnerer verdien. Strengen '2 + 3 * 4' blir altså regnet ut med vanlige presedensregler og gir 14. Uttrykket kan bruke variabler og funksjoner som finnes i programmet i det øyeblikket eval kalles.

uttrykk = '2 + 3 * 4'
print(eval(uttrykk))
print(eval(uttrykk) + 1)

Utskrift:

14
15

eval returnerer en verdi du kan regne videre med — derfor gir eval(uttrykk) + 1 15.

✏️Eksempel 4: La brukeren oppgi funksjonsuttrykket

Skriv et program som spør brukeren om et uttrykk i x, setter x = 2.0 og skriver ut verdien. Brukeren skriver x**2 + sqrt(x). Hva blir utskriften?

from math import sqrt
uttrykk = input('f(x) = ')
x = 2.0
print(eval(uttrykk))

Utskrift:

f(x) = 5.414213562373095

Merk to detaljer. sqrt må være importert i programmet — eval bruker de navnene som finnes der den kalles, så uten from math import sqrt ville uttrykket gitt en NameError. Og x må være satt før eval, ellers samme feil.

Verdien er 22+22^2 + \sqrt{2}, som Python skriver ut med full flyttallspresisjon. Ledeteksten f(x) = står først på linja, som alltid med input.

📝Oppgave 4

(Midtveisnivå, sjanger A — kodesporing.) Hva skriver programmet under ut? Pass på presedensreglene i begge uttrykkene.

uttrykk = '10 - 2 * 3'
svar = eval(uttrykk)
print(uttrykk, '=', svar)
print(eval('2 ** 3 ** 2'))

`sys.exit(melding)` — avslutt programmet med en beskjed
sys.exit stopper programmet umiddelbart. Gir du den en tekst, blir teksten skrevet til feilkanalen (det du ser i terminalen sammen med feilmeldinger), og programmet avslutter med en status som markerer at noe gikk galt. Dette er standardmåten å håndtere «brukeren ga for få argumenter» på.

import sys
if len(sys.argv) < 2:
    sys.exit('Bruk: python vekst.py <rate>')
print('Raten er', sys.argv[1])

Utskrift:

Raten er 0.04

Utskriften over er fra kallet python3 vekst.py 0.04, som hopper over if-blokken. Kjører du programmet uten argumenter, nås aldri print-linja; i stedet skriver sys.exit denne teksten til feilkanalen og avslutter:

Bruk: python vekst.py <rate>
✏️Eksempel 5: Et robust kommandolinjeprogram

Skriv vekstrate.py, som tar en startverdi og en årlig vekstrate på kommandolinjen og skriver verdien etter ett år med to desimaler. Programmet skal gi en forståelig beskjed hvis antall argumenter er feil.

Sjekk antallet først, konvertér deretter:

import sys
if len(sys.argv) != 3:
    sys.exit('Bruk: python vekstrate.py <startverdi> <rate>')
start = float(sys.argv[1])
rate = float(sys.argv[2])
print(f'Etter ett år: {start * (1 + rate):.2f}')

Utskrift:

Etter ett år: 1242.00

Kjørt som python3 vekstrate.py 1200 0.035. Rekkefølgen er det som gjør programmet robust: hadde float(sys.argv[1]) stått først, ville et kall uten argumenter gitt IndexError i stedet for beskjeden din.

Legg merke til at koden er kort. Sensor forventer ingen main-funksjon og ingen ekstra utskrift — bare det oppgaven ber om.

📝Oppgave 5
Eksamensnivå, sjanger E

Programmet skal skrive ut summen av to tall gitt på kommandolinjen, altså gi 9.5 når det kjøres som python3 sum2.py 4 5.5. Hvilket alternativ hører på den tomme linja?

import sys
# HER MANGLER ÉN LINJE
print(sum_to)

a) sum_to = sys.argv[1] + sys.argv[2]
b) sum_to = float(sys.argv[0]) + float(sys.argv[1])
c) sum_to = float(sys.argv[1]) + float(sys.argv[2])
d) sum_to = int(sys.argv[1]) + int(sys.argv[2])

📝Oppgave 6
Eksamensnivå, sjanger E…

Skriv programmet middel.py som tar tre temperaturmålinger på kommandolinjen og skriver ut middeltemperaturen med to desimaler.

a) Programmet skal avbryte med en forståelig beskjed hvis brukeren ikke gir nøyaktig tre tall.
b) Vis utskriften når programmet kjøres som python3 middel.py 4.2 7.8 6.1.

📝Oppgave 7
Eksamensnivå, sjanger O

Programmet doser.py skal ta en pasientvekt og en dose per kilo på kommandolinjen og skrive ut total dose. Det virker ikke. Finn og beskriv alle feilene, og skriv den rettede koden.

import sys
if len(sys.argv) != 2:
    sys.exit('Bruk: python doser.py <vekt> <dose>')
vekt = int(sys.argv[0])
dose = float(sys.argv[1])
print(f'Total dose: {vekt * dose:.1f} mg')

API- og konstruksjonsliste

Begrepsbank

Begrepsbanken er flashcard-/repetisjonsstoff — den gjentar det du nettopp har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder kjernestoffet.

`import sys` — hva importen gir deg
sys er en innebygd modul med informasjon om og kontroll over selve kjøringen. I IN1900 trenger du bare to ting fra den: sys.argv (kommandolinjeargumentene) og sys.exit (avslutt nå). Uten import sys gir sys.argv en NameError, som er en typisk plantet feil i «finn feilen»-oppgaver.
`sys.argv[0]` — programnavnet

Element 0 i argumentlista er navnet på skriptet slik du skrev det på kommandolinjen. python3 doser.py 72 0.5 gir sys.argv[0] lik 'doser.py'. Konsekvensen du må huske: dine egne argumenter starter på indeks 1, og len(sys.argv) er alltid én mer enn antall argumenter du ga.

`sys.argv[1:]` — alle argumentene uten filnavnet

Utsnittet sys.argv[1:] gir en ny liste med alle dine argumenter. Det er praktisk når antallet varierer, for eksempel når programmet skal behandle vilkårlig mange målinger.

Kjørt som python3 utsnitt.py 1.5 2.5:

import sys
print(sys.argv[1:])
for arg in sys.argv[1:]:
    print(arg, float(arg) * 2)

Utskrift:

['1.5', '2.5']
1.5 3.0
2.5 5.0

Merk at utsnittet gir en liste, mens sys.argv[1] gir ett element — samme regel som for vanlige lister i kap. 1.2.

`type(x)` og `str(tall)` — typen fram og tilbake
type(x) forteller hvilken type en verdi har, og skrives ut i formen <class 'str'>. str(tall) går motsatt vei av int/float: den gjør et tall til tekst, slik at + kan lime det sammen med annen tekst.

x = '7'
print(type(x))
print(type(int(x)))
print(str(3.5) + ' meter')

Utskrift:

<class 'str'>
<class 'int'>
3.5 meter
Hvorfor `float('4.0')` virker og `int('4.0')` ikke gjør det
float tolker teksten som et desimaltall og godtar både '4', '4.0' og '4e0'. int krever at teksten er et helt tall skrevet uten punkt, så '4.0' avvises med ValueError selv om verdien er hel. Trenger du et heltall fra '4.0', går du via flyttall: int(float('4.0')) gir 4.
`python skript.py 6 0` — kallet eksamensoppgavene bruker

Eksamensoppgavene i sjanger C oppgir alltid et konkret kall, og du skal svare hva som skjer. Førstesteget er mekanisk: skriv opp lista. python skript.py 6 0 gir sys.argv lik ['skript.py', '6', '0'], altså tre elementer, der sys.argv[1] er '6' og sys.argv[2] er '0'. Er det bare oppgitt python skript.py 6, finnes ikke sys.argv[2], og et forsøk på å bruke den gir IndexError.

`input()` uten ledetekst

Kaller du input() uten argument, skrives ingen melding — programmet venter bare. Det er vanlig når ledeteksten allerede er skrevet med et eget print. Returverdien er den samme: alltid en streng, uten linjeskiftet brukeren avsluttet med.

`eval` mot `float` på samme streng
float('2 + 3') gir ValueError, fordi teksten ikke er ett tall. eval('2 + 3') gir 5, fordi teksten er et gyldig Python-uttrykk. Regelen: float/int for enkeltverdier, eval når brukeren skal kunne oppgi en formel. eval er også kraftigere enn du vil ha i et vanlig program — bruk den bare der oppgaven ber om et brukeroppgitt uttrykk.
Strengsum mot tallsum
'12' + '30' gir '1230' (sammenliming), mens 12 + 30 gir 42 (addisjon). Fordi både input og sys.argv leverer strenger, er dette den vanligste nybegynnerfeilen i Del 2. Konvertér ved innlesingen, så slipper du å tenke på det senere: x = float(sys.argv[1]).
Rekkefølgen i et robust kommandolinjeprogram

Mønsteret er fast og verdt å lære utenat: 1) import sys; 2) sjekk len(sys.argv) og avbryt med sys.exit(melding) hvis antallet er galt; 3) konvertér hvert argument med float eller int; 4) regn; 5) skriv ut med f-streng. Bytter du om steg 2 og 3, får brukeren en rå IndexError i stedet for beskjeden din.

Repetisjon — sjekk deg selv før du går videre

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.