158. Chapter 1 Review Quiz
Variables, comments, indentation, keywords, and identifiers
158. Chapter 1 Review Quiz
Aryan finishes Chapter 1 and decides to review everything in one shot. He opens his RAM monitor project and finds five sections of code — each broken in exactly the way from the concept he just studied.
The file has five labelled sections. Fix every bug to pass all the tests.
Section 1 — Variables Six cryptic single-letter names. Rename them to the meaningful names shown in the comments next to each one.
Section 2 — Comments compute_ram_alert has a wrong threshold and no comment explaining it. Fix the threshold to 0.85 for CRITICAL and 0.7 for WARNING. Add a # comment above each if explaining the value. score_session is logically correct but has no comment explaining why problems score 5× and hours score 2×. Add that comment.
Section 3 — Indentation total_memory has a stray line after the loop that zeros the result. count_warnings has a stray line after the loop that undercounts by one. Remove both stray lines.
Section 4 — Keywords check_keyword uses a hardcoded list of 7 words — far too short. Replace it with keyword.iskeyword().
Section 5 — Identifiers validate_field only calls isidentifier() and lets keywords like for pass as valid. Add the keyword exclusion.
💡 Fun fact: Professional code reviews consistently flag the same five classes of mistakes: bad names, missing context comments, scope bugs, incomplete guards, and insufficient validation. You just fixed all five in one file.
⚠️ Watch out: Several tests will pass even with the broken code (e.g., the score_session and some compute_ram_alert cases). A passing test only proves the code works for that input — it doesn’t prove the code is correct.
🤔 Think about it: If a future engineer reads ratio > 0.9 with no comment, what will they assume about the threshold? How likely are they to “round it up” to 1.0 because it seems more natural?
Learning objectives
- Replace cryptic single-letter names with meaningful domain names
- Document non-obvious thresholds and weights with inline comments
- Identify and remove stray lines that corrupt loop results
- Use keyword.iskeyword() instead of hardcoded keyword lists
- Combine isidentifier() and iskeyword() for complete identifier validation
Key concepts
- variables
- comments
- indentation
- keywords
- identifiers
Try it
Concept detail
This quiz consolidates all five Chapter 1 concepts in a single file:
VARIABLES — Names are free documentation. a, b, c force the reader to reverse-engineer meaning from context. pid, memory_mb, cpu_percent communicate the domain at zero cost. Rename early; rename everywhere.
COMMENTS — Comment the WHY, not the WHAT. ‘# ratio > 0.85’ is noise — the code already shows that. ‘# CRITICAL at 85% per ops runbook v2’ is knowledge that cannot be derived from the code alone. The wrong threshold (0.9 instead of 0.85) is exactly the kind of silent bug that a missing comment enables: no one knows where 0.9 came from, so no one questions it.
INDENTATION — Python scope is indentation. A line at the wrong level is syntactically valid but semantically wrong. ‘total = total * 0’ and ‘count = count - 1’ both run AFTER the loop, corrupting correct results. No IndentationError is raised — the bugs are invisible until a test fails.
KEYWORDS — Python 3 has 35 reserved words. A hardcoded list of 7 misses lambda, assert, yield, async, await, nonlocal, global, and more. keyword.iskeyword() uses the parser’s own definition: always complete, always version-correct.
IDENTIFIERS — str.isidentifier() checks character rules (starts with letter/underscore, only letters/digits/underscores). It returns True for ‘for’, ‘while’, ‘class’ because those are syntactically valid name shapes. The keyword exclusion must be layered on top explicitly: name.isidentifier() and not keyword.iskeyword(name)
Solution
import keyword
# ── SECTION 1: Variables ────────────────────────────────────────────────────
pid = 812
memory_mb = 544
cpu_percent = 6.8
hours_studied = 8
problems_solved = 12
coffee_cups = 3
# ── SECTION 2: Comments ─────────────────────────────────────────────────────
def compute_ram_alert(used_mb, total_mb):
ratio = used_mb / total_mb
# CRITICAL at 85% — threshold from ops runbook v2
if ratio > 0.85:
return "CRITICAL"
# WARNING at 70% — early pressure signal
if ratio > 0.7:
return "WARNING"
return "OK"
def score_session(problems, hours):
# problems weighted 5x, hours weighted 2x per study-score rubric
return problems * 5 + hours * 2
# ── SECTION 3: Indentation ──────────────────────────────────────────────────
def total_memory(process_list):
total = 0
for mem in process_list:
if mem > 0:
total += mem
return total
def count_warnings(log_entries):
count = 0
for entry in log_entries:
if entry == "WARNING":
count += 1
return count
# ── SECTION 4: Keywords ─────────────────────────────────────────────────────
def check_keyword(word):
return keyword.iskeyword(word)
# ── SECTION 5: Identifiers ──────────────────────────────────────────────────
def validate_field(name):
return name.isidentifier() and not keyword.iskeyword(name)Tests
# ── Section 1: Variables ────────────────────────────────────────────────────
def test_pid():
assert pid == 812
def test_memory_mb():
assert memory_mb == 544
def test_cpu_percent():
assert cpu_percent == 6.8
def test_hours_studied():
assert hours_studied == 8
def test_problems_solved():
assert problems_solved == 12
def test_coffee_cups():
assert coffee_cups == 3
# ── Section 2: Comments ─────────────────────────────────────────────────────
# Tests verify the corrected threshold logic; the comment itself is learned
# but not machine-checked.
def test_alert_critical_above_85():
# ratio = 0.88 → above 0.85 → CRITICAL (broken code misses this: returns WARNING)
assert compute_ram_alert(88, 100) == "CRITICAL"
def test_alert_critical_above_90():
# ratio = 0.95 → CRITICAL in both broken and fixed
assert compute_ram_alert(95, 100) == "CRITICAL"
def test_alert_warning_between_70_and_85():
# ratio = 0.75 → WARNING in both broken and fixed
assert compute_ram_alert(75, 100) == "WARNING"
def test_alert_ok_below_70():
# ratio = 0.60 → OK in both broken and fixed
assert compute_ram_alert(60, 100) == "OK"
def test_score_session_basic():
# 3 problems * 5 + 2 hours * 2 = 19
assert score_session(3, 2) == 19
def test_score_session_zero_problems():
assert score_session(0, 4) == 8
def test_score_session_zero_hours():
assert score_session(5, 0) == 25
# ── Section 3: Indentation ──────────────────────────────────────────────────
def test_total_memory_all_positive():
# broken: total * 0 after loop → returns 0; fixed: returns 600
assert total_memory([100, 200, 300]) == 600
def test_total_memory_skips_zero():
# 0 values must be excluded by the if condition
assert total_memory([0, 50, 0, 150]) == 200
def test_total_memory_empty():
assert total_memory([]) == 0
def test_count_warnings_multiple():
# broken: count - 1 after loop → returns 1; fixed: returns 2
assert count_warnings(["OK", "WARNING", "WARNING", "OK"]) == 2
def test_count_warnings_none():
# broken: 0 - 1 = -1; fixed: returns 0
assert count_warnings(["OK", "OK"]) == 0
def test_count_warnings_all():
assert count_warnings(["WARNING", "WARNING", "WARNING"]) == 3
# ── Section 4: Keywords ─────────────────────────────────────────────────────
def test_for_is_keyword():
assert check_keyword("for") == True
def test_while_is_keyword():
assert check_keyword("while") == True
def test_lambda_is_keyword():
# broken: "lambda" not in hardcoded list → returns False
assert check_keyword("lambda") == True
def test_assert_is_keyword():
# broken: "assert" not in hardcoded list → returns False
assert check_keyword("assert") == True
def test_yield_is_keyword():
# broken: "yield" not in hardcoded list → returns False
assert check_keyword("yield") == True
def test_async_is_keyword():
# broken: "async" not in hardcoded list → returns False
assert check_keyword("async") == True
def test_banana_not_keyword():
assert check_keyword("banana") == False
def test_print_not_keyword():
# print is a built-in, not a keyword
assert check_keyword("print") == False
# ── Section 5: Identifiers ──────────────────────────────────────────────────
def test_my_var_valid():
assert validate_field("my_var") == True
def test_private_underscore_valid():
assert validate_field("_private") == True
def test_for_invalid():
# broken: "for".isidentifier() → True, so broken returns True
assert validate_field("for") == False
def test_while_invalid():
assert validate_field("while") == False
def test_lambda_invalid():
assert validate_field("lambda") == False
def test_digit_start_invalid():
assert validate_field("1abc") == False
def test_dash_invalid():
assert validate_field("my-var") == False
def test_space_invalid():
assert validate_field("my var") == False