Chapter 6 · practice
Objects Working Together
Pass One Object to Another
One line from the last chapter is worth looking at again:
attempt.record(question, response)
An Attempt receives a whole Question. It could have been written to receive the pieces instead:
attempt.record(question.prompt, question.answer, question.points, response)
Both work. The difference between them is the subject of this chapter, and it decides how much of your program has to change when something small changes.
Taking an object apart at the door
Here is a report_line
Read the call. Every caller has to know that a question has exactly these three parts, in this order, and has to pull them out by hand. Then look at the body: correct = response == answer recreates the rule that Question.is_correct already owns.
Now suppose questions gain a case_sensitive option. This function’s signature changes, every call site changes, and the comparison rule has to be updated here as well as in Question. The function never asked for that job.
Passing the whole thing
Same output. The call is now report_line(question, "3"), which reads like what it means, and the comparison rule is asked for rather than reproduced. Add case_sensitive to Question now and this function needs no change at all, because it never knew how correctness was decided.
A question gains a new attribute, and is_correct starts using it. Which version of report_line has to change?
The signal to watch for
There is a name for the smell in the first version: a long
You can spot it at the call site, without reading the function at all:
summarize(attempt.learner, attempt.score, attempt.response_count)
Three arguments, one source. That call is quietly asking for an Attempt.
When the pieces are the right answer
Do not turn this into a rule that functions must always receive objects. A function that genuinely works on one
def shorten(text, limit):
...
shorten has no business receiving a Question. It works on text, and passing it a question would make it useless for every other
The exercise has a function with the first shape. Give it the second.
Task
Both
Rewrite describe_result to take (question, response), and summarize_attempt to take (attempt). Ask each object for what you need instead of receiving its parts, and use the
Update the two calls at the bottom to match. The printed output must not change: the point of the exercise is that the interface improved while the behavior stayed put.