Building from Pieces

Recap and Feedback


In this part, you learned to give pieces of behavior names, pass information into functions, return results, reason about local state, validate user input, and test calculation logic independently from the rest of a program.

The central design questions are now:

What is this function responsible for? What information does it need? What should it return or change? How can I check that behavior?

The Dice Combos example added one more question:

Can a larger rule use the result of a smaller function?

Putting the Ideas Together: Reading Tracker

The final programming exercise combines the ideas from this part in a small reading tracker. Read its handout for the function contracts, accepted input, and required output.

The program separates its work into three layers:

read_sessions()
↓ sessions
calculation functions
↓ returned results
print_summary(...)

main() connects these steps. The input function asks for session lengths and handles invalid input. The calculation functions receive the collected list, return their results, and leave the list unchanged. The presentation function displays the summary. You can test the calculations separately by calling them with lists you choose.

Suggested Workflow

Build and check one layer at a time:

  1. Read every function contract and identify its parameters, return value or output, empty case, and allowed effects.
  2. Implement the calculation functions first. Test ordinary, boundary, one-item, and empty cases, and check that the input list remains unchanged.
  3. Implement and check the presentation function using known result values.
  4. Implement the input function. Keep sentinel recognition, integer conversion, and positive-number validation as separate decisions, and test recovery from several invalid attempts.
  5. Connect the functions in main() only after the individual responsibilities work.
  6. Run complete examples, including stopping immediately and entering invalid input before valid input.

This order makes a failure easier to locate: first establish that each part satisfies its contract, and only then test the connections among the parts.

Reading tracker

0 / 40 points

Complete a reading tracker whose input, calculations, and presentation are divided into functions.

Implement the five functions and the coordinating main() function in the starter. Keep the provided import guard so that the calculation functions can be imported for testing without starting the interactive program.

read_sessions() takes no arguments. Use while True for the input process because the number of attempts is not known in advance. Repeatedly ask with the prompt Minutes, or done: . Ignore surrounding whitespace. Any capitalization of done, such as DONE or Done, stops input before conversion and is not stored; use break for this sentinel. Otherwise, use int(...) to convert the text and accept only integers greater than zero.

Keep the try block focused on integer conversion and check whether the converted value is positive separately. This makes it clear which operation may fail and which values the program accepts.

If conversion raises ValueError, or if the integer is zero or negative, print exactly:

Please enter a positive integer or done.

After either kind of invalid response, ask again without storing it. You can use continue to begin the next attempt. Return a list containing only the accepted positive integers. Catch ValueError specifically so that unrelated errors are not treated as invalid input.

The calculation functions must return their results, print nothing, and leave sessions unchanged:

  • total_minutes(sessions) returns the total, or 0 for an empty list.
  • longest_session(sessions) returns the largest value, or 0 for an empty list.
  • count_long_sessions(sessions, minimum_minutes) returns how many values are greater than or equal to the supplied boundary, or 0 for an empty list. Use the parameter rather than hard-coding 30 inside this function.

print_summary(session_count, total, longest, long_count) prints exactly four lines. For a nonempty session list, the format is:

Sessions: 3
Total minutes: 80
Longest session: 45
Long sessions: 1

If session_count is 0, print Longest session: none on the third line. The other empty results are numeric zero.

Finally, main() must call read_sessions, calculate all three results with the calculation functions, use 30 as the long-session boundary, and pass the session count and results to print_summary.

For example, the responses 20, 45, 15, and done produce the four-line nonempty summary above. Entering done immediately produces:

Sessions: 0
Total minutes: 0
Longest session: none
Long sessions: 0

Test immediate stopping, sentinel capitalization and whitespace, invalid text followed by valid input, zero and negative input, a one-item list, a session exactly at 30 minutes, an empty list, and a longest value that is not first.

Explain the Design

When the program works, step back from its individual lines and explain why its responsibilities are separated. The following exercise asks you to connect specific input, calculation, testing, and empty-case decisions to the program’s behavior. Being able to explain those choices is part of being able to maintain the program.

Review the reading tracker design

0 / 10 points

A reading tracker has these function contracts:

  • read_sessions() asks for session lengths in minutes until the user enters done, ignoring surrounding whitespace and capitalization in that command. It converts other entries with int, accepts only positive integers, and returns them in a list. Invalid entries produce a message and another attempt.
  • total_minutes(sessions) returns the total, or 0 for an empty list.
  • longest_session(sessions) returns the largest value, or 0 for an empty list.
  • count_long_sessions(sessions, minimum_minutes) counts values greater than or equal to the supplied minimum, returning 0 for an empty list.
  • print_summary(session_count, total, longest, long_count) displays the four supplied results. When the session count is zero, it displays none for the longest session and numeric zeros for the other results.
  • main() connects these functions, using 30 as the long-session minimum.

The calculation functions receive lists of positive integers, print nothing, and leave the lists unchanged.

In a response of about five to seven sentences, explain why these responsibilities are separated. Include all of the following:

  • why done must be recognized before attempting int(text);
  • what happens after invalid text, zero, or a negative number;
  • why the calculation functions are easier to test than the interactive input function;
  • how longest_session([]) and the printed empty summary represent the no-session case differently;
  • one revealing calculation test, including its input, expected result, and the mistake it could expose.

Base the explanation on the specified program behavior, not only on general statements such as “functions make code cleaner.”

Check Your Understanding

  1. What is the difference between a parameter and an argument?
  2. What is the difference between printing a result and returning it?
  3. Why can mutating a list object through a parameter be visible to the caller, while assigning another integer to a parameter changes only the function’s local name?
  4. What does an assert statement check?
  5. Why should tests be based on intended behavior rather than copied from the implementation?

Feedback

Finish the part with the short reflection and feedback form below.

Reflection and feedback

0 / 5 points

Consider the following statements and answer them based on your experiences from studying the materials and working on the assignments in this part. When answering the numeric statements, answer them so that value 1 means that you strongly disagree with the statement, and value 7 means that you strongly agree with the statement. Please be as honest as possible when answering. The feedback will be used to improve the course.

Looking Ahead

Lists let you store several values, and functions let you organize the behavior that processes them. But a list such as:

student = ["Ada", 42, "Computer Science"]

still relies on remembering what each position means.

In Part 4, you will focus on organizing data. Dictionaries and other structured representations will let programs give names and relationships to the information they store.