Iteratie als interface · eindproject
Eindproject: Project: bouw een itereerbare vragenbank
Eerdere projecten gaven lijstkopieën als momentopnamen terug via benoemde methoden. Dit project combineert het iteratieprotocol uit de afgelopen lessen met lui filteren en begrensd verbruik.
Wat je bouwt
Een QuestionBank die vragen bewaart en drie soorten verzoeken beantwoordt:
for question in bank every graded question, in order
bank.by_topic("loops") a lazy view, filtered
bank.sample(3) at most three, from any source
De eerste is __iter__. De tweede en derde zijn generators. Geen ervan bouwt een lijst tenzij de aanroeper om een lijst vroeg.
De beslissingen
__iter__ slaat onbeoordeelde vragen over. Een bank bevat ook enquête-items en over de bank itereren betekent over de vragen itereren die meetellen. Dat is een echte beslissing en daarom is __iter__ hier een generator in plaats van de delegatie van één regel uit les 4.
by_topic geeft een generator terug en zegt dat ook. Een aanroeper wil misschien de eerste overeenkomst en verder niets, en deze vorm laat die stoppen.
sample heeft een exacte grens. Om twee vragen vragen levert twee op en verbruikt er twee, geen drie. Een aantal van nul of lager begint niet met het doorlopen van de bank.
summary geeft een lijst terug. Die is kort, de aanroeper zal die indexeren en de lengte opvragen, en een generator zou slechter zijn zonder voordeel. De regel uit les 6, toegepast.
Waarom is __iter__ hier als generator geschreven in plaats van als return iter(self._questions)?
Regels die de beoordelaar controleert
De bank is opnieuw doorloopbaar: twee keer itereren ziet alles twee keer.
by_topicensamplezijn generatorfuncties, geen functies die lijsten teruggeven.samplewerkt op een eindeloze bron en moet dus zelf stoppen.sampleverbruikt geen vraag voorbij het gevraagde aantal.first_unansweredonderzoekt niet meer vragen dan nodig.points_neededgeeft0terug voor een doel dat bij het begin al is bereikt.summarygeeft een lijst terug.
Afronden
Lees je QuestionBank en vraag je bij elke methode af wat een aanroeper kan doen met wat die teruggeeft. Eén methode geeft iets terug waarvan je de lengte kunt opvragen en dat je kunt indexeren; de rest geeft iets terug dat je één keer kunt doorlopen en waarbij je vroeg kunt stoppen. Beide zijn juiste antwoorden op verschillende vragen.
Opdracht
Bouw de QuestionBank en de twee functies die die gebruiken.
add(question) bewaart een vraag. __iter__ is een generator die elke vraag van meer dan nul punten op volgorde oplevert en de onbeoordeelde vragen overslaat.
by_topic(topic) is een generator die de beoordeelde vragen oplevert waarvan het onderwerp overeenkomt. sample(count) is een generator die maximaal count beoordeelde vragen oplevert. Die vraagt niet meer beoordeelde vragen aan de iterator van de bank dan die oplevert; om ze te vinden kan die nog steeds onbeoordeelde opgeslagen vragen inspecteren. Een aantal van nul of lager verbruikt niets.
total_points is een alleen-lezen property die de beoordeelde vragen optelt, berekend met een generatorexpressie in plaats van een lijst.
summary() geeft een lijst met strings "<prompt> (<points>)" terug, omdat de aanroeper de lengte opvraagt en de lijst indexeert.
Daarna twee functies die elke iterable met vragen ontvangen, niet alleen een bank:
first_unanswered(questions, answered)geeft de eerste vraag terug waarvan de vraagtekst niet inansweredstaat, ofNone. Die moet stoppen zodra er een is gevonden.points_needed(questions, target)geeft terug hoeveel vragen, op volgorde genomen, nodig zijn voordat hun puntentargetbereiken, ofNoneals dat nooit gebeurt. Geef0terug alstarget <= 0, omdat dat doel al is bereikt voordat een vraag wordt verbruikt.