← Python/Verzamelen en veranderen
Les 8 van 8
MODULE 04 · 08◷ 30 min

Beheer taken met duidelijke mutatieregels

Na deze les kun je
  • Een lijst met taakdictionaries bijhouden
  • Muterende en niet-muterende functies scheiden
  • Kopieën op het benodigde niveau maken

Een takenoverzicht moet soms veranderen en soms alleen een overzicht geven. Als het tonen van open taken per ongeluk ook je oorspronkelijke lijst verandert, wordt het programma moeilijk te vertrouwen. Duidelijke afspraken over lezen, wijzigen en kopiëren voorkomen zulke verrassingen.

Eén lijst, meerdere records

Een taak is in deze oefening een dictionary met twee velden: title bevat tekst en done een boolean. De buitenste lijst bepaalt de volgorde van de taken. Je combineert daarmee precies de collecties die je in de vorige lessen hebt leren gebruiken.

De mutatieafspraak van een functie vertelt of zij bestaande gegevens mag veranderen. Een functie die een taak toevoegt of afrondt mag dat hier wel. Een functie die alleen open titels opzoekt mag de bron juist niet aanpassen.

Kies die afspraak voordat je gaat programmeren. Kijk daarna apart naar de retourwaarde: een wijziging kan None teruggeven, terwijl een leesfunctie een nieuwe lijst oplevert. Het type van het antwoord zegt op zichzelf nog niet of de bron is gewijzigd.

Een bevestiging en een los overzicht

Het zelfstandige voorbeeld gebruikt geplande bezoeken. Een bezoek bevestigen verandert bewust het bestaande record; het maken van een overzicht levert juist losse recordkopieën op. Druk op Voorbeeld uitvoeren en vergelijk de oorspronkelijke plaatsnaam met de aangepaste naam in het overzicht.

Een bezoek bevestigen en een los overzicht maken
def confirm_visit(visits, index):
    visits[index]["confirmed"] = True

visits = [
    {"place": "museum", "confirmed": False},
    {"place": "park", "confirmed": True},
]
confirm_visit(visits, 0)
print(visits[0]["confirmed"])
confirm_visit(visits, 0)
print(visits[0]["confirmed"])
summary = [visit.copy() for visit in visits if visit["confirmed"]]
summary[0]["place"] = "tuin"
print(visits[0]["place"])
print(summary[0]["place"])
print(len(summary))
Verwachte uitvoer
True
True
museum
tuin
2

De bevestigingsfunctie wordt tweemaal voor hetzelfde bezoek aangeroepen. Na beide aanroepen blijft confirmed True. Dit is dezelfde eigenschap die je bij het toevoegen aan een set zag: herhalen hoeft geen nieuwe verandering te veroorzaken.

Bij het overzicht maakt de comprehension een nieuwe buitenste lijst. copy op iedere dictionary maakt bovendien een nieuwe dictionary met dezelfde velden. Daardoor schrijft de aangepaste plaatsnaam niet terug naar het oorspronkelijke bezoek.

visits  ──► lijst A ──► record A: plaats museum
summary ──► lijst B ──► record B: plaats tuin

De veldwaarden zijn hier tekst en booleans. Die veranderen niet van binnenuit, zodat een oppervlakkige dictionarykopie voldoende is. Bij een veld dat zelf een veranderbare lijst bevat, zou je opnieuw moeten bepalen of ook die lijst een kopie nodig heeft.

Veelgemaakte fout: alleen de buitenste lijst vernieuwen

Een filter maakt wel een nieuwe lijst, maar kopieert haar elementen niet vanzelf. Deze zelfstandige foutvariant verzamelt de oorspronkelijke records in een nieuw overzicht. Daarna krijgt één record via dat overzicht een andere naam.

Het overzicht deelt nog hetzelfde bezoekrecord
visits = [{"place": "museum", "confirmed": True}]
summary = [visit for visit in visits if visit["confirmed"]]
summary[0]["place"] = "tuin"
print(visits[0]["place"])
print(summary is visits)
print(summary[0] is visits[0])
Verwachte uitvoer
tuin
False
True

Ook de plaatsnaam in de bron wordt tuin. De nieuwe buitenste lijst was dus echt nieuw, maar wees nog naar dezelfde dictionary. Het probleem is hetzelfde kopieerniveau als bij gedeelde rijen, nu met dictionaries als binnenste objecten.

Kopieer daarom ieder behouden record wanneer wijzigingen in het resultaat niet mogen terugwerken. Een andere variabelenaam of een nieuwe buitenste lijst is daarvoor onvoldoende. Controleer bij een test ook wat er na een wijziging aan het resultaat met de bron gebeurt.

De afspraken voor jouw takenlijst

De vier opdrachten hebben bewust verschillende effecten. Een nieuwe taak begint open, dus met done=False. De titel komt uit de invoer; gelijke titels mogen voorkomen en deze oefening gebruikt nog geen taak-ID's.

FunctieMag de bron veranderen?Antwoord
add_taskJa: achteraan een nieuw taakrecordNone
finish_taskJa: de gekozen taak wordt voltooidNone
open_titlesNeeNieuwe lijst met open titels
prune_doneNeeNieuwe lijst met kopieën van open taakrecords

De index voor afronden is geldig. Zet de toestand op True; wissel haar niet om met not, want dan zou tweemaal afronden de taak weer openen. Alleen done bepaalt of een taak klaar is, niet haar titel.

Bij beide leesfuncties blijft de bestaande volgorde behouden. Een lege bron of een bron met uitsluitend voltooide taken levert een lege lijst op. Ook dan moet de oorspronkelijke bron intact blijven.

AAN DE SLAG 0/4
1

Voeg een open taak toe

Laat add_task een nieuwe taak met done=False toevoegen en None teruggeven.

2

Rond af zonder terug te schakelen

Laat finish_task dezelfde taak blijvend op done=True zetten.

3

Lees alleen open titels

Laat open_titles titels van niet-voltooide taken in dezelfde volgorde teruggeven.

4

Kopieer wat overblijft

Laat prune_done alleen open taken kopiëren, zonder de oorspronkelijke lijst of dictionaries te wijzigen.

Wat je meeneemt

  • Leg per functie vast of zij leest, wijzigt of een los resultaat teruggeeft.
  • Herhaald afronden houdt een taak voltooid; het is geen aan-uitschakelaar.
  • Een los overzicht vraagt nieuwe records als wijzigingen daaraan niet naar de bron mogen terugwerken.

Je kunt nu gegevens combineren en bewust veranderen. Deze transferles oefent het model; later bouw je een zelfstandig project met meerdere bestanden en mijlpalen, en de volgende inhoudsmodule verdiept tekstbewerking.

main.py
UitvoerPython
›
›_

Hier komt je resultaat.

Voer je code uit en ontdek
wat je hebt gemaakt.

0/4 stappen
EVEN MEEKIJKEN

Bekijk hoe het kan.

Je mag de oplossing bekijken. Deze poging telt dan niet mee als afgeronde les. Met Reset kun je daarna opnieuw zelf oefenen.