Plan, Build, and Test Programs · practice
Refactor with a Safety Net
Refactoring works best when one structural change has a clear purpose. Here, that change is to replace repeated
Build one string from a list of strings
Start with three separate strings in a list:
The result is one string:
plan -> build -> test
The method call " -> ".join(stages) uses two parts you already know. " -> " is the separator string, and stages is a list whose items are strings. The .join() method returns one new string with the separator between each neighboring pair. It does not add the separator before the first item or after the last one.
The separator appears before the dot because .join() is a string method. The list supplies the strings to combine. Writing stages.join(" -> ") reverses those jobs, and a list does not provide .join().
Every item supplied to .join() must be a string. If a report includes a number, build that complete line with an
score = 2
lines = ["QUIZ REPORT", f"Score: {score}/3"]
Predict where the separator goes
Before you run this example, predict the exact output. How many lines will it print, and why will there be no empty line at the beginning or end?
The list contains three strings, so .join() places two newline separators between them. The brackets, commas, and quotes belong to the list representation. They do not appear in the returned string.
Make .join() the refactoring move
The starter’s quiz_report() already returns the promised three-line report. It builds that report by concatenating one line at a time:
report = "QUIZ REPORT"
report = report + f"\nAnswered: {len(responses)}"
report = report + f"\nScore: {score}/{len(responses)}"
return report
Refactor those lines into a list of complete strings, then join them with "\n":
lines = [
"QUIZ REPORT",
f"Answered: {len(responses)}",
f"Score: {score}/{len(responses)}",
]
return "\n".join(lines)
This separates two jobs. The list records what each report line says, and .join() records what belongs between the lines.
Refactoring changes the structure of working code without deliberately changing its behavior. Keep the existing assertions, make this one structural change, and run the checks again. If they still pass for the prepared and empty response lists, you have evidence that the refactor preserved the report.
Which expression returns one string with each item from lines on its own line?
Task
The starter quiz_report(responses) already produces the required report. Refactor only the way it assembles that report:
Keep the scoring
and its call to answers_match()unchanged.After the loop, create a
containing the three complete report lines: QUIZ REPORT, the answered count, and the score.Return one
by using "\n".join(...)with that list of strings.Keep both prepared behavior assertions and rerun them after the refactor.
Keep the
QUIZ REPORT
Answered: 3
Score: 2/3