Van werkende code naar programmaontwerp · oefening
Houd vraaggegevens bij elkaar
De vorige les zette de vraagtekst, het antwoord en de punten van elke vraag in één dictionary:
question = {
"prompt": "Which keyword starts a function?",
"answer": "def",
"points": 2,
}
Dat houdt de samenhangende waarden bij elkaar. Maar een andere functie kan ze per ongeluk weer uit elkaar halen.
De vraag bij elke aanroep uit elkaar halen
Stel dat score_attempt het antwoord en de punten als afzonderlijke argumenten ontvangt:
def score_attempt(
answer,
response,
points,
):
...
Bij het aanroepen zijn meerdere zoekopdrachten in dezelfde dictionary nodig:
score_attempt(
question["answer"],
" DEF ",
question["points"],
)
Stel je nu een quiz met meerdere vragen voor. Hetzelfde patroon verschijnt elke keer:
first_score = score_attempt(
first_question["answer"],
first_response,
first_question["points"],
)
second_score = score_attempt(
second_question["answer"],
second_response,
second_question["points"],
)
Elke aanroep haalt één vraag uit elkaar en geeft de delen afzonderlijk door.
Wat gebeurt er wanneer er een regel bijkomt?
Stel dat hoofdletters en kleine letters bij sommige antwoorden nu precies moeten overeenkomen. We voegen aan elke vraag een waarde case_sensitive toe:
question = {
"prompt": "Which keyword starts a function?",
"answer": "def",
"points": 2,
"case_sensitive": False,
}
Die ene nieuwe regel veroorzaakt meerdere wijzigingen:
Voeg
case_sensitivetoe aan elke vraagdictionary.Voeg nog een parameter toe aan
score_attempt.Werk elke plek bij die
score_attemptaanroept.Zorg dat elke aanroep de nieuwe waarde op de juiste positie doorgeeft.
Al die wijzigingen moeten op elkaar aansluiten. Als je er maar één mist, kan dat een fout of een verkeerd resultaat opleveren.
Geef de volledige vraag door
Het antwoord, de punten en de hoofdletterregel beschrijven allemaal dezelfde vraag. We kunnen die vraag rechtstreeks doorgeven:
def score_attempt(question, response):
...
De aanroepen worden:
first_score = score_attempt(first_question, first_response)
second_score = score_attempt(second_question, second_response)
Als de vraag later nog een scoreregel krijgt, kan score_attempt die uit de dictionary lezen. De aanroepen geven de volledige vraag al door en hoeven daardoor misschien niet te veranderen.
Probeer hetzelfde idee in dit kleinere voorbeeld:
Voeg nog een sleutel toe aan question en voer het voorbeeld opnieuw uit. De aanroep question_label(question) geeft nog steeds één volledige vraag door.
Dit is geen regel dat elke functie een dictionary moet ontvangen. Afzonderlijke waarden zijn nog steeds passend wanneer ze afzonderlijke ideeën vertegenwoordigen. Hier horen meerdere waarden al bij één vraag en heeft de functie er meer dan één nodig.
De functies hebben nu gerichte verantwoordelijkheden: de beloften die elk deel van het programma beheert. response_matches beheert de vergelijkingsregel. score_attempt beheert de beslissing om de punten van deze vraag of nul toe te kennen. De volledige vraag doorgeven laat elke functie haar eigen taak uitvoeren zonder elke aanroeper de velden te laten afstemmen.
Waarom kan score_attempt(question, response) later makkelijker te veranderen zijn?
De oefening houdt de vergelijkingscode zichtbaar en compleet. Je taak is alleen score_attempt de volledige vraag te laten gebruiken en het juiste aantal punten te laten teruggeven.
Opdracht
Maak score_attempt(question, response) af.
De meegeleverde functie response_matches volgt de regel case_sensitive van de vraag al.
Roep
response_matchesaan met de volledige vraag en het ingevoerde antwoord.Geef
question["points"]terug als die functieTrueteruggeeft.Geef anders
0terug.
Haal de vraag niet uit elkaar in extra parameters.