Representing and Comparing Objects · capstone
Capstone project: Project: Make Quiz Objects Clear and Comparable
This chapter gave you five
The decisions
| Class | What it is | Gets |
|---|---|---|
Points | A read-only | __repr__, __eq__, __hash__, __lt__ |
Question | A read-only value with no natural order | __repr__, __str__, __eq__, __hash__ |
Response | A value, seen only by developers | __repr__, __eq__ |
QuizAttempt | An event with its own identity | __repr__, __str__ |
Two of these are worth pausing on.
Points and Question keep every attribute used by their hashes read-only. If one of those values could change after entering a set, lookup could fail even though the
Response gets __eq__ but no __hash__. Its question and given text do not change, but a response is never used as a __hash__ that nothing needs is a promise to keep it correct forever in exchange for nothing.
QuizAttempt defines neither __eq__ nor __hash__, so it keeps Python’s default identity equality and identity-based hash. Two attempts by the same learner with the same score are separate events. Their responses may change without changing that identity or hash; a hash based on those changing contents would be unsafe.
Why would giving QuizAttempt a content-based __eq__ be a mistake here?
What the program does
The driver builds a small question bank containing one duplicate, removes the duplicate with a set, sorts what remains by points, runs one attempt, and prints a report. Every step leans on something from this chapter, and none of it works with the default behavior Python gives a new class.
Finishing
Read your finished classes and check each method against one question: what would break if this were deleted? If nothing would, delete it. __hash__ on a class that is never a key, __str__ that only repeats the repr, and __lt__ on something with no obvious order are all code that has to be maintained and gives nothing back.
Finally add one duplicate and one new question of your own to the bank. The printed result should make the duplicate disappear, keep the new question in point order, and remain readable without revealing either answer.
Task
Add the special
Points: read-only amount; repr Points(3); equal, hashable, and ordered by amount.
Question: read-only prompt, answer, and points; repr Question('...', '...', Points(2)); str <prompt> (2 points), which must not reveal the answer; equal and hashable over prompt, answer, and points.
Response: read-only question, given text, correctness, available points, and earned snapshots; repr Response(given='3', earned=2); equal over its question and given text. No __hash__.
QuizAttempt: summary repr QuizAttempt(learner='Mina', response_count=2); str Mina: 4 points. No __eq__ and no __hash__ override: keep the inherited identity behavior.
Then write unique_sorted(questions), returning the distinct questions ordered cheapest first. Use a set to remove duplicates and a key Question.
Every __eq__ must return NotImplemented for a different type.