Chapter 4 Quiz: Control Flow, Functions, and Thinking Like a Programmer
Instructions: This quiz tests your understanding of Chapter 4. Answer all questions before checking the solutions. For multiple choice, select the best answer. For code output questions, trace through the code carefully before checking. Total points: 100.
Section 1: Multiple Choice (8 questions, 4 points each)
Question 1. What is the output of the following code?
x = 75
if x > 90:
label = "high"
elif x > 60:
label = "medium"
elif x > 30:
label = "low"
else:
label = "very low"
print(label)
- (A)
high - (B)
medium - (C)
low - (D)
mediumandlow(both are printed)
Answer
**Correct: (B)** Python evaluates `if`/`elif` chains **top to bottom** and stops at the **first** condition that is `True`. `75 > 90` is `False`, so it moves to `elif`. `75 > 60` is `True`, so `label = "medium"` executes and the rest of the chain is skipped — even though `75 > 30` is also true. **(D)** is a common misconception. Unlike a series of separate `if` statements, an `if`/`elif` chain executes *at most one* branch.Question 2. Which of the following best describes the DRY principle?
- (A) Always delete redundant YAML files from your project
- (B) Avoid duplicating code by encapsulating repeated logic in functions
- (C) Write the shortest possible code, even if it's less readable
- (D) Run your code on dry (test) data before real data
Answer
**Correct: (B)** DRY stands for "Don't Repeat Yourself." The principle says that if you find yourself writing the same code more than once, you should extract it into a function and call the function instead. This makes code easier to maintain (fix one place, not twelve), reduces bugs, and improves readability. **(C)** is wrong because short code that's unreadable violates a different important principle — code clarity. DRY is about eliminating *duplication*, not about brevity at all costs.Question 3. What is the difference between a parameter and an argument?
- (A) They are the same thing — the terms are interchangeable
- (B) A parameter is the variable in the function definition; an argument is the actual value passed when calling the function
- (C) A parameter is for input; an argument is for output
- (D) Parameters are used in
forloops; arguments are used in functions
Answer
**Correct: (B)** In `def greet(name):`, `name` is the **parameter** — a placeholder variable in the function definition. In `greet("Elena")`, `"Elena"` is the **argument** — the actual value passed to the function. The argument gets assigned to the parameter when the function is called. In casual conversation, many programmers use the terms interchangeably, and that's usually fine. But the precise distinction is (B).Question 4. How many times does the body of this loop execute?
for i in range(3):
for j in range(4):
print(i, j)
- (A) 3 times
- (B) 4 times
- (C) 7 times
- (D) 12 times
Answer
**Correct: (D)** The outer loop runs 3 times (i = 0, 1, 2). For *each* iteration of the outer loop, the inner loop runs 4 times (j = 0, 1, 2, 3). Total: 3 x 4 = 12 executions of `print(i, j)`. This is a nested loop — the total number of iterations is the product of the individual loop counts, not the sum.Question 5. What does this function return?
def process(x):
result = x * 2
result = result + 5
print(process(10))
- (A)
25 - (B)
20 - (C)
None - (D) An error occurs
Answer
**Correct: (C)** The function computes `result = 25` correctly, but it has no `return` statement. In Python, a function without a `return` statement implicitly returns `None`. So `process(10)` evaluates to `None`, and `print(None)` outputs `None`. This is the "forgotten return" bug discussed in Section 4.4. The fix is to add `return result` at the end of the function.Question 6. Which of the following is the correct reason to prefer a for loop over a while loop in most data science tasks?
- (A)
forloops are faster thanwhileloops in Python - (B)
whileloops can't iterate over lists - (C)
forloops automatically handle the iteration — there's no risk of an infinite loop from forgetting to update a counter - (D)
whileloops are deprecated in Python 3
Answer
**Correct: (C)** A `for` loop automatically advances through the sequence — you don't need to manage a counter variable, and you can't accidentally create an infinite loop by forgetting to increment it. A `while` loop requires you to manually ensure the condition eventually becomes `False`. **(A)** is not meaningfully true — the performance difference is negligible. **(B)** is false — `while` loops can iterate over lists if you manage an index manually. **(D)** is false — `while` loops are alive and well in Python 3.Question 7. What is the output of this code?
def add_ten(n):
return n + 10
def double(n):
return n * 2
result = add_ten(double(5))
print(result)
- (A)
15 - (B)
20 - (C)
25 - (D)
30
Answer
**Correct: (B)** Python evaluates from the inside out. First, `double(5)` is called, which returns `5 * 2 = 10`. Then `add_ten(10)` is called, which returns `10 + 10 = 20`. If the call were `double(add_ten(5))`, the result would be `30` — add 10 first (getting 15), then double (getting 30). The order of function composition matters.Question 8. What does the term scope refer to in Python?
- (A) The range of values a variable can hold
- (B) The part of the program where a variable is accessible
- (C) The number of functions in a program
- (D) The depth of nested loops
Answer
**Correct: (B)** Scope determines where a variable can be used. A variable created inside a function has *local scope* — it exists only inside that function. A variable created outside all functions has *global scope* — it can be accessed anywhere. Trying to use a local variable outside its function raises a `NameError`. This is why you can use `total` as a variable name inside multiple different functions without them interfering with each other — each `total` exists in its own scope.Section 2: True/False (3 questions, 4 points each)
Question 9. True or False: In an if/elif/else chain, it is possible for none of the branches to execute.
Answer
**False.** If there is an `else` clause, exactly one branch always executes — the `else` catches everything the `if` and `elif` conditions missed. However, if there is no `else` clause (just `if` and `elif`), then it *is* possible for no branch to execute. The statement is false as written because the question specifies an `if`/`elif`/`else` chain (which includes `else`).Question 10. True or False: A while loop always executes its body at least once.
Answer
**False.** A `while` loop checks its condition *before* the first iteration. If the condition is `False` from the start, the body never executes. For example:x = 10
while x < 5:
print("This never prints")
This loop's body executes zero times because `10 < 5` is `False` immediately.
Question 11. True or False: A function in Python can return more than one value.
Answer
**True.** A function can return multiple values separated by commas: `return min_val, max_val, average`. Technically, Python packs them into a tuple, but you can unpack them directly: `low, high, avg = my_function(data)`. This is commonly used in data science to return multiple computed results from a single function.Section 3: Code Output Prediction (5 questions, 6 points each)
For each question, predict the exact output without running the code. Then check your answer.
Question 12. What is the output?
total = 0
for num in [1, 2, 3, 4, 5]:
if num % 2 == 0:
total = total + num
print(total)
Answer
**Output: `6`** The `%` operator computes the remainder after division. `num % 2 == 0` is `True` only for even numbers. The loop adds only the even numbers: 2 + 4 = 6. The odd numbers (1, 3, 5) are skipped by the `if` condition.Question 13. What is the output?
def classify(value):
if value > 100:
return "over"
if value > 50:
return "middle"
return "under"
print(classify(75))
print(classify(120))
print(classify(30))
Answer
**Output:**middle
over
under
Notice that this function uses multiple `return` statements instead of `if`/`elif`/`else`. Each `return` exits the function immediately. For `75`: `75 > 100` is `False`, `75 > 50` is `True`, returns `"middle"`. For `120`: `120 > 100` is `True`, returns `"over"` immediately. For `30`: both conditions are `False`, falls through to `return "under"`.
This style (using `return` to exit early) is called "early return" and is common in professional Python code.
Question 14. What is the output?
x = 5
while x > 0:
x = x - 2
print(x)
Answer
**Output:**3
1
-1
Trace: x starts at 5. Iteration 1: x = 5 - 2 = 3, print 3. Iteration 2: x = 3 - 2 = 1, print 1. Iteration 3: x = 1 - 2 = -1, print -1. Now the condition `x > 0` is `-1 > 0`, which is `False`, so the loop stops.
Note that `x` is decremented *before* printing, and the loop exits *after* printing -1 because the condition is checked *before* each iteration, not after.
Question 15. What is the output?
def outer(a):
def inner(b):
return a + b
return inner(a * 2)
print(outer(3))
Answer
**Output: `9`** `outer(3)` is called with `a = 3`. Inside `outer`, a function `inner` is defined. Then `inner(a * 2)` is called, which is `inner(6)`. Inside `inner`, `b = 6`, and it returns `a + b = 3 + 6 = 9`. So `outer(3)` returns `9`. This shows that functions can be defined inside other functions, and the inner function can access the outer function's variables (in this case, `a`). This concept is called a "closure" — you'll encounter it more in advanced Python.Question 16. What is the output?
values = [10, 20, 30, 40, 50]
result = []
for v in values:
if v > 25:
result.append(v)
print(result)
print(len(result))
Answer
**Output:**[30, 40, 50]
3
The loop checks each value against the condition `v > 25`. Values 30, 40, and 50 pass the condition and are appended to `result`. `len(result)` returns 3 because the list has three elements.
The `append()` method adds an item to the end of a list — you'll study this more in Chapter 5.
Section 4: Short Answer (2 questions, 6 points each)
Question 17. Explain the concept of decomposition in programming. Give a brief example of how you might decompose the task "Generate a report of student grades" into smaller functions.
Answer
**Decomposition** is the process of breaking a large, complex problem into smaller, manageable sub-problems, each of which can be solved independently — typically as its own function. For "Generate a report of student grades," you might decompose into: 1. `validate_grade(value)` — check whether a single grade is valid 2. `numeric_to_letter(grade)` — convert a number to a letter grade 3. `compute_average(grades)` — calculate the mean of a list of grades 4. `format_grade_line(name, grade)` — produce a formatted string for one student 5. `generate_report(student_data)` — orchestrate the above functions to produce the full report Each function does one thing, is independently testable, and can be reused elsewhere. The top-level function reads like a high-level description of the process rather than a tangle of implementation details.Question 18. What is pseudocode, and why is it useful? Write pseudocode for a function that finds the second-largest number in a list.
Answer
**Pseudocode** is a way of describing program logic in plain language (or a mix of plain language and programming-like structure) without using the syntax of any specific programming language. It's useful because it lets you focus on the *logic* of your solution before getting bogged down in syntax details. Pseudocode for finding the second-largest number:FUNCTION find_second_largest(numbers):
SET largest to the first number
SET second_largest to negative infinity
FOR each number in the list:
IF number > largest:
SET second_largest to largest
SET largest to number
ELSE IF number > second_largest AND number != largest:
SET second_largest to number
RETURN second_largest
The pseudocode reveals the key insight: when you find a new largest, the old largest becomes the second-largest. You also need to handle the case where a number is bigger than `second_largest` but not bigger than `largest`.
Section 5: Applied Scenarios (2 questions, 8 points each)
Question 19. Elena has vaccination rates for 8 countries stored in two lists:
countries = ["Brazil", "India", "Nigeria", "Germany",
"Japan", "Kenya", "France", "Australia"]
rates = [72.1, 65.3, 41.8, 88.5,
91.2, 38.4, 85.7, 93.0]
Write a complete Python program that:
1. Defines a function categorize(rate) that returns "low" (below 50), "medium" (50-79), or "high" (80+)
2. Uses a loop to print each country with its rate and category
3. At the end, prints the number of countries in each category
Answer
def categorize(rate):
if rate < 50:
return "low"
elif rate < 80:
return "medium"
else:
return "high"
countries = ["Brazil", "India", "Nigeria", "Germany",
"Japan", "Kenya", "France", "Australia"]
rates = [72.1, 65.3, 41.8, 88.5,
91.2, 38.4, 85.7, 93.0]
low_count = 0
medium_count = 0
high_count = 0
for i in range(len(countries)):
cat = categorize(rates[i])
print(f"{countries[i]}: {rates[i]}% ({cat})")
if cat == "low":
low_count = low_count + 1
elif cat == "medium":
medium_count = medium_count + 1
else:
high_count = high_count + 1
print(f"\nLow: {low_count}, Medium: {medium_count}, High: {high_count}")
Expected output:
Brazil: 72.1% (medium)
India: 65.3% (medium)
Nigeria: 41.8% (low)
Germany: 88.5% (high)
Japan: 91.2% (high)
Kenya: 38.4% (low)
France: 85.7% (high)
Australia: 93.0% (high)
Low: 2, Medium: 2, High: 4
Question 20. Marcus wants a function that analyzes his daily sales and tells him whether the week was "strong" (average above $500), "average" (average between $400 and $500), or "weak" (average below $400). He also wants to know his best and worst day.
Write a function weekly_performance(sales) that:
1. Computes the total and average
2. Finds the best day (highest sales) and worst day (lowest sales) — report the day number (1-based)
3. Classifies the week as "strong," "average," or "weak"
4. Returns a formatted report string (not just a print — return the string so Marcus could save it to a file later)
Test with [520, 380, 610, 430, 390, 710, 550].
Answer
def weekly_performance(sales):
total = 0
best = sales[0]
worst = sales[0]
best_day = 1
worst_day = 1
for i in range(len(sales)):
total = total + sales[i]
if sales[i] > best:
best = sales[i]
best_day = i + 1
if sales[i] < worst:
worst = sales[i]
worst_day = i + 1
average = total / len(sales)
if average > 500:
performance = "strong"
elif average >= 400:
performance = "average"
else:
performance = "weak"
report = f"Weekly Report\n"
report = report + f"Total: ${total}\n"
report = report + f"Average: ${average:.2f}\n"
report = report + f"Best day: Day {best_day} (${best})\n"
report = report + f"Worst day: Day {worst_day} (${worst})\n"
report = report + f"Performance: {performance}"
return report
result = weekly_performance([520, 380, 610, 430, 390, 710, 550])
print(result)
Expected output:
Weekly Report
Total: $3590
Average: $512.86
Best day: Day 6 ($710)
Worst day: Day 2 ($380)
Performance: strong
Key points: the function *returns* the report string rather than printing it directly. This makes it reusable — Marcus could print it, save it to a file, or email it. The day numbering is 1-based (humans count from 1, not 0), so we add 1 to the index.