1.1 Variabler, datatyper og konvertering
Tall, tekst og boolske verdier; heltalls- vs. flyttallsdeling; og int()/float()/str()-konvertering — som er første fallgruve ved fil- og input-data.
Dette kapitlet er grunnmuren. Ingenting av det du gjør senere i faget virker uten det.
- Variabler, datatyper og konvertering står i 10 av 10 eksamenssett i arkivet 2014–2019, altså 100 %. Det er ikke fordi det finnes en egen «datatype-oppgave» — det er fordi hver eneste programmeringsoppgave leser data utenfra, og data utenfra kommer alltid inn som tekst som må gjøres om til tall.
- Regneoperatorene // (heltallsdeling) og % (rest) er faste innslag i sjanger B — kodesporing, altså oppgavetypen «hva skriver dette programmet ut?». Den sjangeren er i alle settene og gir 1–3 % per deloppgave.
- De samme to operatorene bærer tidsregningen (sekunder om til timer, minutter og sekunder) som går igjen i programmeringsoppgavene.
Dette må sitte. Boka bruker tre nivåer: må sitte (høyeste prioritet), må kunne og bør kjenne til. Kapittel 1.1 ligger på det høyeste — ikke fordi stoffet er vanskelig, men fordi en glemt int() ødelegger resten av en ellers riktig besvarelse.
Har du aldri sett et program i det hele tatt, kan du gjerne bruke en time på en mykere inngang først:
- Programmering med Python — de aller første stegene, skrevet for videregående.
- Programmering med Python — samme stoff, enda roligere tempo.
- Variabler, datatyper og uttrykk — samme grunnstoff i et parallelt universitetsemne, hvis du vil ha en ekstra forklaring ved siden av denne.
Ingen av dem er nødvendige. Kapitlet her forklarer alt fra bunnen.
Løkke 1 — Å gi noe et navn (~8 min)
På en strømregning står det tre tall: forbruket i kilowattimer, prisen per kilowattime og fastbeløpet. Skal du regne ut hva regningen blir, må du holde de tre tallene fra hverandre mens du regner. Du gir dem navn — «forbruk», «pris», «fastbeløp» — og regner med navnene.
Det er nøyaktig det et program gjør. Et navn som holder på en verdi, kalles en variabel, og å sette en verdi inn i den kalles en tilordning.
Et navn som peker på en verdi maskinen husker mens programmet kjører.
Navnet velger du selv. Det må begynne med en bokstav eller understrek, kan inneholde bokstaver, tall og understrek, og skiller mellom store og små bokstaver: pris og Pris er to forskjellige variabler. Norske bokstaver er lov i Python 3, men boka holder seg til aa, oe og aa-frie navn der det er naturlig, fordi eksamensfasitene gjør det.
En variabel har ingen fast type. Den peker på det du sist la i den, og kan senere peke på noe helt annet.
Setter verdien på høyre side inn i navnet på venstre side. Likhetstegnet i Python betyr altså «gjør slik at», ikke «er lik».
forbruk = 1250 leser du som «la forbruk være 1250». Høyre side regnes ut først, deretter settes resultatet inn i navnet. Derfor gir n = n + 1 mening: den gamle verdien av n brukes til å regne ut den nye.
Sammenligning skrives med to likhetstegn, ==. Det kommer i kap. 1.2.
Kortform for «regn på verdien som allerede står der, og legg resultatet tilbake i samme navn».
total += 50 betyr nøyaktig det samme som total = total + 50. Tilsvarende finnes -=, *=, /=, //= og %=.
Variabelen må ha en verdi fra før — total += 50 på et navn som ikke finnes, gir feilmeldingen NameError. Derfor settes startverdien alltid før løkka i tellemønstrene du møter i kap. 1.3.
Forbruket er 1250 kilowattimer, prisen er 1,15 kroner per kilowattime og fastbeløpet er 39 kroner. Hva blir regningen, og hva skjer hvis forbruket senere korrigeres til 1310?
Vi gir de tre tallene navn og regner med navnene:
forbruk = 1250
pris = 1.15
fastbelop = 39
regning = forbruk * pris + fastbelop
print(regning)Utskrift:
1476.5Merk at desimaltall skrives med punktum, ikke komma: 1.15. Komma betyr noe annet i Python.
Korrigeres forbruket, tilordner vi på nytt — og må regne ut regningen på nytt. Den gamle utregningen henger ikke igjen:
forbruk = 1250
pris = 1.15
fastbelop = 39
regning = forbruk * pris + fastbelop
forbruk = 1310
print(regning)
regning = forbruk * pris + fastbelop
print(regning)Utskrift:
1476.5
1545.4999999999998Første print gir fortsatt den gamle summen. regning husker tallet som ble regnet ut, ikke oppskriften. Dette er den vanligste misforståelsen om tilordning, og den lønner seg å ha sett én gang.
(Innstegsoppgave — minimal sporing. Sjanger B — kodesporing, altså «hva skriver programmet ut?».) Hva skriver programmet ut?
antall = 4
antall = antall + 3
antall += 2
print(antall)Løkke 2 — De fire typene (~10 min)
Tallet 7 og teksten «7» ser like ut på skjermen, men maskinen behandler dem helt forskjellig. Det ene kan du regne med; det andre kan du bare sette sammen med annen tekst. Hvilken av delene en verdi hører til, kalles verdiens datatype.
Fire typer dekker nesten alt du trenger i dette faget.
Hele tall uten desimaler: 0, 7, -42, 1250. Ingen øvre grense i Python 3 — heltall kan bli vilkårlig store.
Skrives uten fnutter og uten mellomrom som tusenskille: 1250, aldri 1 250.
Regning mellom to heltall gir heltall, med ett unntak: / gir alltid desimaltall.
Tall med desimaler: 1.15, 3.0, -0.5. Desimalskilletegnet er punktum, ikke komma.
«Flyttall» betyr at komma «flyter» — maskinen lagrer tallet omtrent slik 1.15 ganger en tierpotens, med et begrenset antall siffer. Derfor er flyttall tilnærminger: 0.1 + 0.2 blir 0.30000000000000004, ikke 0.3. Det er ikke en feil i Python, det er avrundingen i et endelig antall bit.
3.0 er et flyttall selv om verdien er hel. Utskriften viser .0-en.
En tekst, skrevet mellom enkle eller doble fnutter: 'Trondheim', "1250". «Streng» er fagordet for tekst i programmering — en streng av tegn.
Fnuttene er ikke en del av teksten. print('sol') skriver sol, uten fnutter.
+ mellom to strenger limer dem sammen: '12' + '7' gir '127', ikke 19. Dette er felle #1 i bokas feilregister, og den vanligste enkeltfeilen i faget.
Har nøyaktig to mulige verdier: True (sann) og False (usann). Stor forbokstav, uten fnutter — 'True' med fnutter er en streng, ikke en sannhetsverdi.
Sannhetsverdier oppstår av sammenligninger (5 > 3 gir True) og styrer alle valg i programmet. Hele apparatet rundt dem står i kap. 1.2.
Internt er True tallet 1 og False tallet 0, så True + True gir 2. Det er sjelden nyttig, men det forklarer at man kan telle sanne tilfeller ved å summere dem.
Forteller hvilken datatype verdien x har akkurat nå. Svaret skrives som <class 'int'>, <class 'float'>, <class 'str'> eller <class 'bool'>.
type regner ikke om noe og endrer ingenting — den bare rapporterer. På eksamen bruker du den aldri i en besvarelse, men når du sporer kode i hodet, er «hvilken type er dette nå?» ofte det spørsmålet som avgjør svaret.
Hva er typen til 1250, 1.15, '1250' og 1250 > 1000 — og hva skjer når du plusser to strenger mot to tall?
print(type(1250))
print(type(1.15))
print(type('1250'))
print(type(1250 > 1000))Utskrift:
<class 'int'>
<class 'float'>
<class 'str'>
<class 'bool'>Legg merke til den tredje linja: '1250' med fnutter er en tekst som ser ut som et tall. Det er nøyaktig slik tall kommer inn fra en fil eller fra brukeren, og derfor det viktigste tilfellet i hele kapitlet.
Forskjellen viser seg med én gang du regner:
print(12 + 7)
print('12' + '7')Utskrift:
19
127Samme operator, to helt ulike resultater. + betyr «legg sammen» for tall og «lim sammen» for tekst.
Hva skriver programmet ut? Skriv de tre linjene nøyaktig som terminalen viser dem.
a = '5'
b = 5
print(a + a)
print(b + b)
print(a * 2)Løkke 3 — Regneoperatorene, og de to som overrasker (~12 min)
Fire av regneoperatorene oppfører seg som på kalkulatoren: +, -, * og potens. To gjør det ikke, og nettopp de to er faste innslag i kodesporingsoppgavene: heltallsdelingen // og resten %.
Et konkret bilde først. En treningsøkt varte 3725 sekunder. Hvor mange hele minutter er det, og hvor mange sekunder blir til overs? Du deler på 60 og ser på heltallsdelen — det er // — og resten er %.
Vanlig divisjon. Gir alltid et flyttall, også når det går opp: 10 / 2 gir 5.0, ikke 5.
Dette er en av de vanligste kildene til rar utskrift. Skriver programmet 5.0 der du ventet 5, har du sannsynligvis delt med / der du mente //.
Deling på null gir feilmeldingen ZeroDivisionError og stopper programmet.
Deler og kaster desimalene, slik at svaret blir et heltall når begge operandene er heltall: 17 // 5 gir 3.
Presist: // runder nedover, mot minus uendelig — ikke mot null. Det betyr at -17 // 5 gir -4, ikke -3. Dette er nøyaktig den detaljen sporingsoppgavene tester, og den eneste måten å huske den på er å lese «nedover på tallinja».
Er én av operandene et flyttall, blir svaret et flyttall uten desimaler: 17.0 // 5 gir 3.0.
Gir resten etter heltallsdeling: 17 % 5 gir 2, fordi 17 er 3 femmere og 2 til overs.
To bruksmåter går igjen på eksamen: sifre (n % 10 gir siste siffer) og partall (n % 2 == 0 er sant når n er et partall).
For negative tall følger % samme regel som //, så resten får samme fortegn som det du deler på: -17 % 5 gir 3. Sammenhengen som alltid gjelder, er at (a // b) * b + (a % b) er a.
Skrives med to stjerner: 2 ** 10 gir 1024. To heltall gir heltall.
Negativ eksponent gir flyttall: 2 ** -1 gir 0.5. Kvadratrot skrives som x ** 0.5, som er grunnen til at boka nesten aldri trenger math-modulen.
Potens binder sterkere enn alt annet, og sterkere enn minustegnet foran et tall: -2 ** 2 er , ikke .
Det kanoniske mønsteret for tidsregning i dette faget, og en fast innpakning i programmeringsoppgavene. Tre linjer, i denne rekkefølgen:
sekunder = 3725
timer = sekunder // 3600
minutter = (sekunder % 3600) // 60
rest = sekunder % 60
print(timer, minutter, rest)Utskrift:
1 2 51. Timene er hele antall 3600-sekunders bolker: // 3600.
2. Minuttene finnes i det som er igjen etter timene: først % 3600, deretter // 60.
3. Sekundene er resten etter hele minutter: % 60.
Bruker du / i stedet for // på noen av linjene, får du desimaltall og hele regnestykket sprekker. Motsatt vei: bytter du % og //, får du timer der du skulle hatt sekunder.
Selve utskriftsformen 01:02:05, med nuller foran, hører til formatert utskrift og kommer i Del 3.
Hva gir 17 // 5, 17 % 5 og 17 / 5 — og hva skjer med de samme uttrykkene når tallet er negativt?
print(17 // 5, 17 % 5, 17 / 5)
print(-17 // 5, -17 % 5, -17 / 5)Utskrift:
3 2 3.4
-4 3 -3.4Første linje er som ventet: 3 hele femmere, 2 til overs, og 3,4 som desimaltall.
Andre linje er den som koster poeng. -17 // 5 er ikke . Heltallsdelingen runder nedover på tallinja, og nedover fra er . Resten blir da 3, fordi .
Kontrollen du kan gjøre på papir: gang svaret fra // med det du delte på, og legg til resten. Får du tilbake det opprinnelige tallet, har du regnet riktig.
Feilkode #9 i bokas feilregister (samlet i kap. 0.1): å bruke vanlig divisjon der heltallsdeling var meningen, eller omvendt.
Symptomet er lett å kjenne igjen: utskriften får et .0 eller en lang desimalhale den ikke skulle hatt, eller en indeks blir et flyttall og programmet stopper med TypeError.
Regel du kan bruke uten å tenke: skal resultatet brukes som et antall — antall timer, antall hele bolker, en plass i en liste — skal du ha //. Skal det brukes som en måling — pris, gjennomsnitt, andel — skal du ha /.
Hva skriver programmet ut? Pass på fortegnene.
print(29 // 4)
print(29 % 4)
print(29 / 4)
print(-29 // 4)
print(-29 % 4)En treningsøkt er logget som 7384 sekunder. Hva skriver programmet ut?
sek = 7384
t = sek // 3600
m = (sek % 3600) // 60
s = sek % 60
print(t, m, s)
print(t + m + s)Løkke 4 — Rekkefølgen uttrykkene regnes i (~5 min)
Når flere operatorer står i samme uttrykk, må maskinen bestemme hvilken som gjelder først. Reglene er de samme du lærte i matematikken, med potens på toppen.
Rekkefølgen operatorene regnes i, fra sterkest til svakest:
1. Potens — regnes fra høyre mot venstre: 2 ** 3 ** 2 er 2 ** 9, altså 512.
2. Unært minus — minustegnet foran ett tall.
3. *, /, //, % — like sterke, regnes fra venstre mot høyre.
4. + og - — svakest, også fra venstre mot høyre.
Parenteser slår alt. Er du i tvil på eksamen, sett parenteser — de koster ingenting og fjerner hele spørsmålet.
Den ene fella som faktisk brukes i oppgaver: potens binder sterkere enn minustegnet, så -3 ** 2 er .
Hva blir 2 + 3 * 4, (2 + 3) * 4, -3 ** 2 og 20 - 6 // 4 * 2?
print(2 + 3 * 4)
print((2 + 3) * 4)
print(-3 ** 2)
print(20 - 6 // 4 * 2)Utskrift:
14
20
-9
18Den siste er verdt en gjennomgang. // og * er like sterke og regnes fra venstre:
1. 6 // 4 gir 1.
2. 1 * 2 gir 2.
3. 20 - 2 gir 18.
Den som regner 4 * 2 først og deretter 6 // 8, får 20 — og har brutt regelen om venstre mot høyre.
Hva skriver programmet ut?
print(10 - 2 ** 3)
print(-2 ** 2)
print(18 % 5 * 2)
print(18 % (5 * 2))Løkke 5 — Konvertering: fra tekst til tall og tilbake (~10 min)
Nå kommer kapitlets viktigste avsnitt. Alle data som kommer inn i programmet utenfra — fra en fil, fra tastaturet — kommer inn som tekst. Ingen unntak. Skal du regne med dem, må du gjøre dem om til tall først. Å gjøre om en verdi fra én datatype til en annen kalles konvertering.
En prisliste på fil ser slik ut for maskinen:
Rimi;melk;21.90Prisen 21.90 er tekst, ikke et tall, helt til du selv gjør noe med den.
Tar en tekst som ser ut som et helt tall, og gir tallet: int('42') gir 42.
Teksten må inneholde bare et helt tall, eventuelt med fortegn og omkringliggende mellomrom. int(' 42 ') virker; int('42 kr'), int('') og int('3.9') gir alle feilmeldingen ValueError og stopper programmet.
Merk det siste: en tekst med desimalpunktum kan ikke sendes rett til int. Da må du gå veien om float.
Tar en tekst som ser ut som et tall, og gir et flyttall: float('3.14') gir 3.14, og float('7') gir 7.0.
Desimalskilletegnet må være punktum. float('3,14') gir ValueError — en felle når data kommer fra norske regneark.
Tommelfingerregel for fildata: felt som er penger, målinger eller tider konverteres med float, felt som er antall eller årstall med int.
Motsatt vei: str(7) gir '7', og str(3.5) gir '3.5'.
Nødvendig når du vil lime et tall sammen med tekst med +: 'Pris: ' + str(pris). Uten str får du feilmeldingen TypeError: can only concatenate str.
print gjør denne konverteringen selv for hvert argument, så print('Pris:', pris) virker uten str. Behovet oppstår først når du bygger en tekst.
Brukt på et flyttall kaster int desimalene og beholder heltallsdelen — mot null, ikke nedover.
int(3.9) gir 3, og int(-3.9) gir -3. Legg merke til at dette er en annen regel enn //, som runder nedover og ville gitt . To operasjoner som ser like ut, med ulik oppførsel for negative tall.
Vil du runde av på vanlig måte, bruker du round.
round(2.7) gir 3, og round(3.14159, 2) gir 3.14. Med ett argument er svaret et heltall, med to er det et flyttall.Python 3 bruker bankers avrunding ved eksakt halv: den runder til nærmeste partall. Derfor gir round(0.5) verdien 0 og round(1.5) verdien 2. Det overrasker de fleste, og er verdt å kjenne til, men det er sjelden avgjørende i en besvarelse.
Vil du bare vise et pent tall på skjermen, er formatert utskrift (Del 3) et bedre valg enn round.
Spørres på en streng og gir True eller False: '42'.isdigit() gir True, mens '42.5'.isdigit(), '-42'.isdigit() og ''.isdigit() alle gir False.
Punktumet, minustegnet og den tomme teksten er alle tre «ikke bare sifre». Metoden er altså en test for positive hele tall skrevet uten fortegn, ikke en generell tall-test.
Nytten er å kunne sjekke før du konverterer, slik at programmet slipper å krasje på ValueError. Det er selve grunnmuren i input-valideringen i kap. 1.4.
Bokas mest brukte enkeltregel, og den som forebygger den hyppigste feilen på eksamen:
Alt som kommer utenfra, er tekst. Skal du regne med det, konverterer du først.
I praksis to steg, i denne rekkefølgen:
1. Del opp teksten i felt (kommer i Del 3).
2. Konvertér hvert felt som skal regnes med, med int eller float — på stedet, med én gang, ikke «senere».
Her er hele forskjellen i to linjer:
pris_tekst = '21.90'
print(pris_tekst + pris_tekst)
print(float(pris_tekst) + float(pris_tekst))Utskrift:
21.9021.90
43.8Den øverste linja er ikke en feilmelding. Den er verre: den er et galt svar som ser riktig ut. Programmet fortsetter, og feilen dukker først opp lenger ned i besvarelsen.
Feilkode #1 i bokas feilregister: å regne, sammenligne eller sortere på verdier som fortsatt er tekst.
Tre symptomer å kjenne igjen når du kontrollerer din egen besvarelse:
- Summen blir en lang sammenlimt tekst i stedet for et tall.
- Sammenligningen blir feil: '9' > '10' er True, fordi tekst sammenlignes tegn for tegn, og tegnet 9 kommer etter tegnet 1.
- Programmet stopper med TypeError når teksten møter et tall.
Sensor gir eksplisitt poeng for at tallkolonner er konvertert. Det er én av de billigste poengene på hele settet, og en av de mest tapte.
l, I eller O som variabelnavn. Liten l og stor I ser ut som tallet 1, og stor O ser ut som tallet 0. På et håndskrevet eksamenssvar blir det umulig for sensor å avgjøre hva du mente. Bruk i, k, n, antall, total.Aldri et innebygd navn som variabel. Skriver du sum = 0, virker den innebygde funksjonen sum(...) ikke lenger i resten av programmet — navnet er opptatt. Det samme gjelder list, str, int, float, dict, set, max, min, abs, round, len, type, id, range, input, format, bytes og next. Denne fella heter #14 i feilregisteret.
Trygge alternativer: s, total, verdier, tekst, ordbok, tabell, antall.
En linje fra en prisliste ser slik ut, som ren tekst:
21.90Butikken setter opp prisen med 12 prosent. Hva blir den nye prisen — og hva går galt hvis du hopper over konverteringen?
Først den gale veien, slik den faktisk ser ut i en besvarelse:
pris = '21.90'
print(pris * 2)Utskrift:
21.9021.90Ingen feilmelding, bare tull: teksten ble gjentatt to ganger. Hadde vi skrevet pris * 1.12, ville programmet stoppet med TypeError, fordi tekst ikke kan gjentas et desimalt antall ganger.
Så den riktige veien. Konvertér på stedet, regn, og gjør om til tekst igjen bare når du skal bygge en utskriftslinje:
pris = '21.90'
ny_pris = float(pris) * 1.12
print(ny_pris)
print(round(ny_pris, 2))
print('Ny pris: ' + str(round(ny_pris, 2)) + ' kr')Utskrift:
24.528000000000002
24.53
Ny pris: 24.53 krDen første utskriften viser hele flyttallshalen — det er slik flyttall faktisk er, og noe du bør vente å se. round(..., 2) gir det tallet du vil vise. Den siste linja bygger en tekst, og der er str nødvendig.
Uttelling: sensor er ute etter at prisen representeres som flyttall. Å konvertere ved innlesing, én gang, er både det korteste og det som gir poeng.
Hva skriver programmet ut? Én av linjene ser riktig ut, men er det ikke.
a = '8'
b = '10'
print(a + b)
print(int(a) + int(b))
print(a > b)
print(int(a) > int(b))Hva skriver programmet ut?
x = 7.8
print(int(x))
print(round(x))
print(int(-x))
print(-x // 1)En vaktliste oppgir hvor mange minutter en person har stått på post. Hva skriver programmet ut?
minutter = '415'
t = int(minutter) // 60
m = int(minutter) % 60
print(t, m)
print(str(t) + ':' + str(m))
print(minutter + str(t))Hva skriver programmet ut? Se nøye på både typer og fortegn.
n = -13
print(n // 4, n % 4)
print(int(n / 4))
print(abs(n) % 10)
print(type(n / 1))Fire feller, og de tre første er blant de dyreste i hele faget:
- #1 — glemt int()/float() etter innlesing. Gir sammenliming i stedet for addisjon, og sammenligning tegn for tegn i stedet for etter tallverdi. Ingen feilmelding, bare galt svar.
- #9 — / mot //. Feil operator gir et .0 eller en desimalhale som ødelegger tids- og indeksregning.
- Nedrundingen i //. For negative tall runder // nedover, mens int(...) kutter mot null. -17 // 5 er ; int(-17 / 5) er .
- #14 — skygge et innebygd navn. sum = 0 ødelegger sum(...) resten av programmet.
Alle fire kan kontrolleres på under et minutt når du leser gjennom besvarelsen til slutt.
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.