1.1 Variabler, datatyper, uttrykk og operatorpresedens
Tall, boolske verdier, aritmetiske og logiske uttrykk, og presedensreglene som avgjør hva et uttrykk evaluerer til.
- Sjanger A — kodesporing, altså «hva skriver dette programmet ut?». Den forekommer i 100 % av settene og gir 1–3 poeng per spørsmål. Den bærer i praksis hele midtveiseksamen (UiOs digitale flervalgseksamen i oktober, som teller 25 % av karakteren), og de første oppgavene på den avsluttende eksamenen i desember er samme sjanger.
- Sjanger D — matche-tabell, der du får en liste med uttrykk eller påstander og skal parre hver av dem med et svar («sann/falsk», «terminerer/uendelig»). Her møter du D-varianten for boolske uttrykk: er dette uttrykket sant eller falskt?
- Faste feller fra nettopp dette kapitlet, år etter år: heltall mot desimaltall, heltallsdivisjon og operatorpresedens — altså hvilken operator som regnes ut først.
Prioritet: dette må sitte (høyeste prioritet av tre nivåer i boka — «må sitte», «må kunne», «bør kjenne til»). Ikke fordi stoffet er vanskelig, men fordi alt annet i faget hviler på det, og fordi feilene her koster billige poeng du egentlig hadde.
Har du aldri programmert før, finnes det to mykere innganger på plattformen som du kan bla gjennom først, uten at det er nødvendig:
- Programmering med Python — Python fra null, i et matematikkurs fra videregående.
- Programmering med Python — samme innføring, i en litt roligere versjon.
Er du usikker på om du er «god nok i matte» til IN1900: kapitlet her bruker ingen matematikk utover pluss, minus, gange og dele.
Løkke 1 — Verdier, navn og datatyper
En værstasjon på Blindern måler temperaturen hver time. Du vil regne på tallene: finne gjennomsnitt, sjekke om det frøs, telle antall målinger. Da må maskinen holde orden på to ting — verdiene (21.5, 4, «Blindern») og navnene du bruker på dem.
Et Python-program er lite mer enn en liste med slike navngivinger, og uttrykk som regner med dem. Vi begynner der, fordi kodesporing i bunn og grunn er å holde en slik navneliste i hodet.
En variabel er et navn som peker på en verdi. Du lager den med et likhetstegn: navnet til venstre, verdien til høyre.
Likhetstegnet i Python betyr ikke «er lik» slik det gjør i matematikk. Det betyr «regn ut høyresiden, og la navnet på venstresiden peke på resultatet». Derfor er x = x + 1 en helt fornuftig setning: regn ut den gamle x pluss 1, og la x peke på det nye tallet.
temperatur = 21.5
temperatur = temperatur + 1
print(temperatur)Utskrift:
22.5Skriver verdiene ut i terminalen og avslutter med linjeskift. Flere argumenter skilles av ett mellomrom — det er Python som setter det inn, ikke deg.
Dette er detaljen som avgjør flest kodesporingsoppgaver: print(3, 4) gir 3 4 med ett mellomrom, mens print('3' + '4') gir 34 uten.
print(3, 4)
print('sum:', 3 + 4)
print('3' + '4')Utskrift:
3 4
sum: 7
34Tall uten desimalpunkt: 4, -7, 1000. Heltall i Python har ingen øvre grense — 2**100 regnes ut eksakt, uten avrunding.
Så lenge du bare bruker +, -, * og ** på heltall, får du et heltall tilbake. Det er / som bryter mønsteret: den gir alltid et desimaltall, også når det går opp.
Desimaltall: 21.5, -0.5, 1e-5 (som betyr ). Python skriver desimalskilletegnet som punktum, aldri komma — 21,5 er ikke ett tall i Python, men to.
Flyttall er tilnærminger. Maskinen lagrer dem i totallssystemet, og de fleste desimaltall får ikke plass eksakt. Derfor er 0.1 + 0.2 ikke helt lik 0.3:
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)Utskrift:
0.30000000000000004
FalseDette er ikke en feil i Python, det er slik flyttall virker overalt. Det er også grunnen til at testfunksjoner i kap. 3.1 sammenligner med en toleranse i stedet for med likhetstegn.
Datatypen med bare to verdier: True og False. Stor forbokstav, alltid — true finnes ikke i Python.
Sannhetsverdier oppstår normalt ikke fordi du skriver dem selv, men fordi du sammenligner noe: 5 > 3 er verdien True. De er også tall i forkledning: True oppfører seg som 1 og False som 0 i regnestykker, så True + True er 2.
Tekst, skrevet mellom enkle eller doble fnutter: 'Blindern' eller "Blindern". De to formene er likeverdige.
På strenger betyr + å skjøte sammen og * å gjenta: 'ab' + 'cd' gir 'abcd', og 'ab' * 2 gir 'abab'. Merk at '3' + '4' derfor gir '34' og ikke 7 — tallet 3 og tegnet '3' er to helt forskjellige verdier. Mer om strenger i kap. 1.4.
Svarer med datatypen til verdien x. Utskriften ser slik ut: <class 'int'>.
Du bruker den nesten aldri i en eksamensbesvarelse, men den er uvurderlig når du selv skal sjekke om et uttrykk ga heltall eller desimaltall — nettopp det kodesporing spør om.
En værstasjon lagrer fire opplysninger. Hvilken datatype har hver av dem, og hva skriver programmet ut?
Vi lar Python svare selv. Legg merke til at type skriver typenavnet inne i <class ...>:
temperatur = 21.5
antall_stasjoner = 4
navn = 'Blindern'
maalt_i_dag = True
print(type(temperatur))
print(type(antall_stasjoner))
print(type(navn))
print(type(maalt_i_dag))Utskrift:
<class 'float'>
<class 'int'>
<class 'str'>
<class 'bool'>Fire linjer inn, fire linjer ut: float, int, str, bool. Merk at det er verdien som bestemmer typen, ikke navnet — Python spør aldri hva du hadde tenkt.
(Innstegsoppgave — ren gjengivelse.) Skriv ned datatypen til hver av disse verdiene, med Pythons eget navn på typen:
a) -12
b) -12.0
c) '-12'
d) 12 > 3
To grupper navn skal du styre unna hele semesteret:
1. Enkeltbokstavene l, I og O. I de fleste skrifttyper er små l nesten identisk med sifferet 1, og stor O med sifferet 0. På en eksamen der sensor leser koden din på skjerm, er det en unødvendig misforståelse. Bruk i, n, k, x — eller et ordentlig ord.
2. Navn som Python allerede bruker. sum, list, str, int, float, dict, max, min, abs, round, len, type, input, range, id, next, format. Skriver du sum = 0, virker det fint — helt til du lenger nede prøver å bruke sum(...) på en liste og får en feilmelding om at et heltall ikke kan kalles. Feilen er stum og kommer langt fra åstedet, og den er en klassiker i «finn feilen»-oppgaver.
Bruk i stedet s, total, verdier, tekst eller ordbok. Boka gjør det konsekvent, og du bør gjøre det samme i besvarelsen din.
Løkke 2 — De fire divisjonene
Nå kommer den mest lønnsomme halvtimen i kapitlet. Python har tre forskjellige måter å dele på, og de gir tre forskjellige svar på samme regnestykke. Nesten hvert midtveissett har minst ett spørsmål som lever av at studenten blander dem.
Vanlig divisjon. Resultatet er alltid et flyttall, også når det går opp: 6 / 3 gir 2.0, ikke 2.
Det er verdt å merke seg i kodesporing: et desimalpunkt i utskriften avslører at det har vært en / inne i regnestykket.
Deler og runder resultatet nedover til nærmeste heltall. 7 // 2 gir 3.
«Nedover» betyr mot minus uendelig, ikke mot null. Derfor er -7 // 2 lik -4, ikke -3. Det er den fellen som går igjen. Får begge operandene være heltall, blir svaret et heltall; er én av dem et flyttall, blir svaret et flyttall med .0 (7.0 // 2 gir 3.0).
Resten etter heltallsdivisjon: 7 % 2 gir 1.
To bruksområder du får se om og om igjen: n % 2 == 0 betyr «n er et partall», og n % 5 == 0 betyr «n er delelig med 5». I Python har resten alltid samme fortegn som det du deler på, så -7 % 2 gir 1 (ikke -1). De to operatorene henger sammen: (a // b) * b + a % b gir alltid a tilbake.
Hva skriver dette programmet ut? Vær nøye med fortegnene.
Vi kjører det:
antall = 7
gruppestorrelse = 2
print(antall / gruppestorrelse)
print(antall // gruppestorrelse)
print(antall % gruppestorrelse)
print(-antall // gruppestorrelse, -antall % gruppestorrelse)Utskrift:
3.5
3
1
-4 1Linje for linje: / gir flyttallet 3.5. // kaster desimalene og gir 3 — sju personer fordelt to og to blir tre hele par. % gir 1 — én person står igjen.
Den siste linja er fellen. -7 // 2 er ikke -3. Runder du nedover fra , kommer du til . Og siden (-4) * 2 + 1 er -7, må resten være 1.
Feilkode #15 (boka nummererer de vanligste feilene og samler dem i kap. 0.1) dekker tre nære slektninger:
- // runder nedover, ikke mot null. -7 // 2 er -4.
- / gir alltid flyttall. 4 / 2 er 2.0, og skrives ut med desimalpunkt.
- ** regnes ut fra høyre. Det kommer i neste løkke.
Alle tre er testet med flervalg der ett av alternativene er nettopp det svaret du får hvis du tar feil. Sjekk fortegnene to ganger når negative tall er inne i bildet.
(Midtveisnivå, sjanger A — kodesporing.) Hva skriver programmet ut? Skriv utskriften nøyaktig, med linjeskift slik terminalen viser den.
maalinger = 13
kolonner = 4
print(maalinger // kolonner)
print(maalinger % kolonner)
print(maalinger / kolonner)Opphøyd i: 2 ** 3 gir 8. Med et negativt eksponentuttrykk får du flyttall: 2 ** -1 gir 0.5.
To særegenheter du må huske: ** binder sterkest av alle regneoperatorene, og den regnes ut fra høyre (den er høyre-assosiativ). Derfor er 2 ** 3 ** 2 det samme som , ikke . Og fordi ** binder sterkere enn minustegnet foran et tall, er -2 ** 2 lik -4.
Fire uttrykk som ser nesten like ut. Hva skriver programmet ut?
print(2 ** 3 ** 2)
print((2 ** 3) ** 2)
print(-2 ** 2)
print((-2) ** 2)Utskrift:
512
64
-4
4Linje 1 og 2 skiller seg fordi ** regnes fra høyre: , mens parentesene i linje 2 tvinger .
Linje 3 og 4 skiller seg fordi ** binder sterkere enn det unære minuset: i linje 3 regnes 2 ** 2 først og fortegnet snus etterpå, mens parentesen i linje 4 gjør at hele opphøyes.
Praktisk regel i besvarelsen: er du i tvil, sett parentes. Sensor trekker aldri for en parentes du ikke trengte.
(Midtveisnivå, sjanger A.) Hva skriver programmet ut?
a = 3
print(2 ** a ** 2)
print(-a ** 2 + 1)
print(2 ** -2)Løkke 3 — Presedens: hva regnes ut først?
Et uttrykk som 6 + 4 * 2 har bare ett riktig svar, og Python bruker samme regler du lærte på skolen — pluss noen flere, fordi Python har flere operatorer enn matematikken.
Rekkefølgen Python regner ut i, fra det som bindes sterkest til det som bindes svakest:
1. () — parentes
2. ** — potens (regnes fra høyre)
3. -x — unært minus
4. *, /, //, % — regnes fra venstre mot høyre
5. +, - — regnes fra venstre mot høyre
6. <, <=, >, >=, ==, != — sammenligninger
7. not
8. and
9. or
To operatorer på samme nivå tas fra venstre: 12 / 3 * 2 er (12 / 3) * 2 som gir 8.0, ikke 12 / 6. Eneste unntak er **, som tas fra høyre.
Merk at alle regneoperatorene kommer før sammenligningene, og at not kommer før and, som kommer før or.
Tallene 6 og 4 i fem forskjellige uttrykk. Hva skriver programmet ut?
a = 6
b = 4
print(a + b * 2)
print((a + b) * 2)
print(a / b * 2)
print(a - b - 1)
print(a % b * 2)Utskrift:
14
20
3.0
1
4- 6 + 4 * 2: gangetegnet først, altså 6 + 8.
- (6 + 4) * 2: parentesen først, altså 10 * 2.
- 6 / 4 * 2: samme nivå, fra venstre: 1.5 * 2. Flyttall, fordi / var inne.
- 6 - 4 - 1: fra venstre: 2 - 1. Hadde det vært fra høyre, ville svaret vært 3.
- 6 % 4 * 2: % og * er samme nivå, fra venstre: 2 * 2.
Den tredje og den femte linja er de som skiller. Begge lever av regelen «samme nivå tas fra venstre».
(Midtveisnivå, sjanger A.) Hva skriver programmet ut?
x = 10
y = 3
print(x - y * 2 + 1)
print(x // y ** 2)
print(x / y // 2)Løkke 4 — Logiske uttrykk
En værstasjon skal varsle om frost. Det er et spørsmål med to svar, og slike spørsmål skriver du i Python som logiske uttrykk. De er kjernen i alle if-setninger og while-løkker senere i boka, og de utgjør en egen matche-tabell på eksamen (sjanger D).
<, <=, >, >= sammenligner størrelse; == spør om likhet og != om ulikhet. Hver av dem gir True eller False.To fallgruver. Ett likhetstegn tilordner, to sammenligner — x = 5 og x == 5 er to helt ulike setninger. Og Python tillater kjeding: 0 < x < 10 er lovlig og betyr 0 < x and x < 10. Det er praktisk, men også en yndet felle, fordi den samme skrivemåten ikke betyr noe fornuftig i mange andre språk.
a and b er sann bare når begge er sanne. a or b er sann når minst én er sann. not a snur svaret.Rekkefølgen er not før and før or. Derfor betyr not x > 3 or x == 5 det samme som (not (x > 3)) or (x == 5): not-et gjelder bare den første sammenligningen, ikke hele uttrykket. Er du i tvil, sett parentes.
Python er dessuten lat: i a and b regnes b bare ut hvis a var sann. Det er derfor n != 0 and 10 / n > 1 er trygt selv når n er null.
Alle verdier kan brukes der Python venter et ja/nei-svar. Regelen er kort: tallet 0, den tomme strengen '', den tomme lista [] og den tomme ordboka {} regnes som falske. Alt annet er sant.
bool(x) viser hva Python mener om x. Dette forklarer hvorfor if verdier: er et vanlig og idiomatisk uttrykk for «hvis lista ikke er tom».
Temperaturen er målt til 5 grader. Hva skriver programmet ut?
t = 5
print(0 < t < 10)
print(t > 3 and t % 2 == 0)
print(not t > 3 or t == 5)
print(bool(0), bool(''), bool(-1))Utskrift:
True
False
True
False False True- 0 < 5 < 10: begge leddene i kjeden er sanne.
- 5 > 3 and 5 % 2 == 0: første ledd sant, andre ledd falskt (5 er ikke et partall), og and krever begge.
- not 5 > 3 or 5 == 5: not-et tar bare 5 > 3, som er sant, så første ledd blir False. Andre ledd er sant, og or krever bare ett.
- bool(0), bool('') er falske; bool(-1) er sann, for det er bare null som er falsk, ikke negative tall.
Legg merke til den siste: mange gjetter False for bool(-1) fordi negativt «føles» som nei.
(Midtveisnivå, sjanger D — matche-tabell der du avgjør sannhetsverdien til hvert uttrykk.) La n = 12 og m = 5. Avgjør for hvert uttrykk om det er True eller False.
| Uttrykk |
|---|
| n % m == 2 |
| n > m and m > 10 |
| not n == 12 |
| m < n < 20 |
| n % 2 == 0 or m % 2 == 0 |
Løkke 5 — Konvertering, avrunding og korte tilordninger
Til slutt tre småting som dukker opp i nesten hver eneste kodesporingsoppgave: å bytte datatype, å runde av, og den korte skrivemåten for «legg til».
Gjør x om til et heltall. På et flyttall kutter den desimalene bort — den runder ikke. Og den kutter mot null: int(2.7) gir 2, og int(-2.7) gir -2.
Det er en viktig forskjell fra //, som runder nedover: int(-2.7) er -2, mens -27 // 10 er -3. På en streng virker int bare hvis strengen inneholder et helt tall: int('42') gir 42, mens int('42.0') og int('to') stopper programmet med en feilmelding.
Gjør x om til et flyttall: float(3) gir 3.0, og float('2.5') gir 2.5.
Dette er konverteringen du bruker når du har lest tall fra fil eller fra kommandolinjen — der kommer alt inn som tekst, og tekst kan man ikke regne med. Se kap. 2.1.
round(x) runder av til nærmeste heltall og gir et heltall. round(x, n) runder av til n desimaler og gir et flyttall.Særegenhet du bør kjenne: står tallet midt imellom, runder Python til det nærmeste partallet. Derfor er round(0.5) lik 0, round(1.5) lik 2 og round(2.5) lik 2. Regelen kalles bankers avrunding, og den finnes for at mange avrundinger ikke skal skjeve seg systematisk oppover.
s += x er kortformen for s = s + x, og tilsvarende for de andre. Kortformen er den idiomatiske måten å bygge opp en sum eller en teller.Du får se den i hver rekke-oppgave i kap. 3.2, som s += ledd. Merk at variabelen må ha en verdi først: s += 1 på et navn som ikke finnes, stopper programmet.
Dette er en typisk midtveisoppgave: fem linjer, ingen løkker, men fire ulike feller. Hva skriver programmet ut?
x = 2.7
print(int(x), int(-x))
print(round(x), round(-x))
print(round(0.5), round(1.5), round(2.5))
t = 10
t += 5
t //= 4
print(t)Utskrift:
2 -2
3 -3
0 2 2
3Sporingstavle
| Linje | Hva skjer | t | Utskrift |
|---|---|---|---|
| 2 | int kutter mot null i begge retninger | — | 2 -2 |
| 3 | round runder normalt | — | 3 -3 |
| 4 | midt imellom: rund til partall | — | 0 2 2 |
| 5–7 | t blir 10, så 15, så 15 // 4 som er 3 | 3 | 3 |
De to linjene som skiller besvarelsene er linje 2 og linje 4.
int(-2.7) er -2 fordi int kutter, og round(2.5) er 2 fordi Python runder til nærmeste partall når det står midt imellom.(Midtveisnivå, sjanger A.) Hva skriver programmet ut?
verdi = -3.6
print(int(verdi))
print(round(verdi))
print(round(verdi, 1))
s = 7
s *= 3
s %= 4
print(s)(Midtveisnivå, sjanger A — kodesporing med blandede datatyper.) Hva skriver programmet ut?
antall = 4
sum_grader = 82.0
print(sum_grader / antall)
print(sum_grader // antall)
print(antall * 2 ** 2)
print(antall == 4.0)Hva skriver programmet ut?
n = -13
d = 4
print(n // d, n % d)
print(-(n // d), int(n / d))
print(n // d * d + n % d)La x = 0, tekst = 'null' og verdier = [] (en tom liste).
Avgjør for hvert uttrykk om det er True eller False.
a) bool(x)
b) bool(tekst)
c) bool(verdier)
d) x == 0 and not verdier
e) x or tekst
f) not x and not tekst
- #15 — heltallsdivisjon og presedens. // runder nedover (også for negative tall), / gir alltid flyttall, ** regnes fra høyre og binder sterkere enn unært minus. Dette er den store.
- #16 — utskriftsdetaljer. print setter ett mellomrom mellom argumentene sine. Et svar med komma mellom tallene er feil, selv om tallene er riktige. Mer om dette i kap. 1.4.
- #22 — is mot ==. == sammenligner verdier, is sammenligner om det er samme objekt. Bruk == på tall og strenger; is hører bare sammen med None.
- Datatypen glemt i utskriften. 1 og 1.0 er samme tall, men to forskjellige utskrifter. I sjanger A teller tegnene.
- Ett mot to likhetstegn. = tilordner, == sammenligner.
Begrepsbank
Begrepsbanken er flashcard-/repetisjonsstoff — den gjentar det du nettopp har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder kjernestoffet.
Tallverdien til x, uten fortegn: abs(-4.5) gir 4.5, og abs(3) gir 3.
Den er viktigere enn den ser ut: hver testfunksjon i boka bruker abs(forventet - beregnet) < tol for å sjekke om to flyttall er «nær nok». Se kap. 3.1.
I Python bestemmes datatypen av verdien, ikke av navnet, og et navn kan peke på ulike typer etter hverandre: x = 4 og deretter x = 'fire' er lovlig.
Konsekvensen for deg er at typefeil ikke oppdages før koden kjører. Skriver du '3' + 4, får du ingen advarsel på forhånd — programmet stopper når linja nås, med en TypeError. Det er en av exception-typene i kap. 2.2.
Et uttrykk har en verdi: 2 + 2, x > 3, int('42'). En setning gjør noe: x = 5, print(x).
Skillet er praktisk i sporing: hvert uttrykk kan du erstatte med verdien sin og gå videre. Det er nettopp det en sporingstavle gjør, linje for linje.
Et flyttall lagres med et endelig antall binære siffer, så de fleste desimaltall blir litt feil i siste siffer. Derfor er 0.1 + 0.2 lik 0.30000000000000004, og 1 / 3 skrives 0.3333333333333333.
Tre konsekvenser du får bruk for: (1) sammenlign aldri flyttall med ==, bruk en toleranse; (2) bruk formatert utskrift når du vil vise et pent tall, se kap. 1.4; (3) heltall har ikke dette problemet — de er eksakte, uansett størrelse.
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.