Tilbake
5.3

5.3 DRILL — «Forklar med én setning» og «fyll inn manglende kodelinje»

De to distinktive NTNU-sjangrene: beskrive en funksjons formål presist i én setning (C), og velge kodelinjen som får funksjonen til å virke (D).

75 min
14 oppgaver
DRILLForklar med én setningfyll inn manglende kodelinje
Din fremgang i kapitlet
0 / 14 oppgaver
Sist du var her — Forkunnskaper, ferdig oppfrisket

Begge sjangrene består i å LESE kode, ikke skrive den. Du trenger derfor ingen nye konstruksjoner, men du må kjenne igjen de tre mønstrene under på et blunk. Her er de, kjørt og ferdig oppfrisket.

1. Telleren med ordbok (kap. 3.5) — «hvor mange av hver?»:

linjer = ['tog', 'buss', 'tog']
d = {}
for t in linjer:
    d[t] = d.get(t, 0) + 1
print(d)

Utskrift:

{'tog': 2, 'buss': 1}

2. Finn beste (kap. 3.1) — løkka som holder på den beste verdien sett så langt:

priser = [42, 19, 87, 31]
beste = priser[0]
for p in priser:
    if p > beste:
        beste = p
print(beste)

Utskrift:

87

3. Bygg ei ny liste (kap. 3.2) — den tomme lista som fylles i løkka:

tall = [4, 7, 2, 9]
resultat = []
for t in tall:
    if t % 2 == 1:
        resultat.append(t)
print(resultat)

Utskrift:

[7, 9]

Du trenger dessuten løkkegrensene fra kap. 1.3, utsnitt fra kap. 3.3, sporingstavla fra kap. 5.1 og rekursjonsmalen fra kap. 5.2.

Første halvdel — «forklar med én setning» (~35 min)

Sjangeren ser lett ut og er det ikke. Nesten alle klarer å forstå hva koden gjør; det som skiller besvarelsene, er om de klarer å si det kort.

Tenk på det slik: du skal skrive den ene setningen som ville stått over funksjonen som en kommentar. Ikke en bruksanvisning, ikke en gjennomgang — en overskrift.

Etter løsningsoppskrifta følger seks korte oppslag. De er flashcard-stoff — hopp trygt over ved førstegangslesing; det du trenger for å komme i gang, står i oppskrifta og i eksempel 1.

📜Løsningsoppskrift for sjanger C

Fire steg. De tar under et minutt til sammen når du har trent litt.

1. Les hele funksjonen, og se på return først. Returverdien forteller deg nesten alltid hva funksjonen er til for. Returnerer den et tall, ei liste, en ordbok eller en sannhetsverdi?
2. Spør: hva OPPNÅS? Ikke hvordan. «Går gjennom lista og sammenligner hvert element» er hvordan. «Finner det største tallet» er hva.
3. Skriv én setning som starter med et verb. «Returnerer …», «Teller …», «Sorterer …», «Sjekker om …». Ingen innledning, ingen «denne funksjonen».
4. Stryk alt om enkeltlinjer, løkkevariabler og innrykk. Er setningen fortsatt sann og entydig? Da er du ferdig.

Tommelfingerregel for lengden: én setning, som regel 6–15 ord. Blir den lengre enn to linjer på arket, har du begynt å beskrive hvordan.

Sjanger C — «forklar med én setning»

Oppgaveformen der du får en ferdig funksjon og skal beskrive formålet i én setning. Den kommer ofte som en deloppgave rett etter en sporingsoppgave på den samme koden: først «hva returnerer myst(48, 18)?», så «forklar med én setning hva myst gjør».

Poengsummen er lav — rundt 2 % — men den er så godt som gratis når du først har sporet funksjonen, fordi du allerede har lest den.

*Hva* mot *hvordan*

Skillet hele sjangeren står på.

Hvordan (feil svar)Hva (riktig svar)
«Løkka går gjennom lista og sammenligner hvert element med det største så langt»«Returnerer det største tallet i lista»
«Den tar n % 10 og legger til resultatet av kallet med n // 10»«Returnerer tverrsummen av et positivt heltall»
«For hver rad legger den inn en verdi i en ordbok med get»«Teller hvor mange ganger hver verdi forekommer»

Et hvordan-svar er ikke galt — det er bare svar på et annet spørsmål, og det trekker ned fordi det er lengre enn nødvendig.

Verbstarten

Begynn setningen med verbet, i presens, uten subjekt: «Returnerer …», «Teller …», «Sjekker om …», «Sorterer …», «Fjerner …», «Bygger …».

Grunnen er ikke stil, men presisjon: verbet tvinger deg til å si hva funksjonen gjør med en gang, og du slipper innledninger som «Denne funksjonen tar inn en liste og …», som koster plass uten å si noe.

De seks verbene over dekker nesten alle funksjoner du møter i faget.

Returverdien er nøkkelen

Se på return-linja først. Typen på det som returneres, avgrenser svaret ditt før du har lest resten:

ReturnererDa er funksjonen som regel
ett tallen teller, en sum eller et «finn beste»
True/Falseen sjekk — «Sjekker om …»
ei listeet filter, en omforming eller et uttrekk
ei liste av listeren tabelloperasjon, ofte transponering
en ordboken teller eller en gruppering
-1 i tillegg til et tallet søk, der -1 betyr «ikke funnet»

Er det flere return-linjer, ser du på dem alle: en funksjon som returnerer både True og False er alltid en sjekk.

Konsishetsregelen

Sensors formulering, som gjentas hvert år: svar kort og klart. Er svaret uklart eller lengre enn nødvendig, trekker dette ned.

Regelen gjelder alle fritekstsvar i faget, men den er skarpest her, fordi oppgaven uttrykkelig ber om én setning. To riktige setninger er dårligere enn én riktig setning.

Praktisk konsekvens: skriv svaret, les det, og stryk alt som ikke trengs for at det skal være sant og entydig. Det du stryker, er poengene du ellers ville tapt.

Feilkode #13 — den ordrike forklaringen

Bokas feilkatalog nummererer den vanligste feilen i sjangeren: å beskrive hvordan koden virker linje for linje i stedet for hva funksjonen oppnår.

Feilen har tre kjennetegn, og har du ett av dem, har du som regel alle tre: svaret nevner løkkevariabler ved navn, det er lengre enn to setninger, og det kunne vært skrevet uten å skjønne hva funksjonen er til for.

Motgiften er steg 4 i løsningsoppskriften: stryk alt om enkeltlinjer, og se om setningen fortsatt er sann.

✏️Eksempel 1: en gjennomarbeidet C-oppgave med margnotater

Forklar med én setning hva funksjonen gjør.

def beh(tabell):
    ny = []
    for j in range(len(tabell[0])):
        rad = []
        for i in range(len(tabell)):
            rad.append(tabell[i][j])
        ny.append(rad)
    return ny

Steg 1 — se på return. Den returnerer ny, som er ei liste der hvert element selv er ei liste. Altså en tabell. Det utelukker med én gang at funksjonen er en teller eller en sjekk.

Margnotat: dette steget alene halverer mulighetene, og det tar fem sekunder.

Steg 2 — hva oppnås? Den ytre løkka går over kolonnene, den indre over radene, og tabell[i][j] plukkes ut i den rekkefølgen. Rader blir kolonner. La oss bekrefte med et minimalt eksempel:

def beh(tabell):
    ny = []
    for j in range(len(tabell[0])):
        rad = []
        for i in range(len(tabell)):
            rad.append(tabell[i][j])
        ny.append(rad)
    return ny

print(beh([[1, 2], [3, 4], [5, 6]]))

Utskrift:

[[1, 3, 5], [2, 4, 6]]

Tre rader og to kolonner inn; to rader og tre kolonner ut. Det er transponering.

Steg 3 — én setning med verbstart:

Returnerer den transponerte tabellen, altså den samme tabellen med rader og kolonner byttet om.

Steg 4 — stryk resten. Ingenting om i, j, append eller løkkene. De er hvordan.

Kontrast — slik ser et svar som trekker ned ut:

«Funksjonen lager først ei tom liste ny. Så går den gjennom alle kolonnene med j, og for hver av dem lager den ei ny tom liste rad. Inne i den løkka går den gjennom alle radene med i og legger tabell[i][j] inn i rad. Til slutt legges rad inn i ny, og ny returneres.»

Alt er riktig, og likevel gir det trekk: det er en oversettelse av koden til norsk, ikke en forklaring. Sensor leter etter ordet «transponerer» eller «bytter om rader og kolonner» — og finner det ikke.

Margnotat: har du sporet funksjonen først, som i kap. 5.1, har du allerede sett formen på svaret. Det er derfor de to sjangrene henger sammen på settet.

📝Oppgave 1

(Innstegsoppgave, sjanger C — «forklar med én setning hva funksjonen gjør».) Skriv én setning som starter med et verb.

def f(x):
    total = 0
    for v in x:
        if v < 0:
            total = total + 1
    return total

📝Oppgave 2
Eksamensnivå, sjanger C

Forklar med én setning hva funksjonen gjør.

def g(tekst):
    d = {}
    for bokstav in tekst:
        d[bokstav] = d.get(bokstav, 0) + 1
    beste = ''
    for k in d:
        if beste == '' or d[k] > d[beste]:
            beste = k
    return beste

📝Oppgave 3
Eksamensnivå, sjanger C

Forklar med én setning hva funksjonen gjør.

def h(x):
    resultat = []
    for v in x:
        if v not in resultat:
            resultat.append(v)
    return resultat

📝Oppgave 4
Eksamensnivå, sjanger C

Funksjonen er rekursiv. Forklar med én setning hva den gjør.

def m(a, b):
    if b == 0:
        return a
    return m(b, a % b)

📝Oppgave 5
Eksamensnivå, sjanger C

Forklar med én setning hva funksjonen gjør. Vær nøye med kanttilfellet.

def s(tabell, kolonne):
    k = tabell[0].index(kolonne)
    beste = None
    for rad in tabell[1:]:
        if beste is None or float(rad[k]) > float(beste[k]):
            beste = rad
    return beste

📝Oppgave 6
Eksamensnivå, sjanger C

Forklar med én setning hva funksjonen gjør.

def p(s):
    ren = ''
    for tegn in s:
        if tegn != ' ':
            ren = ren + tegn
    return ren == ren[::-1]

📝Oppgave 7
Eksamensnivå, sjanger C

Forklar med én setning hva funksjonen gjør. Vær nøye med hva som returneres når verdien ikke finnes.

def q(x, maal):
    for i in range(len(x)):
        if x[i] == maal:
            return i
    return -1

Andre halvdel — «fyll inn manglende kodelinje» (~40 min)

— naturlig pausepunkt —

I sjanger D får du en nesten ferdig funksjon der én linje er byttet ut med markøren #KODE1, og fire alternativer å velge mellom. Dette er et flervalg, og det er en av de få oppgavene i faget der du kan kontrollere svaret ditt helt mekanisk før du krysser av.

Det er ingen minuspoeng på flervalg fra 2015. Blankt teller som feil, så kryss alltid av — også når du bare har eliminert to alternativer.

Også her følger seks korte oppslag etter løsningsoppskrifta. De er flashcard-stoff — hopp trygt over ved førstegangslesing; eksempel 2 viser metoden i arbeid.

📜Løsningsoppskrift for sjanger D

Fire steg. Steg 3 er det som skiller full pott fra gjetting.

1. Les spesifikasjonen først. Hva SKAL funksjonen gjøre? Står det ikke i oppgaveteksten, står det i funksjonsnavnet og i return-linja. Uten spesifikasjonen kan fire linjer se like riktige ut.
2. Les koden rundt hullet nøyaktig. Hvilke variabler finnes på det punktet? Hva er løkkegrensene? Hva slags verdi ligger allerede i variabelen linja skal oppdatere?
3. Prøv HVERT alternativ mot et minimalt eksempel. To eller tre elementer holder. Regn ut hva funksjonen ville returnert med hver av de fire linjene. Dette er ikke sløsing med tid — det er hele metoden.
4. Velg linja som gir riktig oppførsel også i kanttilfellet. Ofte gir to alternativer riktig svar for det enkle eksemplet, og bare det ene gir riktig svar for tom liste, for første runde, eller for siste element.

Tidsbruk: to–tre minutter. Er du usikker etter det, kryss av på det beste alternativet og gå videre — det koster ingenting å ta feil.

Sjanger D — «fyll inn manglende kodelinje»

Oppgaveformen der én linje i en ellers komplett funksjon er erstattet med markøren #KODE1, og du velger mellom fire kandidatlinjer.

Linja som mangler, er nesten alltid en av fire typer: en løkkegrense, en betingelse, en oppdatering av en variabel, eller en indeksberegning. Kjenner du de fire typene, vet du hva du skal se etter.

`#KODE1`-markøren

Markøren er en vanlig Python-kommentar, og den står nøyaktig der linja skulle vært — med det innrykket linja skal ha.

Innrykket er informasjon: står markøren inne i løkka, skal linja kjøres hver runde; står den etter løkka, skal den kjøres én gang. Det alene eliminerer av og til to alternativer.

Merk at kode med #KODE1 i seg ikke er kjørbar som den står. I denne boka er slike blokker derfor merket som ikke-kjørbare.

Minimaleksempel-testen

Metoden som gjør sjanger D mekanisk: velg det minste mulige inndataeksempelet — to eller tre elementer — og regn ut hva funksjonen returnerer med hvert av de fire alternativene.

Et godt minimaleksempel har tre egenskaper: det er lite nok til å regnes i hodet, det gir forskjellig svar for de forskjellige alternativene, og det inneholder det som skiller alternativene — for eksempel både et partall og et oddetall, eller både første og siste element.

Vær alltid ferdig med ett alternativ før du begynner på det neste. Blander du dem, ender du med å gjette.

Grensealternativet

Den vanligste D-oppgaven handler om en løkkegrense, og de fire alternativene skiller seg med nøyaktig én: range(len(x)) mot range(len(x) - 1) mot range(1, len(x)) mot range(0, len(x), 2).

Spørsmålene som avgjør:

- Skal det FØRSTE elementet være med? Da kan ikke rekka starte på 1.
- Sammenlignes elementet med naboen sin, x[i + 1]? Da må rekka stoppe én tidligere, ellers går indeksen ut over lista.
- Skal annethvert element behandles? Da må steget være 2 — og startverdien avgjør om det er de like eller de ulike indeksene.

Oppdateringslinja

Den nest vanligste D-oppgaven er linja som oppdaterer en variabel inne i en løkke: en akkumulator (total = total + v), en teller (antall = antall + 1), en beste-verdi (beste = v) eller en grense i et søk (imin = midt + 1).

Testen er alltid den samme: hva står i variabelen FØR linja, og hva må stå der ETTER? Alternativene skiller seg gjerne på om de bruker elementet v eller indeksen i, og på om de legger til eller tilordner på nytt.

Den nære distraktoren

I en godt laget D-oppgave er ett av de gale alternativene nesten riktig: det gir riktig svar for det enkleste eksempelet, og feil svar for ett bestemt tilfelle.

De tre vanligste formene:

- Linja gir riktig svar for ett element, men feil for to.
- Linja gir riktig svar når treffet ligger først, men feil når det ligger sist.
- Linja gir riktig svar for en ikke-tom liste, men avbryter programmet for den tomme.

Derfor holder det aldri med ett testeksempel. Finner du to alternativer som begge ser riktige ut, er det et signal om at du har funnet den nære distraktoren — og at du trenger et eksempel til som skiller dem.

✏️Eksempel 2: en gjennomarbeidet D-oppgave, alle fire alternativer prøvd

Funksjonen skal returnere True hvis tall er et primtall, altså et heltall større enn 1 som ikke er delelig med noe annet enn 1 og seg selv. Én linje mangler. Hvilket alternativ hører hjemme i #KODE1?

def er_primtall(tall):
    if tall < 2:
        return False
    for i in range(2, tall):
        #KODE1
            return False
    return True

a) if tall % i != 0:
b) if tall % i == 0:
c) if i % tall == 0:
d) if tall // i == 0:

Blokken er merket som ikke-kjørbar fordi den mangler en linje.

Steg 1 — spesifikasjonen. Funksjonen skal gi False så snart den finner en divisor, og True hvis den kommer gjennom hele løkka uten å finne noen.

Steg 2 — koden rundt hullet. Linja etter markøren er return False, med ett ekstra innrykk. Det betyr at #KODE1 er en if-linje, og at betingelsen må være sann når i ER en divisor.

Steg 3 — prøv hvert alternativ mot minimaleksemplet tall = 9. Løkka går over i lik 2, 3, 4, 5, 6, 7 og 8. Riktig svar er False, siden 3 deler 9.

AlternativHva skjer for tall = 9Resultat
a) tall % i != 0sann allerede for i lik 2, siden 9 delt på 2 gir restFalse — men av feil grunn
b) tall % i == 0usann for 2, sann for 3False — riktig
c) i % tall == 02 % 9 er 2, aldri 0 for i mindre enn tallTrue — feil
d) tall // i == 09 // 2 er 4, aldri 0 herTrue — feil

Steg 4 — kanttilfellet skiller a) fra b). Begge gir False for 9, men prøv tall = 7, som ER et primtall og skal gi True:
- Med a) er 7 % 2 != 0 sann med én gang, og funksjonen returnerer False. Feil.
- Med b) er ingen av testene sanne, løkka går til ende, og funksjonen returnerer True. Riktig.
Riktig svar: b)
Den ferdige funksjonen, kjørt:

def er_primtall(tall):
    if tall < 2:
        return False
    for i in range(2, tall):
        if tall % i == 0:
            return False
    return True

print(er_primtall(7), er_primtall(9), er_primtall(2), er_primtall(1))

Utskrift:

True False True False

Margnotat: legg merke til at alternativ a) var «riktig nok» for det første eksemplet. Det er nettopp derfor steg 4 finnes — et eneste testeksempel er ikke nok når to alternativer er nære hverandre.

📝Oppgave 8

(Innstegsoppgave, sjanger D — «fyll inn manglende kodelinje».) Funksjonen skal summere alle tallene i lista. Hvilket alternativ hører hjemme i #KODE1?

def summer(x):
    total = 0
    for v in x:
        #KODE1
    return total

a) total = v
b) total = total + v
c) total = total + 1
d) total = v + 1

Blokken er merket som ikke-kjørbar fordi den mangler en linje.

📝Oppgave 9
Eksamensnivå, sjanger D

Funksjonen skal kvadrere annethvert tall i lista, med start på det ANDRE tallet, og endre lista der den står. Hvilket alternativ hører hjemme i #KODE1?

def kvadrer_annethvert(x):
    #KODE1
        x[i] = x[i] ** 2
    return x

a) for i in range(0, len(x), 2):
b) for i in range(1, len(x)):
c) for i in range(1, len(x), 2):
d) for i in range(2, len(x), 2):

Blokken er merket som ikke-kjørbar fordi den mangler en linje.

📝Oppgave 10
Eksamensnivå, sjanger D

Funksjonen skal returnere det største tallet i lista. Hvilket alternativ hører hjemme i #KODE1?

def storst(x):
    beste = x[0]
    for v in x:
        if v > beste:
            #KODE1
    return beste

a) beste = v
b) beste = beste + v
c) v = beste
d) return v

Blokken er merket som ikke-kjørbar fordi den mangler en linje.

📝Oppgave 11
Eksamensnivå, sjanger D

Funksjonen skal telle hvor mange ganger hver verdi forekommer, og returnere en ordbok. Hvilket alternativ hører hjemme i #KODE1?

def tell(x):
    d = {}
    for v in x:
        #KODE1
    return d

a) d[v] = d[v] + 1
b) d[v] = 1
c) d[v] = d.get(v, 0) + 1
d) d.get(v, 0) + 1

Blokken er merket som ikke-kjørbar fordi den mangler en linje.

📝Oppgave 12
Eksamensnivå, sjanger D

Funksjonen skal sjekke om lista er sortert stigende ved å sammenligne hvert element med det neste. Hvilket alternativ hører hjemme i #KODE1?

def er_sortert(x):
    #KODE1
        if x[i] > x[i + 1]:
            return False
    return True

a) for i in range(len(x)):
b) for i in range(1, len(x)):
c) for i in range(len(x) + 1):
d) for i in range(len(x) - 1):

Blokken er merket som ikke-kjørbar fordi den mangler en linje.

📝Oppgave 13
Eksamensnivå, sjanger D

Funksjonen leser en tekstfil der hver linje har tre felt skilt med semikolon, og skal returnere en 2D-tabell der hver rad er ei liste av de tre feltene, uten linjeskift. Hvilket alternativ hører hjemme i #KODE1?

def les_tabell(filnavn):
    tabell = []
    f = open(filnavn, 'r')
    for linje in f:
        #KODE1
    f.close()
    return tabell

a) tabell.append(linje.split(';').strip())
b) tabell.append(linje.strip().split(';'))
c) tabell.append(linje.split(';'))
d) tabell.append(linje.strip())

Blokken er merket som ikke-kjørbar fordi den mangler en linje.

📝Oppgave 14
Eksamensnivå, sjanger D

Funksjonen leter etter en verdi i ei sortert liste ved å halvere søkeområdet for hvert steg. Den returnerer indeksen til treffet, eller −1. Hvilket alternativ hører hjemme i #KODE1?

def finn(x, maal):
    imin = 0
    imax = len(x) - 1
    while imin <= imax:
        #KODE1
        if x[imid] == maal:
            return imid
        elif x[imid] < maal:
            imin = imid + 1
        else:
            imax = imid - 1
    return -1

a) imid = (imin + imax) / 2
b) imid = (imin - imax) // 2
c) imid = (imin + imax) // 2
d) imid = len(x) // 2

Blokken er merket som ikke-kjørbar fordi den mangler en linje. Algoritmen bak — halveringssøket — hører til algoritmedelen senere i boka; her trenger du bare å lese koden som står der.

API- og konstruksjonsliste

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.