0%

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 concatenation with a of finished lines and one string .

Build one string from a list of strings

Start with three separate strings in a list:

Try it

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 before putting it in the list:

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?

Try it

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:

  1. Keep the scoring and its call to answers_match() unchanged.

  2. After the loop, create a containing the three complete report lines: QUIZ REPORT, the answered count, and the score.

  3. Return one by using "\n".join(...) with that list of strings.

  4. Keep both prepared behavior assertions and rerun them after the refactor.

Keep the names, prepared data, and final print. The output must remain:

QUIZ REPORT
Answered: 3
Score: 2/3