{
  "assessmentTests": {
    "python_test": {
      "name": "Python-test",
      "desc": "30 scenariospørsmål om syntaks, funksjoner, datastrukturer og objektatferd — finn ut om din Python-kunskap matcher det som jobbutlysninger forventer av Python-kompetanse.",
      "recommendation": "Din Python-ferdighetsprofil",
      "results": {
        "beginner": {
          "name": "Nybegynner",
          "desc": "Du kan følge et kort skript og endre verdier i det, men spørsmålene du bommet på handler først og fremst om språkets egen spesifikke atferd i stedet for generell logikk — et standardargument som bygges én gang og gjenbrukes, is versus == på to like lister, en variabel som blir lokal fra det øyeblikket du tildeler den noe som helst i en funksjon. Dette dreier seg ikke om å være dårlig til programmering; det er Python-spesifikke regler som forvirrer folk fra andre språk like ofte som nybegynnere. Det betyr noe på jobben fordi hver regel er der en feil skjuler seg i kode som ser riktig ut ved første øyekast.",
          "recommendation": "Begynn med tre ting, i denne rekkefølgen: mutable standardargumenter (hvorfor basket=[] er farlig), forskjellen mellom is og ==, og hvordan variabelscope fungerer inne i en funksjon. Den offisielle Python-opplæringen på docs.python.org dekker alle tre direkte, og søkeordet \"Python gotchas\" finner opp gjennomarbeidede eksempler på hver."
        },
        "intermediate": {
          "name": "Intermediær",
          "desc": "Du håndterer hverdagslig scripting komfortabelt — datastrukturer, kontrollflyt, unkompliserte funksjoner — og ville ikke bli sakket ned av rutinemessig vedlikehold eller en liten feature på en eksisterende kodebase. Gapet mellom her og Avansert er først og fremst det som skjer når Pythons bekvemmelighetsfunksjoner samhandler med hverandre: en grunn kopi som etterlater nestet data delt når du forventet den duplisert, en generators returverdi som stille blir en del av utdatamengden, dekoratørgrup som stables i en rekkefølge som er lett å få bakover. Det er den type feil en senior reviewer merker på ti sekunder og alle andre bruker en time på å jage.",
          "recommendation": "Fokuser på objekt- og iterasjonsinternals: grunn versus dyp kopi, hva en generator faktisk gjør med return, og hvordan dekoratørenes stakkingsrekkefølge fungerer. Deretter klassegrunnlag som de fleste opplæringsprogrammer hopper over — standardlikhet uten __eq__, og hvorfor et foranderlig klassattributt deles på tvers av hver instans."
        },
        "advanced": {
          "name": "Avansert",
          "desc": "Dette er nivået de fleste jobbutlysninger mener med \"sterk Python.\" Du griper til det rette verktøyet uten å lete etter det, du vet hvorfor et stykke delt tilstand endret seg i stedet for bare at det gjorde det, og du kan lese en annen persons funksjon og forutsi utdatamengden riktig. Det som skiller dette bandet fra toppen, er forsvarsiden av arbeidet: å vite hvilken av to korrekt utseende tilnærminger som oppfører seg dårlig når et klassattributt, et keyword-only-argument, eller et unntakshierarki er involvert.",
          "recommendation": "Skyv inn i delene som beskytter en kodebase som andre også rører: keyword-only-argumenter som et API-designvalg i stedet for bare en syntakskuriositet, unntakshierarkiet (slik at except-ledd fanger den rette feiltypefamilien, ikke bare en klasse), og kontekstadministratorer som standardveien for å garantere opprydning. Real Python sine dyptgående artikler er et godt neste stoppested for alle tre."
        },
        "expert": {
          "name": "Ekspert",
          "desc": "Du scoret på toppen av hver del — kjernespyntaks, funksjoner og scope, datastrukturer, og objektorientert idiomer. Praktisk sett betyr det at du kan få overlevert en fremmed fil og forklare hvorfor den produserer utdatamengden den gjør, ikke bare hva syntaksen sier den burde gjøre, noe som er den vanskeligere og mer verdifulle ferdigheten. På dette nivået er råsproget sjelden begrensningsfaktoren i arbeidet ditt; grensen er vanligvis systemets størrelse eller form omkring koden.",
          "recommendation": "Avkastningen ligger nå i verktøy og gjennomgang: statisk typekontroll med mypy eller pyright, profilering før optimalisering i stedet for gjetning, og lesing av andre menneskers pull-forespørsler for nøyaktig denne kategorien av feil — de som passerer hver test og fortsatt gjør det feil under en bestemt inndata. Hvis du blir screenet for en rolle, beskriv en feil som denne som du fant i stedet for å nevne språkfunksjoner — det demonstrerer resonnementet, ikke bare ordforrådet."
        }
      },
      "questions": [
        {
          "question": "Du skriver def add_item(item, basket=[]): basket.append(item); return basket, deretter kaller du add_item('a') og add_item('b'), begge ganger uten å oppgi basket. Hva returnerer den andre kallet?",
          "options": [
            {
              "icon": "",
              "label": "['b'] — hvert kall får en fersk tom liste som standard"
            },
            {
              "icon": "",
              "label": "TypeError — du må oppgi et basket-argument"
            },
            {
              "icon": "",
              "label": "['a', 'b'] — standardlisten opprettes én gang og gjenbrukes på tvers av kall"
            },
            {
              "icon": "",
              "label": "['a'] deretter ['b'] som to uavhengige enliste-lister"
            }
          ]
        },
        {
          "question": "a = [1, 2, 3] og b = [1, 2, 3]. Hva returnerer a == b, og hva returnerer a is b?",
          "options": [
            {
              "icon": "",
              "label": "True for begge — identiske lister er alltid det samme objektet"
            },
            {
              "icon": "",
              "label": "True for ==, False for is — like innhold men ulike objekter i minnet"
            },
            {
              "icon": "",
              "label": "False for begge — separate litteraler er aldri like i Python"
            },
            {
              "icon": "",
              "label": "True for is, False for == — is sjekker verdilikhet for lister"
            }
          ]
        },
        {
          "question": "I Python 3, hva evaluerer 7 / 2 til, og hva evaluerer 7 // 2 til?",
          "options": [
            {
              "icon": "",
              "label": "3.5, deretter 3 — / returnerer alltid en float, // avrunder resultatet nedover"
            },
            {
              "icon": "",
              "label": "3, deretter 3.5 — / avkorter og // returnerer en float"
            },
            {
              "icon": "",
              "label": "3.5, deretter 3.5 — begge operatørene returnerer en float i Python 3"
            },
            {
              "icon": "",
              "label": "3, derefter 3 — begge operatørene avrunder nedover i Python 3"
            }
          ]
        },
        {
          "question": "s = 'hello', deretter kjører du s[0] = 'H'. Hva skjer?",
          "options": [
            {
              "icon": "",
              "label": "s blir 'Hello'"
            },
            {
              "icon": "",
              "label": "s blir 'Hhello' fordi tegnet blir satt inn, ikke erstattet"
            },
            {
              "icon": "",
              "label": "TypeError — strenger er uforanderlige og støtter ikke elementtilordning"
            },
            {
              "icon": "",
              "label": "Ingenting — tilordningen blir ignorert stille og s forblir 'hello'"
            }
          ]
        },
        {
          "question": "x = [10, 20, 30, 40, 50]. Hva returnerer x[1:4]?",
          "options": [
            {
              "icon": "",
              "label": "[20, 30, 40, 50]"
            },
            {
              "icon": "",
              "label": "[10, 20, 30, 40]"
            },
            {
              "icon": "",
              "label": "[20, 30, 40]"
            },
            {
              "icon": "",
              "label": "[30, 40]"
            }
          ]
        },
        {
          "question": "name = 'Ana' og age = 30. Hva produserer f'{name} is {age}'?",
          "options": [
            {
              "icon": "",
              "label": "{name} is {age}"
            },
            {
              "icon": "",
              "label": "Ana is 30"
            },
            {
              "icon": "",
              "label": "name is age"
            },
            {
              "icon": "",
              "label": "En TypeError, fordi f-strenger krever format()-metoden"
            }
          ]
        },
        {
          "question": "Hva evaluerer 1 < 2 < 3 til?",
          "options": [
            {
              "icon": "",
              "label": "True — Python kjeder sammenligningene som (1 < 2) og (2 < 3)"
            },
            {
              "icon": "",
              "label": "False — kjetet sammenligninger evalueres fra venstre til høyre uten kortslutnning, noe som gir 1 < 2 < 3 -> 1 < True -> False"
            },
            {
              "icon": "",
              "label": "En SyntaxError — sammenligninger kan ikke kjedes"
            },
            {
              "icon": "",
              "label": "3 — Python returnerer den siste verdien i kjeden"
            }
          ]
        },
        {
          "question": "Hva returnerer bool([]), og hva returnerer bool([0])?",
          "options": [
            {
              "icon": "",
              "label": "False, deretter False — enhver liste som inneholder bare usanne verdier er usann"
            },
            {
              "icon": "",
              "label": "False, deretter True — en tom liste er usann, en liste som inneholder ett element (selv 0) er sant"
            },
            {
              "icon": "",
              "label": "True, deretter True — ikke-None-objekter er alltid sanne"
            },
            {
              "icon": "",
              "label": "True, derefter False — en liste er sann bare når den er tom"
            }
          ]
        },
        {
          "question": "En modul-nivå count = 0 finnes. Inne i def increment(): count += 1; return count, kaller du increment(). Hva skjer?",
          "options": [
            {
              "icon": "",
              "label": "UnboundLocalError — tilordning til count hvor som helst i funksjonen gjør den lokal, så count += 1 prøver å lese en lokal variabel før den blir tilordnet"
            },
            {
              "icon": "",
              "label": "Den returnerer 1 og inkrementerer modul-nivå count til 1"
            },
            {
              "icon": "",
              "label": "Den returnerer 1 men etterlater modul-nivå count på 0"
            },
            {
              "icon": "",
              "label": "Den kaster NameError fordi count aldri ble erklært inne i funksjonen"
            }
          ]
        },
        {
          "question": "def f(*args, **kwargs): return args, kwargs. Hva returnerer f(1, 2, x=3)?",
          "options": [
            {
              "icon": "",
              "label": "([1, 2], {'x': 3})"
            },
            {
              "icon": "",
              "label": "((1, 2), {'x': 3})"
            },
            {
              "icon": "",
              "label": "(1, 2, {'x': 3})"
            },
            {
              "icon": "",
              "label": "TypeError — posisjonsargumenter og nøkkelordargumenter kan ikke blandes i ett kall"
            }
          ]
        },
        {
          "question": "Du bygger funcs = [lambda: i for i in range(3)] i en løkke. Hva returnerer [f() for f in funcs]?",
          "options": [
            {
              "icon": "",
              "label": "[2, 2, 2] — hver lambda ser opp i når den kalles, og innen den tiden har løkken avsluttet med i lik 2"
            },
            {
              "icon": "",
              "label": "[0, 1, 2] — hver lambda fanger verdien av i på det tidspunktet den ble opprettet"
            },
            {
              "icon": "",
              "label": "[0, 0, 0] — lambdaer fanger alltid den første verdien som er tilordnet en variabel"
            },
            {
              "icon": "",
              "label": "En NameError, fordi i ikke lenger finnes når løkken avsluttes"
            }
          ]
        },
        {
          "question": "En funksjon er definert med @a direkte over @b, som sitter direkte over def f(): pass. I hvilken rekkefølge blir dekoratørene brukt på f?",
          "options": [
            {
              "icon": "",
              "label": "b omslutter f først, deretter omslutter a resultatet av b — dekoratøren nærmest funksjonen kjører først"
            },
            {
              "icon": "",
              "label": "a omslutter f først, deretter omslutter b resultatet — dekoratører brukes fra topp til bunn"
            },
            {
              "icon": "",
              "label": "Begge dekoratørene omslutter f uavhengig og bare den siste som er definert får effekt"
            },
            {
              "icon": "",
              "label": "Det avhenger av rekkefølgen dekoratørene importeres, ikke deres posisjon i koden"
            }
          ]
        },
        {
          "question": "def f(a, *, b): return a + b. Hvilket av disse kallene fungerer?",
          "options": [
            {
              "icon": "",
              "label": "f(1, b=2) — b må sendes etter nøkkelord fordi den kommer etter den bare * i signaturen"
            },
            {
              "icon": "",
              "label": "f(1, 2) — posisjonsargumenter fyller parametere fra venstre til høyre uavhengig av *"
            },
            {
              "icon": "",
              "label": "f(a=1, 2) — nøkkelordargumenter må komme først"
            },
            {
              "icon": "",
              "label": "f(1) — b er valgfritt fordi det følger *"
            }
          ]
        },
        {
          "question": "En generatorfunksjon gir 1, deretter gir 2, derefter gjør return 99. Hva inneholder list(the_generator()), og hva skjer med 99?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 99] — return inne i en generator oppfører seg som en yield til"
            },
            {
              "icon": "",
              "label": "[99] — return overstyrer umiddelbar alle verdier som allerede er gitt"
            },
            {
              "icon": "",
              "label": "[1, 2] — returverdien av en generator blir verdien knyttet til StopIteration som den kaster, den er ikke gitt"
            },
            {
              "icon": "",
              "label": "En RuntimeError, fordi generatorer ikke kan inneholde en return-uttalelse"
            }
          ]
        },
        {
          "question": "I en outer()-funksjon settes x = 1, deretter gjør en nestet inner() nonlocal x; x += 1, og outer() kaller inner() før return x. Hva returnerer outer()?",
          "options": [
            {
              "icon": "",
              "label": "1 — inner() opererer på sin egen lokale kopi av x, så endringen blir ikke stående"
            },
            {
              "icon": "",
              "label": "En UnboundLocalError, fordi x ikke er erklært inne i inner() før nonlocal-uttalelsen"
            },
            {
              "icon": "",
              "label": "En SyntaxError — nonlocal kan bare brukes inne i klasser"
            },
            {
              "icon": "",
              "label": "2 — nonlocal lar inner() endre ytter-funksjonen x i stedet for å opprette en ny lokal variabel"
            }
          ]
        },
        {
          "question": "d = {'a': 1, 'b': 2}. Hva returnerer d.get('c', 0), og legger den til 'c' i ordboken?",
          "options": [
            {
              "icon": "",
              "label": "0, og nei — get() returnerer standarden uten å sette inn nøkkelen"
            },
            {
              "icon": "",
              "label": "0, og ja — get() setter inn nøkkelen med standardverdien"
            },
            {
              "icon": "",
              "label": "KeyError, fordi 'c' ikke finnes"
            },
            {
              "icon": "",
              "label": "None, og ja — get() legger alltid til manglende nøkler med en None-verdi"
            }
          ]
        },
        {
          "question": "t = (1, 2, [3, 4]). Kan du kjøre t[2].append(5), og kan du kjøre t[0] = 10?",
          "options": [
            {
              "icon": "",
              "label": "Begge fungerer — å nesle en liste inne i en tuple gjør hele tuppelen foranderlig"
            },
            {
              "icon": "",
              "label": "Begge kaster TypeError — ingenting inne i en tuple kan noensinne endres"
            },
            {
              "icon": "",
              "label": "t[2].append(5) kaster TypeError, men t[0] = 10 fungerer fordi tuples tillater omtildeling av sitt første element"
            },
            {
              "icon": "",
              "label": "t[2].append(5) fungerer fordi listen inne er foranderlig; t[0] = 10 kaster TypeError fordi tuppelen selv er uforanderlig"
            }
          ]
        },
        {
          "question": "Hvilken av disse returnerer en iterator som beregner verdier latent i stedet for å bygge hele sekvensen i minnet på en gang: [x*x for x in range(1000000)] eller (x*x for x in range(1000000))?",
          "options": [
            {
              "icon": "",
              "label": "Den med parenteser, (x*x for x in range(1000000)) — det er et generatoruttrykk"
            },
            {
              "icon": "",
              "label": "Den med firkantete parenteser — listekomprehensjonar er alltid late i Python 3"
            },
            {
              "icon": "",
              "label": "Begge er late — den eneste forskjellen er typen som returneres på slutten"
            },
            {
              "icon": "",
              "label": "Ingen — begge bygger hele sekvensen i minnet umiddelbar"
            }
          ]
        },
        {
          "question": "En try-blokk deler med null, except ZeroDivisionError-ledd skriver 'a', og en finally-ledd skriver 'b'. Hva skriver, og i hvilken rekkefølge?",
          "options": [
            {
              "icon": "",
              "label": "b deretter a — finally kjører alltid før noen except-ledd"
            },
            {
              "icon": "",
              "label": "a deretter b — det samsvarende except kjøres først, og finally kjører alltid etterpå uansett"
            },
            {
              "icon": "",
              "label": "Bare b — unntaket blir egentlig ikke fanget, så 'a' skriver aldri"
            },
            {
              "icon": "",
              "label": "Bare a — finally hoppes over når et unntak allerede er håndtert"
            }
          ]
        },
        {
          "question": "import copy; a = [[1, 2], [3, 4]]; b = copy.copy(a); b[0].append(99). Endres a[0] også?",
          "options": [
            {
              "icon": "",
              "label": "Nei — copy.copy() dupliserer alltid nestede objekter også"
            },
            {
              "icon": "",
              "label": "Nei — å legge til i b[0] oppretter en helt ny liste for bare b[0]"
            },
            {
              "icon": "",
              "label": "Ja, men bare fordi copy.copy() ble kalt uten deepcopy-argumentet"
            },
            {
              "icon": "",
              "label": "Ja — copy.copy() gjør en grunn kopi, så de nestede listene deles fortsatt mellom a og b"
            }
          ]
        },
        {
          "question": "d = {'x': 1, 'y': 2}. Hva sjekker 'x' in d mot — nøklene, verdiene eller begge?",
          "options": [
            {
              "icon": "",
              "label": "Verdiene — `in` sjekker om 1 eller 2 er lik 'x'"
            },
            {
              "icon": "",
              "label": "Både nøkler og verdier blir sjekket"
            },
            {
              "icon": "",
              "label": "Ingen — `in` på en ordboken kaster alltid TypeError"
            },
            {
              "icon": "",
              "label": "Nøklene — `in` på en ordbok tester medlemskap blant dens nøkler, ikke dens verdier"
            }
          ]
        },
        {
          "question": "names = ['Al', 'Bo'] og scores = [10, 20]. Hva returnerer list(zip(names, scores))?",
          "options": [
            {
              "icon": "",
              "label": "[('Al', 'Bo'), (10, 20)]"
            },
            {
              "icon": "",
              "label": "['Al', 10, 'Bo', 20]"
            },
            {
              "icon": "",
              "label": "[('Al', 10), ('Bo', 20)]"
            },
            {
              "icon": "",
              "label": "En ValueError, fordi zip krever tre eller flere argumenter"
            }
          ]
        },
        {
          "question": "class Dog: tricks = [] holder en klassenliste, og add_trick legger til i self.tricks. d1 = Dog() og d2 = Dog() blir begge opprettet, deretter kjører d1.add_trick('sit'). Hva inneholder d2.tricks?",
          "options": [
            {
              "icon": "",
              "label": "[] — hver instans får sin egen uavhengige kopi av tricks"
            },
            {
              "icon": "",
              "label": "['sit'] — tricks er en klassenliste delt av hver instans, så d1s endring er synlig på d2 også"
            },
            {
              "icon": "",
              "label": "En TypeError — instanser kan ikke legge til i et klasseattributt"
            },
            {
              "icon": "",
              "label": "['sit'] bare etter at d2 = Dog() blir kjørt på nytt"
            }
          ]
        },
        {
          "question": "class A har def greet(self): return 'A'. class B(A) har def greet(self): return 'B' + super().greet(). Hva returnerer B().greet()?",
          "options": [
            {
              "icon": "",
              "label": "'AB' — super() kjører alltid før underkjasses egen kode"
            },
            {
              "icon": "",
              "label": "'B' — super().greet() blir ignorert fordi B allerede overstyrer greet"
            },
            {
              "icon": "",
              "label": "'BA' — super().greet() kaller A's metode og dens resultat legges til 'B'"
            },
            {
              "icon": "",
              "label": "En AttributeError, fordi A har ingen greet-metode synlig for B"
            }
          ]
        },
        {
          "question": "class Point lagrer self.x i __init__ og definerer ingen andre metoder. p1 = Point(1) og p2 = Point(1). Hva returnerer p1 == p2 som standard?",
          "options": [
            {
              "icon": "",
              "label": "True — Python sammenligner alle samsvarende attributter som standard"
            },
            {
              "icon": "",
              "label": "False — uten en tilpasset __eq__, faller == tilbake til identitetssammenligning, og p1 og p2 er ulike objekter"
            },
            {
              "icon": "",
              "label": "True, men bare fordi begge objekter ble opprettet med det samme argumentet"
            },
            {
              "icon": "",
              "label": "En TypeError, fordi Point ikke definerer __eq__"
            }
          ]
        },
        {
          "question": "Hvilken except-ledd nedenfor vil også fange en ZeroDivisionError: except ArithmeticError, except ValueError, eller except KeyError?",
          "options": [
            {
              "icon": "",
              "label": "except ValueError — delingsfeil behandles som ugyldige verdier"
            },
            {
              "icon": "",
              "label": "except KeyError — enhver kjøretidsfeil ikke knyttet til en spesifikk type faller tilbake til KeyError"
            },
            {
              "icon": "",
              "label": "Ingen av dem — bare except ZeroDivisionError selv kan fange den"
            },
            {
              "icon": "",
              "label": "except ArithmeticError — ZeroDivisionError er en underklasse av ArithmeticError"
            }
          ]
        },
        {
          "question": "Du åpner en fil med open('data.txt') as f: og et unntak blir reist mens du leser inne i blokken. Blir filen fortsatt lukket?",
          "options": [
            {
              "icon": "",
              "label": "Nei — filen forblir åpen fordi blokken ikke ble avsluttet normalt"
            },
            {
              "icon": "",
              "label": "Bare hvis du også legger til en finally-ledd rundt with-uttalelsen"
            },
            {
              "icon": "",
              "label": "Ja — with-uttalelsen kaller filens __exit__-metode, som lukker den, selv hvis et unntak oppstår inne i blokken"
            },
            {
              "icon": "",
              "label": "Det avhenger av unntakstypen — bare unntak som fanges andre steder utløser rydding"
            }
          ]
        },
        {
          "question": "x = [3, 1, 2] og y = x.sort(). Hva holder y?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 3] — sort() returnerer den nylig sorterte listen"
            },
            {
              "icon": "",
              "label": "None — list.sort() sorterer på plass og returnerer None; x selv blir [1, 2, 3]"
            },
            {
              "icon": "",
              "label": "[3, 1, 2] — sort() returnerer den opprinnelig usorterte listen og endrer bare xs interne orden"
            },
            {
              "icon": "",
              "label": "En TypeError, fordi sort() ikke kan tilordnes en variabel"
            }
          ]
        },
        {
          "question": "Hva skjer når du kjører 'Score: ' + 42?",
          "options": [
            {
              "icon": "",
              "label": "'Score: 42' — Python konverterer tallet automatisk inne i et +-uttrykk"
            },
            {
              "icon": "",
              "label": "'Score: ' — tallet blir stille droppet"
            },
            {
              "icon": "",
              "label": "42 — strengen blir tvunget til et tall og lagt til"
            },
            {
              "icon": "",
              "label": "TypeError — du kan ikke konkatenere en str og en int direkte, 42 må konverteres med str() først"
            }
          ]
        },
        {
          "question": "Du må sjekke om en liste kalt results er tom. Hva er den idiomatiske Python-måten: if results == []: , if len(results) == 0: , eller if not results: ?",
          "options": [
            {
              "icon": "",
              "label": "if results == []: — dette er den eneste pålitelige måten å oppdage en tom liste"
            },
            {
              "icon": "",
              "label": "if len(results) == 0: — dette er nødvendig fordi tomme lister er sanne i Python"
            },
            {
              "icon": "",
              "label": "Alle tre brukes aldri i praksis; standardtilnærmingen er if results is None:"
            },
            {
              "icon": "",
              "label": "if not results: — Python-idiom stole på sannhet, og en tom liste er usann"
            }
          ]
        }
      ],
      "optionOrderVersion": "92945565db6c55da"
    }
  }
}
