Föreläsningsöversikt¶
- Termövning 25/2
- Laboration 3: En egen pokedex som hämtar data från webben
- Oföränderliga och föränderliga värden
- Variabler som referenser
- Associationstabeller:
dict - Mer om dataabstraktion
- Nästlade datastrukturer
- Bearbetning av nästlade datastrukturer
- Strängformatering med f-strängar
Termövning 25e februari¶
- Uppdelat i 3 pass
- 13.15 - 14.30 Y1.a och Y1.b
- 14.30 - 15.45 Y1.c och TMA
- 15.45 - 17.00 MED
- Ingen förberedelse behövs.
- Men titta gärna på introduktionsbilderna här så kommer ni igång snabbare.
- Samling i S26 på utsatt tid
- Kort introduktion av mig
- Sedan följer ni en av assistenterna till anvisad sal
- Brukar upplevas som ett av de mest värdefulla momenten i hela kursen och har tidigarelagts i år på inrådan av förra årets studenter.
Kort om laboration 3, Del 2¶
- Hämta information från webben istället för från fil
- Textbaserat data-format: JSON
- Webb-API:er - som om URL:er ("webbadresser") vore funktioner som returnerar data.
- PokeAPI - ett webb-API till en databas om Pokémon.
pokedex.py- skript som skriver ut information om en Pokémon.
- Lektion 3: övningar inför Del 2
- paketet
requestsför att hämta data från webben - JSON-data till dictionary
- paketet
Oföränderliga värden¶
- I Python är strängar, heltal, flyttal, sanningsvärden,
Noneoch tupler oföränderliga (eng. immutable). - Detta betyder att man inte kan ändra på dessa värden.
- t.ex. så kan inte ändra värdet
5till värdet1, värdet5är alltid5. - Python behandlar strängar på samma sätt; i Python kan vi inte ändra strängen
"hej"till strängen"nej"
- t.ex. så kan inte ändra värdet
Föränderliga värden¶
- Av de datatyper som vi stött på så tillhör bara listor kategorin förändringsbara (eng. mutable) värden.
- Detta betyder att vi kan ändra på dessa värden.
- Vi kan t.ex. byta ut första elementet i listan
[1, 2, 3]till5
In [1]:
numbers = [1, 2, 3]
print(numbers)
numbers[0] = 5
print(numbers)
[1, 2, 3] [5, 2, 3]
Jämförelse¶
In [3]:
numbers_list = [1, 2, 3]
print(numbers_list)
numbers_list[0] = 5
print(numbers_list)
[1, 2, 3] [5, 2, 3]
In [4]:
numbers_tuple = (1, 2, 3)
print(numbers_tuple)
numbers_tuple[0] = 5
print(numbers_tuple)
(1, 2, 3)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[4], line 3 1 numbers_tuple = (1, 2, 3) 2 print(numbers_tuple) ----> 3 numbers_tuple[0] = 5 4 print(numbers_tuple) TypeError: 'tuple' object does not support item assignment
"Ändra" oföränderliga värden¶
- Vi använder funktionen
idför att skriva ut minnesadressen för ett visst värde.
In [5]:
numbers_list = [1, 2, 3]
print("Before:", numbers_list, "at memory address", id(numbers_list))
numbers_list[0] = 5
print(" After:", numbers_list, "at memory address", id(numbers_list))
Before: [1, 2, 3] at memory address 140579410135936 After: [5, 2, 3] at memory address 140579410135936
In [6]:
numbers_tuple = (1, 2, 3)
print("Before:", numbers_tuple, "at memory address", id(numbers_tuple))
numbers_tuple = (5,) + numbers_tuple[1:]
print(" After:", numbers_tuple, "at memory address", id(numbers_tuple))
Before: (1, 2, 3) at memory address 140579408295936 After: (5, 2, 3) at memory address 140579408288384
Vad spelar det för roll?¶
- Föränderliga värden
- Snabbare (utom för väldigt stora värden).
- Mindre säkert.
- Oföränderliga värden
- Långsammare (utom för väldigt stora värden).
- Säkrare.
- Föränderliga värden kan introducera svårhittade buggar.
- För att förstå varför behöver vi prata om referenser.
Variabler som referenser till värden¶
- I de flesta fall är det lämpligast att se variabler som "etiketter" som refererar till värden.
- En tilldelningssats, t.ex.
result = "", kan ses som att vi säger "låt etiketten result referera till värdet ..." - Liknelsen från första föreläsningen, där variabler beskrevs som lådor som innehåller värden, är alltså inte riktigt korrekt.
Variabler är inte lådor med värden i
- Man säger ofta lite slarvigt att en variabel "innehåller" ett värde, och illustrerar det med att variabeln är en låda som man stoppar ett värde i.
- (T.ex. beskrev jag det så i kursens första föreläsning.)
- Det är mer korrekt (i Python) att säga att en variabel innehåller en referens till ett värde.
- Flera variabler kan referera till samma värde, dvs. till samma stycke data i minnet.
- Vi kan byta ut vilket värde som en variabel refererar till, dvs. vilket stycke data i minnet som som pekas ut, utan ändra på den data som ligger på den ursprungliga platsen i minnet.
- Om ett värde är förändringsbart kan vi ändra på värdet som variabeln refererar till, dvs. och detta speglas i alla referenser till det värdet.
Flera referenser till samma värde¶
In [7]:
numbers_list = [1, 2, 3]
other_list = numbers_list
print("numbers_list is", numbers_list, "at memory address", id(numbers_list))
print(" other_list is", other_list, "at memory address", id(other_list))
numbers_list is [1, 2, 3] at memory address 140579410183168 other_list is [1, 2, 3] at memory address 140579410183168
Konsekvenser¶
In [8]:
numbers_list = [1, 2, 3]
other_list = numbers_list
numbers_tuple = (1, 2, 3)
other_tuple = numbers_tuple
print(" numbers_list is", numbers_list, "at memory address", id(numbers_list))
print(" other_list is", other_list, "at memory address", id(other_list))
print("numbers_tuple is", numbers_tuple, "at memory address", id(numbers_tuple))
print(" other_tuple is", other_tuple, "at memory address", id(other_tuple))
numbers_list is [1, 2, 3] at memory address 140579418594880 other_list is [1, 2, 3] at memory address 140579418594880 numbers_tuple is (1, 2, 3) at memory address 140579783559680 other_tuple is (1, 2, 3) at memory address 140579783559680
In [9]:
numbers_list[0] = 5
numbers_tuple = (5,) + numbers_tuple[1:]
print(" numbers_list is", numbers_list, "at memory address", id(numbers_list))
print(" other_list is", other_list, "at memory address", id(other_list))
print("numbers_tuple is", numbers_tuple, "at memory address", id(numbers_tuple))
print(" other_tuple is", other_tuple, "at memory address", id(other_tuple))
numbers_list is [5, 2, 3] at memory address 140579418594880 other_list is [5, 2, 3] at memory address 140579418594880 numbers_tuple is (5, 2, 3) at memory address 140579410135168 other_tuple is (1, 2, 3) at memory address 140579783559680
Vad händer när vi skickar föränderliga värden till funktioner?¶
In [10]:
def change_and_return_list(a_list):
a_list[0] = 5
a_list.append("list was changed")
return a_list
numbers_list = [1, 2, 3]
other_list = numbers_list
third_list = change_and_return_list(numbers_list)
In [11]:
print(numbers_list)
print(other_list)
print(third_list)
[5, 2, 3, 'list was changed'] [5, 2, 3, 'list was changed'] [5, 2, 3, 'list was changed']
Beror på vad funktionen gör!¶
In [12]:
def change_and_return_list(a_list):
a_list[0] = 5
return a_list + ["list was changed"]
my_list = [1, 2, 3]
other_list = my_list
third_list = change_and_return_list(my_list)
In [13]:
print(my_list)
print(other_list)
print(third_list)
[5, 2, 3] [5, 2, 3] [5, 2, 3, 'list was changed']
Dictionary
- Dictionary eller
dicti Python.- Mer generellt: associationslista eller associationstabell (eng. associative array, symbol table, map)
- (Kärt barn har många namn.)
- Nyckel-värde-par
- Värden hämtas med hjälp av nyckel istället för index som i fallet med listor och tupler.
- Alla datatyper som är oföränderliga (immutable) kan användas som nycklar, t.ex. flyttal, heltal, strängar, tupler
- Alla datatyper kan vara värden
Varför namnet "dictionary"?¶
- Ordet dictionary är en väldigt bra beskrivning av vad det handlar om.
- Vi slår upp ett ord, och får den vägen veta något om ordet, t.ex. dess definition, hur det uttalas, eller den äldsta dokumenterade förekomsten av ordet.
- Speciellt bra liknelse blir det om vi tänker oss ett klassiskt översättningslexikon, säg mellan svenska och engelska.
- Vi slår upp ett svenskt ord, nyckeln, och får den vägen veta dess översättning, värdet, på engelska.
- I programmeringssammanhang är vi inte bara begränsade till sträng-till-sträng-"översättning", men principen är densamma.
- Av något skäl har den här principen visat sig förvånansvärt svår att greppa för många studenter (även för mig, för sisådär 20 år sedan).
- Troligvis för att konceptet tenderar att introduceras vid en sådan tidpunkt att man som student förväntar sig något mycket mer komplicerat.
- Här kommer därför ett försök till en osedvanligt rigorös beskrivning av vad det handlar om.
Matematisk funktion
- Definition: Låt $A$ och $B$ vara två mängder. En funktion $f$ från $A$ till $B$ är en relation mellan $A$ och $B$, som har egenskapen att för varje $x \in A$ finns precis ett $y \in B$ sådant att $(x, y) \in f$.
- Vi säger saker i stil med $f: A \rightarrow B$, $x \mapsto f(x)$, och om $(x, y) \in f$ så betyder det att $y = f(x)$.
- Detta har vi pratat om förut och är något alla förhoppningsvis är bekanta med.
Mappning som matematisk funktion¶
- Rent logiskt ingen skillnad mellan en funktion och en mappning.
- I praktiken uttrycks en funktion oftast som en formel.
- Inom den matematik vi är vana vid sedan åtminstone gymnasiet, t.ex. ett polynom.
- Inom programmering, en serie operationer som givet en viss input beräknar en viss out output.
- Vi skulle dock kunna explicit definiera varje $x \mapsto y$
- T.ex. för kvadraten av positiva heltal skulle det se ut som:
En dict för kvadrater i Python¶
- Vi kan representera de första sju kvadraterna med en
dictpå följande sätt:
In [ ]:
squares = {1:1, 2:4, 3:9, 4:16, 5:25, 6:36, 7:49}
print("The square of 3 is", squares[3])
- Det är viktigt att inse att ingen ytterligare inferens eller extrapolering görs utifrån de par som vi definierat, bara de par som explicit lagts till i
dict:en kan slås upp.- Dvs. vi kan inte slå upp kvadraten av 8 i
squares:
- Dvs. vi kan inte slå upp kvadraten av 8 i
In [5]:
print("The square of 8 is", squares[8])
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[5], line 1 ----> 1 print("The square of 8 is", squares[8]) NameError: name 'squares' is not defined
En dict för kvadrater i Python¶
- Vi kan representera de första 4 kvadraterna på följande sätt:
In [14]:
squares = {1:1, 2:4, 3:9, 4:16}
print("The square of 3 is", squares[3])
The square of 3 is 9
- Det är viktigt att inse att ingen ytterligare inferens eller extrapolering görs utifrån de par som vi definierat, bara de par som explicit lagts till i
dict:en kan slås upp.- Dvs. vi kan inte slå upp kvadraten av 5 i
squares:
- Dvs. vi kan inte slå upp kvadraten av 5 i
In [15]:
print("The square of 5 is", squares[5])
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Cell In[15], line 1 ----> 1 print("The square of 5 is", squares[5]) KeyError: 5
Varför inte bara uttrycka det som en formel?¶
- Kvadratfunktionen för positiva heltal går enkelt att uttrycka som en generell formel som gäller för alla positiva heltal, nämligen:
- Inte alla mappningar går att uttrycka lika enkelt som en formel.
- Hur skulle t.ex. formeln för en mappning mellan personer och deras födelseår se ut?
- Vi blir tvugna att explicit lista associationerna på något sätt:
Födelseår i Python¶
- Skulle vi använda en vanlig Python-funktion, som vi är vana vid sedan tidigare, skulle det kunna se ut som:
In [16]:
def birth_year_fun(name):
if name == "Newton":
return 1643
elif name == "al-Khwarizmi":
return 780
elif name == "Gauss":
return 1777
elif name == "Turing":
return 1912
print("Turing's birth year is", birth_year_fun('Turing'))
Turing's birth year is 1912
- Som
dict:
In [17]:
birth_year_dict = {"Newton": 1643, "al-Khwarizmi": 780, "Gauss": 1777, "Turing": 1912}
print("Turing's birth year is", birth_year_dict['Turing'])
Turing's birth year is 1912
En dict är en samling¶
- Har en storlek som är antalet nyckel-värde-par.
- Dvs. inte summan av antalet nycklar och antalet värden.
In [18]:
len({1:1, 2:4, 3:9})
Out[18]:
3
- En
dictär dock inte en sekvens, dvs. vi kan inte använda index eller slice för att slå upp värden. - Subskriptnotationen används istället för att slå upp värdet associerat med en viss nyckel:
- T.ex. uttrycket
birth_year_dict['Turing']beräknas till1912.
- T.ex. uttrycket
En dict är förändringsbar¶
- Dvs. vi får göra nedanstående om vi skulle komma fram att
780var fel födelseår för al-Khwarizmi.- (I verkligheten vet vi inte exakt vilket år al-Khwarizmi föddes, bara att det var runt 780.)
birth_year_dict['al-Khwarizmi'] = 779
- Vi kan också lägga till nya nyckel-värde-par genom tilldelning på följande vis:
birth_year_dict['Cantor'] = 1845
Nycklarna måste vara unika¶
- Bara det sista nyckel-värde-paret med en viss nyckel kommer att lagras.
In [19]:
hcs_surnames = {"Erik": "Prytz", "Erik": "Berglund"}
print(hcs_surnames)
{'Erik': 'Berglund'}
- Men inte värdena
- Flera nycklar kan ha samma värde:
In [20]:
hcs_firstnames = {"Prytz": "Erik", "Berglund": "Erik"}
print(hcs_firstnames)
{'Prytz': 'Erik', 'Berglund': 'Erik'}
En nyckel kan ha flera värden¶
- Men vi måste i så fall explicit representera det med ett värde som är en samling, t.ex. en lista:
In [21]:
hcs_surnames = {"Erik": ["Prytz", "Berglund"]}
print(hcs_surnames)
{'Erik': ['Prytz', 'Berglund']}
Nycklar måste vara hashningsbara¶
- Bara vissa datatyper kan användas som nycklar, de som är hashningsbara.
- Vi kan tänka på hashningsbar som ekvivalent med oföränderlig för tillfället.
- Dvs. det går bra att ha nycklar som är
int,tuple,strmen inte nycklar som ärlist, eller för den delendict.
- Dvs. det går bra att ha nycklar som är
- Alla datatyper kan dock användas som värden.
- Vi kan också blanda olika datatyper som både nycklar och värden i sammma
dict:
In [22]:
dict_example = {"name": "Cantor", 345: "integer", 3: 54, (4,9): ['occupied', 'working', 'forbidden']}
- (Men det blir ofta svårt att reda ut vad i hela fridens namn datan egentligen representerar när vi blandar friskt.)
Iterera över en dict¶
- Metoderna
dict.keys(),dict.values()ochdict.items()returnerar olika vyer (eng. views). - Vyer tillåter att vi itererar över
- nycklar:
dict.keys() - värden:
dict.values() - nyckel-värde-par som tupler med 2 element:
dict.items() - ("
dict" refererar här till ett värde av typen dictionary, denna konvention, att låta datatypens namn stå för ett godtyckligt värde av typen, används även i pythondokumentationen)
- nycklar:
- Vi kan dock inte använda index eller slice på en vy, och vyer kan inte användas för att ändra i den
dictden är kopplad till.
OBS! Iterera inte i onödan!¶
- T.ex. behöver vi aldrig iterera för att kontrollera om en nyckel finns i en
dict(my_key in my_dict) eller för att slå upp värdet associerat med en känd nyckel (my_dict[my_key]). - Många lurar sig att de måste hålla på och loopa och leta i
dict:ar eftersom de just lärt sig att iterera. - I många fall är poängen med
dictatt slippa att iterera eller leta manuellt.
Iterera över nycklar¶
In [23]:
birth_years = {"Newton": 1643, "al-Khwarizmi": 780, "Gauss": 1777, "Turing": 1912}
for name in birth_years.keys():
print(name)
Newton al-Khwarizmi Gauss Turing
Iterera över värden¶
In [24]:
birth_years = {"Newton": 1643, "al-Khwarizmi": 780, "Gauss": 1777, "Turing": 1912}
for year in birth_years.values():
print(year)
1643 780 1777 1912
Om vi vill ha både nycklar och värden då?
- Dåligt sätt:
In [25]:
birth_years = {"Newton": 1643, "al-Khwarizmi": 780, "Gauss": 1777, "Turing": 1912}
for name in birth_years.keys():
print(name, "was born in", birth_years[name])
Newton was born in 1643 al-Khwarizmi was born in 780 Gauss was born in 1777 Turing was born in 1912
Om vi vill ha både nycklar och värden då?
- Bättre sätt:
In [26]:
birth_years = {"Newton": 1643, "al-Khwarizmi": 780, "Gauss": 1777, "Turing": 1912}
for pair in birth_years.items():
print(pair)
('Newton', 1643)
('al-Khwarizmi', 780)
('Gauss', 1777)
('Turing', 1912)
In [27]:
# Med tuple assignment av 2 loopvariabler i for-loopen:
for name, year in birth_years.items():
print(name, "was born in", year)
Newton was born in 1643 al-Khwarizmi was born in 780 Gauss was born in 1777 Turing was born in 1912
Sammansatta datastrukturer¶
Fram tills nu¶
- Oftast en variabel för varje värde:
In [28]:
pokemon_name = "Pidgey"
ability1 = "big-pecks"
ability2 = "tangled-feet"
ability3 = "keen-eye"
- Hur gör vi om vi vill ha information om fler eller färre "abilities" på ett smidigt sätt?
Lista för relaterade data¶
- Vi har sett att listor kan användas att representera data som kan innehålla fler än ett värde, t.ex.
In [29]:
# Before:
pokemon_name = "Pidgey"
ability1 = "big-pecks"
ability2 = "tangled-feet"
ability3 = "keen-eye"
# After:
pokemon_name = "Pidgey"
abilities = ["big-pecks", "tangled-feet", "keen-eye"]
- Men hur gör vi om vi vill ha information om flera Pokémon? Ska vi ha
pokemon_name1,pokemon_name2,abilities1,abilities2?
Listor i listor¶
- En lista kan själv vara ett element i en annan lista.
- Vi kallar detta för nästling, en inre lista nästlad inne i en yttre lista.
- Detta är en typ av rekursiv datastruktur.
- Vi kan samla ihop informationen om varje Pokémon till en lista samt bestämma den ordning som informationen ska komma i.
- Första elementet kan vara namnet och andra elementet den tillhörande listan med "abilities".
In [30]:
# Before:
pokemon_name = "Pidgey"
abilities = ["big-pecks", "tangled-feet", "keen-eye"]
# After:
pokemon1 = ["Pidgey", ["big-pecks", "tangled-feet", "keen-eye"]]
pokemon2 = ["Ditto", ["imposter", "limber"]]
- Men hur gör vi om vi inte vet exakt hur många Pokémon vi kommer behöva lagra data om? Vi kan ju inte skapa hundratals variabler som heter
pokemonNför godtyckligt stora värden påN.
Samma princip igen¶
- Vi kan också samla ihop alla Pokémon-listor i en lista.
- Nu kan vi helt enkelt lägga till nya listor i vår lista.
In [31]:
# Before:
pokemon1 = ["Pidgey", ["big-pecks", "tangled-feet", "keen-eye"]]
pokemon2 = ["Ditto", ["imposter", "limber"]]
# After:
pokemon = [["Pidgey", ["big-pecks", "tangled-feet", "keen-eye"]], ["Ditto", ["imposter", "limber"]]]
Göra nästlade listor mer överskådliga¶
- Vi kan använda radbrytningar och indentering för att visualisera strukturen hos en nästlad lista:
In [32]:
# Before:
pokemon = [["Pidgey", ["big-pecks", "tangled-feet", "keen-eye"]], ["Ditto", ["imposter", "limber"]]]
# After:
pokemon = [
[
"Pidgey",
["big-pecks", "tangled-feet", "keen-eye"]
],
[
"Ditto",
["imposter", "limber"]
]
]
- Men hur ska vi veta vad som är vad. Om du är bekant med Pokémon kanske du vet att
"pidgey"är ett namn och känner igen olika typer av "abilities", men för oss andra då?
Vår nya datatyp till räddning¶
- Vi ersätter listan för varje Pokémon med en
dictmed beskrivande namn på nycklarna:
In [33]:
# Before:
pokemon = [
[
"Pidgey",
["big-pecks", "tangled-feet", "keen-eye"]
],
[
"Ditto",
["imposter", "limber"]
]
]
# After:
pokemon = [
{
"name": "Pidgey",
"abilities": ["big-pecks", "tangled-feet", "keen-eye"]
},
{
"name": "Ditto",
"abilities": ["imposter", "limber"]
}
]
- Nu måste vi dock loopa för att hitta data om en viss Pokémon, det hade ju varit bättre om vi kunde slå upp dem direkt.
Vi tillämpar åter samma princip igen¶
- Men med
dictistället. - Vi kan använda själva namnen som nycklar också.
In [34]:
# Before:
pokemon = [
{
"name": "Pidgey",
"abilities": ["big-pecks", "tangled-feet", "keen-eye"]
},
{
"name": "Ditto",
"abilities": ["imposter", "limber"]
}
]
# After:
pokemon = {
"pidgey": {
"name": "Pidgey",
"abilities": ["big-pecks", "tangled-feet", "keen-eye"]
},
"ditto": {
"name": "Ditto",
"abilities": ["imposter", "limber"]
}
}
JSON¶
- JSON, eller JavaScript Object Notation är ett dataformat som speglar nästan exakt nästlade
dict:ar och listor i Python. - Modulen
jsonkan läsa in en fil i JSON-format och representera den just som nästladedict:ar och listor. - Svaret vi får från ett Webb-API kommer väldigt ofta i just JSON-format.
- https://www.json.org/json-sv.html
JSON: Exempel¶
- Konfigurationsfil för Pythonuppgifterna
{
"excluded_shortcodes": [],
"excluded_misc": [],
"pytest_config": {
"VENV_PATH": "/courses/TDDE44/venv_pytest",
"HELP_URL": "https://www.ida.liu.se/~TDDE44/kurslogistik/inlamningar/"
},
"assignment_sets": {
"intro": {
"name": "Introduktion",
"shortname": "Introduktion",
"outcomes": [
"Förstå vad funktioner är och hur de används.",
"Förstå vad ett returvärde är.",
"Känna till olika datatyper så som till exempel heltal, flyttal och strängar och veta hur man konverterar mellan dem.",
"Kunna använda python som en miniräknare."
],
"pass_score": 0.7,
"distinction_score": 0.7,
"point_rounding": 5,
"assignments": [
{
"type": "single",
"id": "basic/return_five",
"points": 5
},
{
"type": "single",
"id": "basic/five_twice",
"points": 5
},
...
JSON: Exempel¶
- Tentakonfiguration
{
"id": "TDDE44-DAT1-20260107",
"version": "1.3",
"config-type": "single",
"instructions": "TDDE44_v10.md",
"title": "TDDE44. DAT1. 2hp.",
"date": "2026-01-07 kl. 14.00-18.00",
"templates": {
"exam": "exam_template.md",
"part": "part_template.md",
"single_question": "single_question_template_manual_points.md",
"multi_question": "multi_question_template_manual_points.md",
"subquestion": "subquestion_template_manual_points.md",
"web_solution_exam": "hugo_web_solution_template.md",
"web_solution_part": "part_template.md",
"web_solution_single_question": "single_question_template_web_with_solution.md",
"web_solution_multi_question": "multi_question_template_web_with_solution.md",
"web_solution_subquestion": "subquestion_template_web_with_solution.md"
},
"pagebreak_after_question": true,
"unittests": "question",
"parts": [
{
"name": "Del 1",
"id": "del1",
"info": "För att bli godkänd på Del 1 måste alla uppgifter vara godkända.",
"questions": [
{
"name": "Uppgift 1 - Loopar",
"id": "uppg1",
"type": "multi",
"points": "",
"info": "- För att få godkänt på denna uppgift skall __båda__ deluppgifterna lösas.\n- En av uppgifterna skall lösas med en `while`-loop och en skall lösas med `for`-loop.\n- Comprehensions, generatorer eller rekursion får *inte* användas för att lösa uppgifterna.\n- Spara lösningarna till båda deluppgifterna i Uppgift 1 i en fil med namnet `uppg1.py`.\n- Filen skickas in via Studentklienten som '*Assignment #1*'.",
"required_score": 4,
"global_tests": [
{
"name": "Uppgift 1 - en med for, en med while",
"id": "test1",
"points": "2",
"file": "for_while"
}
],
"subquestions": [
{
"name": "Uppgift 1.1 - lös med lämplig loop",
"id": "uppg11",
"type": "single",
"points": "",
"folder": "listor",
"file": "get_repeated"
},
{
"type": "pagebreak"
},
{
"name": "Uppgift 1.2 - lös med lämplig loop",
"id": "uppg12",
"type": "single",
"points": "",
"folder": "loopar",
"file": "multiply_until_inc"
}
]
},
...