Check your understanding of the previous reading: the six logical patterns, and how to reason about multiple return statements.

Question 1

Match each explanation to the most relevant pattern.
An if statement with an and can be replaced with two if statements, one inside the other.
Wrap some code with an if statement so that errors are not caused in certain conditions.
Return a value from a function if a condition is not met, in order to avoid errors.
Return a value from a function with many if/elif/else branches by putting return statements in each branch.
Return a value from a function with many if/elif/else branches by updating a variable and then only having one return statement at the end.
Avoid having multiple else branches to specify default behavior by assigning an initial value to a variable prior to the if statements.

Question 2

What happens when there are multiple return statements in a function?

Select every answer that applies, then check.

  • Not quite. A return ends the function call, not the whole program; execution continues right after the call.
  • Correct. As soon as a return executes, the function is over — nothing after it runs for that call.
  • Not quite. A function may contain as many return statements as you like, as long as at most one of them executes per call.
  • Not quite. Only the first return that actually executes matters; a function ends the moment it runs.
  • Not quite. Only one return executes per call, so there is nothing to combine.
  • Correct. A return unconditionally ends the function, so any code written right after it at the same indentation — including another return — is unreachable. if/elif/else branches are what let several return statements each be reachable.

Question 3

Why might you use the Build-Up-Return pattern instead of the Multiple-Returns pattern?

Select every answer that applies, then check.

  • Correct — this is exactly the trade-off from the reading: isolating return to a single spot makes the control flow easier to reason about.
  • Not stated, and not generally true: Build-Up-Return needs an assignment in every branch plus a final return result, which is usually about the same length as Multiple Return Spots.
  • Not stated in the reading. The two patterns do the same work; there's no meaningful performance difference.
  • Not quite. Both patterns need an exhaustive if/elif/else chain (ending in else) to guarantee a value — forgetting a branch is just as possible either way.
  • Incorrect — the reading says the opposite: "Functionally, they are equivalent." Neither pattern can do something the other can't.

Question 4

In which of these cases might you need a Defensive Guard to avoid an error?

Select every answer that applies, then check.

  • Correct — the reading's own example: guard distance / time with if time > 0:.
  • Correct — the reading's own example: guard int(user_input) with if user_input.isdigit():.
  • Not needed. str() works on any integer — positive, negative, or zero — without error.
  • Not needed. not works on any boolean value without error.
  • Correct. Indexing an empty string (e.g. ""[0]) raises an IndexError, so checking the string is non-empty first avoids it.
  • Not needed for a slice: some_string[:10] never raises an error, even on a shorter string — it just returns however many characters are available.

Question 5

Which of these comparisons between the patterns are accurate?

Select every answer that applies, then check.

  • Correct — the reading says exactly this: "The Early Return pattern is like the Defensive Guard pattern, with an if statement ending a branch inside of a function before an error ... can occur."
  • Incorrect on two counts: the reading never compares these two patterns, and Defensive Guard doesn't use or at all — its examples are plain if checks.
  • Correct — the reading states they are "functionally equivalent," with the same value returned either way.
  • Incorrect. Define-and-Refine is contrasted with needing an else at every level of nested if, not with Multiple Return Spots — the reading never draws that comparison.

Question 6

What does the following code print?

alpha = 20
beta = 3

if alpha > 10:
    if beta > 10:
        alpha = 10

print(alpha)

Show worked solution

The outer condition alpha > 10 is true (20 > 10), so Python enters that block. But the inner condition beta > 10 is false, since beta is 3. So the inner if body (alpha = 10) never runs, and alpha keeps its original value. print(alpha) prints 20.

Question 7

Given the following code:

gamma = "Hello!"
if gamma and gamma[-1] == "!":
    print("Exclaim")

Which of the following programs are functionally equivalent to the conditional part, for any string value of gamma (not just "Hello!")?

Select every answer that applies, then check.

  • Equivalent. len(gamma) > 0 is true exactly when gamma is truthy, and and short-circuits the same way in both versions, so an empty string never reaches the indexing.
  • Not equivalent. With or, any non-empty gamma makes the condition true regardless of its last character, and an empty gamma would fall through to gamma[-1] and raise an IndexError — the original never does either.
  • Equivalent. This is exactly the And vs Nested If pattern applied to the original condition.
  • Not equivalent. This can print twice, prints even when the last character isn't "!", and still indexes gamma[-1] unguarded when gamma is empty.
  • Not equivalent. Any non-empty gamma prints via the first branch, regardless of its last character — the original also requires the last character to be "!".