Iteration as an Interface · capstone
Capstone project: Project: Build an Iterable Question Bank
Earlier projects handed out
What you are building
A QuestionBank that holds questions and answers three kinds of request:
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
The first is __iter__. The second and third are generators. None of them builds a list unless a list is what the caller asked for.
The decisions
__iter__ skips ungraded questions. A bank holds survey items too, and looping over the bank means looping over the questions that count. That is a real decision, and it is the reason __iter__ is a generator here rather than the one-line delegation from Lesson 4.
by_topic returns a generator, and says so. A caller may want the first match and nothing else, and this is the shape that lets them stop.
sample has an exact boundary. Asking for two questions yields and consumes two, not three. A zero or negative count does not start walking the bank.
summary returns a list. It is short, the caller will
Why is __iter__ written as a generator here rather than return iter(self._questions)?
Rules the grader checks
The bank is re-
: looping twice sees everything twice. by_topicandsampleare generator, not functions returning lists. sampleworks on an endless source, so it must stop on its own.sampledoes not consume a question beyond the requested count.first_unansweredexamines no more questions than it needs to.points_neededreturns0for a target that is already reached at the start.summaryreturns a list.
Finishing
Read your QuestionBank and ask, for each method, what a caller can do with what it returns. One of them gives back something you can measure and index; the rest give back something you can walk once and stop early. Both are right answers, to different questions.
Task
Build the QuestionBank and the two
add(question) stores a question. __iter__ is a generator yielding every question worth more than zero points, in order, skipping the ungraded ones.
by_topic(topic) is a generator yielding the graded questions whose topic matches. sample(count) is a generator yielding at most count graded questions. It requests no more graded questions from the bank’s
total_points is a read-only property summing the graded questions, computed with a generator
summary() returns a list of "<prompt> (<points>)"
Then two functions that take any
first_unanswered(questions, answered)returns the first question whose prompt is not inanswered, orNone. It must stop as soon as it finds one.points_needed(questions, target)returns how many questions, taken in order, are needed before their points reachtarget, orNoneif they never do. Return0whentarget <= 0, because that target is reached before consuming a question.