Organizing Code with Functions

Restructuring Your Study Log with Functions


This chapter is the project checkpoint for this part. Your task in this part is to refactor your own study log into functions, write a specification for each one, and write a small set of tests using the edge-case checklist as a guide.

Nothing new is added to the program in this part. The study log will accept multiple sessions in one run, react to each one, and print a summary at the end — same as in the previous part. What changes is the internal organization. By the end of this checkpoint, the main script should be short, and the substantive logic should live in named, specified, tested functions.

What the Study Log Does Now

Same behavior as in the previous part:

  1. Asks for sessions one at a time in a loop, until the user types done.
  2. Stores each session (subject and minutes) in parallel lists.
  3. Reacts to each session with a different message depending on its length.
  4. Prints a summary at the end: number of sessions, total minutes, average session length, longest session.

The edge case handling extends slightly beyond the previous part. Done and done still work as quit signals, the empty case still does not crash, and zero-minute sessions are still accepted. New in this part: when the user types something that is not a number for the minutes — forty-five, an empty string, a word — the program re-prompts rather than crashing. This uses the try/except pattern from the chapter on Exceptions and Input Validation.

Required Functions

At a minimum, your refactored study log must define and use the following three functions. You may add others.

1. A classification function. Takes a number of minutes and returns a label or response that describes the session length. Your choice whether it returns a short label ("short", "solid", "long") or a longer message — but it must return, not print. The thresholds are yours to pick.

2. A totalling function. Takes a list of minutes and returns the total. Handles the empty list correctly: the total of nothing is zero.

3. A longest-session function. Takes a list of minutes and returns the largest. Handles the empty list explicitly — either by returning None, raising an error, or some other choice you can justify.

Each of these must:

  • Take its inputs entirely through parameters.
  • Produce its output entirely through return.
  • Avoid touching global state.

In other words, the three required functions should be small calculation helpers: they receive data through parameters and give the answer back with return. Functions that involve input(...) or print(...) — like get_session or print_summary — are not required. You may add them if they help organize your program, but the required tests focus on the three returned-value helpers above.

Required Specifications

Each required function gets a docstring describing:

  • What it takes (parameters, with types).
  • What it returns (with type).
  • What it does on edge cases — at minimum, the empty list, the single element, and the boundary values that apply to the function.

The format is up to you, but the content must cover what the previous chapter called the parts of a spec — name, parameters, return value, edge cases, and (when applicable) what the function raises. Here is one valid example for the totalling function:

def total_minutes(minutes_list):
"""Return the sum of all integers in minutes_list.
Parameters:
minutes_list: list of int.
Returns:
int. The sum of the items.
Edge cases:
Empty list returns 0.
Single-element list returns that element.
Negative numbers are summed normally.
"""
total = 0
for m in minutes_list:
total += m
return total

The docstring is the spec, sitting permanently above the function. Anyone reading the code — including yourself, later on — knows exactly what this function is supposed to do.

Required Tests

For each required function, write at least three assert-based tests. The three tests should hit different rows of the edge-case checklist. At minimum, include:

  • An obvious case that any version of the function should pass.
  • A boundary case if the function has thresholds, or an edge case like the empty list otherwise.
  • A single-element case if the function takes a list.

Put the tests immediately below each function definition, with a confirming print(...) after the assertions so a successful test run produces visible output.

def total_minutes(minutes_list):
...
assert total_minutes([]) == 0
assert total_minutes([45]) == 45
assert total_minutes([45, 30, 60]) == 135
print("total_minutes passes.")

When the program starts, you should see your three confirmation messages printed before the === Study Log === banner. That is your evidence that all required functions are working as specified.

Required Input Validation

The program must handle a non-numeric minutes input gracefully. If the user types forty-five or an empty string when asked for minutes, the program must re-prompt rather than crash with a ValueError.

The recommended place for this is inside whatever function reads input — usually get_session() if you wrote one, or directly in the main loop if you did not.

while True:
minutes_text = input("For how many minutes? ").strip()
try:
minutes = int(minutes_text)
break
except ValueError:
print("Please enter a whole number of minutes.")

You may go further if you want — rejecting negative numbers, very large numbers, or zero — but the minimum requirement is just the non-numeric case. The choice of whether to validate beyond that should be reflected in the function’s spec, including a Raises section if your function raises exceptions of its own.

The Main Script After Refactoring

Your main script — the part that runs the user-facing program — should be considerably shorter than the version from the previous part. It should look roughly like this skeleton:

# ... function definitions and tests above ...
print("=== Study Log ===")
print()
subjects = []
minutes_list = []
while True:
# ... get a session, break if done ...
# ... append to lists ...
# ... use classify function to respond ...
# ... call summary function ...

The substantive work — classifying, totalling, finding the longest — is done by function calls. The main script is mostly the input loop and the glue around it.

A Reference Checkpoint

The chapter Refactoring Code Into Functions walked through a complete refactor of the study log. If your own refactor becomes tangled, that worked version is available as a reference. You do not have to match it line for line — many valid refactors are possible — but it is one shape the program can take, and borrowing from it is fine.

The reason for the reference is to give you something to fall back to if the refactor takes more time than expected.

Using AI for This Project

It is worth being explicit about how to use AI well on this checkpoint, if you choose to.

You may use AI assistants to help with the refactor. The recommended approach is the workflow from the previous chapter:

  1. Write the spec for each required function yourself, by hand, including the edge-case section.
  2. Use the spec as the AI prompt.
  3. Verify the result with the tests you derived from the spec, not from the AI’s output.
  4. Trace one execution by hand for each function before considering it done.

This way, the AI does the typing, but you do the design and the verification. The course is not asking you to avoid AI assistants. It is asking you to use them through the three skills you have built — reading, verifying, specifying — rather than as a shortcut around them.

Extra Things to Try Out

A few open suggestions, none required:

  • A count_long_sessions(minutes_list, threshold) function that returns the number of sessions exceeding a threshold. Specify the boundary case (is exactly threshold long?) before writing it.
  • A most_studied_subject(subjects) function that returns the subject appearing most often in the list. Specify the tie-breaking rule (what if two subjects tie?) before writing it.
  • A format_session_response(subject, label) function that returns the response string given a subject and a length label. Specify how the function handles an unknown label.

Each of these is small. Each gets a spec, an implementation, and at least three tests. Doing one of them — fully, with the discipline — is more valuable than starting all three.

Refactor the study log into functions

0 / 20 points

Build the refactored study log.

The user-facing behavior is the same as in the previous part, with one added robustness requirement: non-numeric minutes must re-prompt instead of crashing.

Your program must define and use at least these three pure helper functions:

  • classify_session(minutes), returning "short", "solid", or "long",
  • total_minutes(minutes_list), returning the total minutes and 0 for an empty list,
  • longest_session(minutes_list), returning the largest value and None for an empty list.

Each required helper must have a docstring/specification, take inputs through parameters, return its result, avoid global state, and have at least three assert tests. In total, your program should contain at least nine assert statements for these helpers.

Required classification behavior:

  • less than 15 minutes is "short",
  • 15 through 90 minutes is "solid",
  • more than 90 minutes is "long".

The main program must:

  • print Study Log,
  • repeatedly ask for a subject until the user types done,
  • normalize Done, DONE, and done with .strip().lower(),
  • ask for minutes only after a non-quit subject,
  • re-prompt with Please type minutes as a whole number. after non-numeric minutes,
  • store subjects and minutes in parallel lists,
  • print a response for each session using the classification helper,
  • and print a summary after the loop.

The summary must include the number of sessions, total minutes, average minutes rounded to one decimal place, and longest session in minutes.

Required response lines:

Short session on math.
Solid session on math.
Long session on math.

Your program prints the one that matches the actual subject and minutes.

If no sessions are logged, print:

No sessions logged.

Example input:

Math
10
Physics
nope
95
Done

Required output text:

Study Log
Short session on math.
Please type minutes as a whole number.
Long session on physics.
Sessions: 2
Total minutes: 105
Average minutes: 52.5
Longest session: 95

The exact input prompts may differ. The required output lines above must appear exactly as written. It is fine if your helper-test confirmation messages print before Study Log.

Empty-run example input:

done

Required output text:

Study Log
No sessions logged.