0%

Representing and Comparing Objects · capstone

Capstone project: Project: Make Quiz Objects Clear and Comparable

This chapter gave you five and, more usefully, a set of rules about when each one belongs. The project is mostly an exercise in restraint: three of the four classes should end up with fewer methods than you might be tempted to give them.

The decisions

ClassWhat it isGets
PointsA read-only with a natural order__repr__, __eq__, __hash__, __lt__
QuestionA read-only value with no natural order__repr__, __str__, __eq__, __hash__
ResponseA value, seen only by developers__repr__, __eq__
QuizAttemptAn 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 was still present.

Response gets __eq__ but no __hash__. Its question and given text do not change, but a response is never used as a or put in a set, and adding 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 listed in the lesson’s table. Keep the supplied public operations working; small helper methods are welcome.

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 to sort, since neither decision belongs inside Question.

Every __eq__ must return NotImplemented for a different type.