Chapter 7 Quiz: Understanding AI-Generated Code

Test your understanding of the concepts covered in this chapter. Each question has a single best answer. Click the answer section to reveal the correct response.


Question 1: What is the recommended first step when reviewing AI-generated code?

A) Read the code line by line from top to bottom B) Run the code to see if it works C) Perform a structural analysis scan of imports, classes, and functions D) Check for security vulnerabilities

Answer **C) Perform a structural analysis scan of imports, classes, and functions** Structural analysis (the "bird's-eye view") should always come first. It gives you context about the code's organization and dependencies before you dive into the details of any particular function. This is Phase 1 of the five-phase review process described in section 7.10.

Question 2: When tracing through code, why is it important to use concrete input values rather than abstract ones?

A) Abstract values are harder to type B) Concrete values let you verify exact behavior and catch edge-case bugs C) Python does not support abstract variables D) Concrete values make the code run faster

Answer **B) Concrete values let you verify exact behavior and catch edge-case bugs** When you trace with a specific value like `items = [3, 1, 4]`, you can determine the exact output and catch issues like off-by-one errors or incorrect comparisons. Abstract reasoning ("the list has some elements") can miss specific cases where bugs manifest.

Question 3: Which of the following is the correct way to check for None in Python?

A) if x == None: B) if x is None: C) if x = None: D) if x.isNone():

Answer **B) `if x is None:`** PEP 8 specifies that comparisons to singletons like `None` should always use `is` or `is not`, never the equality operators `==` and `!=`. The `is` operator checks identity (whether it is the exact same object), which is both faster and more correct for `None`.

Question 4: What is the primary problem with this AI-generated code pattern?

def get_low_tasks(tasks): ...
def get_medium_tasks(tasks): ...
def get_high_tasks(tasks): ...

A) The functions are too short B) It violates DRY by duplicating nearly identical logic C) The function names are too descriptive D) Python does not allow multiple functions with similar names

Answer **B) It violates DRY by duplicating nearly identical logic** This is the "copy-paste variations" pattern common in AI-generated code (section 7.5, Pattern 5). A single parameterized function `get_tasks_by_priority(tasks, priority)` eliminates the duplication and is easier to maintain.

Question 5: What is the algorithmic complexity of looking up a key in a Python dictionary?

A) O(n) B) O(log n) C) O(1) on average D) O(n^2)

Answer **C) O(1) on average** Python dictionaries are implemented as hash tables, which provide average-case constant-time lookup. This is why converting a list to a dictionary for repeated lookups can dramatically improve performance.

Question 6: Which of the following is a security vulnerability?

A) cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,)) B) cursor.execute(f"SELECT * FROM users WHERE id = {user_id}") C) cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) D) Both A and C are secure; B is vulnerable

Answer **D) Both A and C are secure; B is vulnerable** Option B uses f-string interpolation to insert a value directly into the SQL query, making it vulnerable to SQL injection. Options A and C use parameterized queries where the database driver safely handles the value insertion.

Question 7: What makes the following code problematic?

result = ""
for item in large_list:
    result += str(item) + "\n"

A) str() is slow B) String concatenation in a loop creates a new string on each iteration, leading to O(n^2) behavior C) The newline character is wrong D) large_list should be a tuple

Answer **B) String concatenation in a loop creates a new string on each iteration, leading to O(n^2) behavior** Since Python strings are immutable, each `+=` operation creates a new string object and copies all previous content into it. For a list of n items, this copies approximately 1 + 2 + 3 + ... + n characters, which is O(n^2). The fix is to use `"\n".join()` or a list and join at the end.

Question 8: What does it mean when AI-generated code includes import os but os is never used in the code body?

A) The import is needed for internal Python operations B) It is an unused import and should be removed C) It improves performance by preloading the module D) It is required by PEP 8

Answer **B) It is an unused import and should be removed** Unused imports are clutter that makes it harder to understand the code's actual dependencies. AI tools often include "just in case" imports. They can be detected automatically by tools like `flake8` (warning code F401) or `pylint`.

Question 9: Which is the best approach to error handling for a function that reads a file?

A) Let exceptions propagate naturally without any handling B) Wrap everything in a bare except: clause C) Handle specific expected exceptions like FileNotFoundError and json.JSONDecodeError D) Use try/except to silently return None on any error

Answer **C) Handle specific expected exceptions like `FileNotFoundError` and `json.JSONDecodeError`** Specific exception handling communicates what failures are expected and how they are handled. Bare `except:` catches everything including `KeyboardInterrupt` and `SystemExit`, which is almost never correct. Silently returning `None` hides bugs.

Question 10: In the PEP 8 import ordering convention, what is the correct order?

A) Third-party, standard library, local B) Local, standard library, third-party C) Standard library, third-party, local D) Alphabetical regardless of source

Answer **C) Standard library, third-party, local** PEP 8 specifies that imports should be grouped in this order: standard library imports, third-party imports, and local application/library imports, with a blank line between each group. This makes it easy to identify external dependencies at a glance.

Question 11: What is the key difference between structural analysis and line-by-line tracing?

A) Structural analysis is faster; tracing is more thorough B) Structural analysis looks at overall organization; tracing follows execution flow with specific values C) Structural analysis is for classes; tracing is for functions D) There is no difference; they are the same technique

Answer **B) Structural analysis looks at overall organization; tracing follows execution flow with specific values** Structural analysis is the bird's-eye view where you identify components and their relationships. Line-by-line tracing is the detailed level where you mentally execute code with concrete inputs to verify correctness. Both are necessary for thorough review.

Question 12: Why is eval() considered a security risk in AI-generated code?

A) It is slow B) It executes arbitrary Python code, which could be malicious if the input is untrusted C) It only works in Python 2 D) It cannot handle strings

Answer **B) It executes arbitrary Python code, which could be malicious if the input is untrusted** `eval()` interprets and executes any Python expression, meaning if user input reaches an `eval()` call, an attacker could execute arbitrary code on the system. Safer alternatives include `ast.literal_eval()` for parsing data literals or purpose-built parsers for more complex needs.

Question 13: What is a "silent failure" in code?

A) Code that runs without producing any output B) Code that fails but does not raise an error or indicate the failure to the caller C) Code that only fails when run in silent mode D) Code that catches all exceptions

Answer **B) Code that fails but does not raise an error or indicate the failure to the caller** Silent failures are particularly dangerous because the program continues running with incorrect state. An example is a `delete_task` function that returns nothing whether or not the deletion succeeded — the caller has no way to know if the task was actually removed.

Question 14: What is the "thundering herd" problem referenced in the context of retry logic?

A) Too many animals accessing the same watering hole B) Many clients simultaneously retrying after a failure, overwhelming the server C) A performance issue with too many threads D) A memory leak caused by excessive retries

Answer **B) Many clients simultaneously retrying after a failure, overwhelming the server** When a server goes down briefly, all clients that were waiting will retry at the same moment, creating a massive spike that can bring the server down again. Exponential backoff with random jitter staggers the retries across time, preventing this problem.

Question 15: What is wrong with the following comparison in AI-generated code?

if task.completed == True:

A) It should use is True B) It is redundant; if task.completed: is sufficient and more Pythonic C) True is not a valid Python value D) The comparison operator is wrong

Answer **B) It is redundant; `if task.completed:` is sufficient and more Pythonic** Comparing a boolean value to `True` is unnecessary because the `if` statement already evaluates the truthiness of the expression. Writing `if task.completed:` is cleaner, more Pythonic, and follows PEP 8 recommendations. The same applies to `if not task.completed:` instead of `if task.completed == False:`.

Question 16: When reviewing AI-generated code, what should you do if you find an import for a third-party package you do not recognize?

A) Remove it immediately B) Assume the AI knows best and keep it C) Research the package's purpose, maintenance status, and whether it is necessary D) Replace it with a standard library alternative

Answer **C) Research the package's purpose, maintenance status, and whether it is necessary** Unknown third-party packages could be outdated, unmaintained, or even malicious. Before accepting any dependency, check its PyPI page, GitHub repository, download statistics, and recent release history. Also verify whether a standard library module could accomplish the same task.

Question 17: What is the most common reason AI generates overly verbose code?

A) AI models have a verbosity setting that is too high B) AI is trained on diverse code and tends toward explicit, safe patterns rather than concise idioms C) Verbose code runs faster D) Python requires verbose syntax

Answer **B) AI is trained on diverse code and tends toward explicit, safe patterns rather than concise idioms** AI models generate code based on patterns in their training data, which includes code at all skill levels. They tend to produce code that is maximally explicit — using loops instead of comprehensions, creating wrapper functions, and adding comments for obvious operations. This makes the code accessible but often less Pythonic.

Question 18: What hidden performance problem exists in this code?

def find_duplicates(items: list[str]) -> list[str]:
    duplicates = []
    for item in items:
        if items.count(item) > 1 and item not in duplicates:
            duplicates.append(item)
    return duplicates

A) The list is not sorted B) items.count() scans the entire list on each iteration, making this O(n^2) C) The not in check is invalid syntax D) There is no performance problem

Answer **B) `items.count()` scans the entire list on each iteration, making this O(n^2)** `items.count(item)` is O(n) because it must check every element. When called inside a loop that is also O(n), the total complexity becomes O(n^2). Additionally, `item not in duplicates` is also O(n), making the worst case O(n^2) from two sources. A dictionary-based counting approach achieves O(n).

Question 19: What is a resource leak?

A) Sensitive data exposed in logs B) An open file, connection, or other system resource that is not properly closed C) A memory allocation that grows without bound D) A security vulnerability that leaks information

Answer **B) An open file, connection, or other system resource that is not properly closed** Resource leaks occur when code opens a file handle, database connection, or network socket but does not close it, especially when an exception occurs between the open and close operations. In Python, context managers (the `with` statement) prevent this by guaranteeing cleanup regardless of exceptions.

Question 20: What is the purpose of a code tracing table?

A) To record how long each function takes to execute B) To track variable values at each step of execution for debugging and verification C) To trace which files import which modules D) To measure code coverage during testing

Answer **B) To track variable values at each step of execution for debugging and verification** A tracing table has columns for line number, variable name, current value, and notes. By filling it in as you mentally execute the code, you create a precise record of program state at each step, making it much easier to spot logical errors.

Question 21: Why should secrets never be hardcoded in source code?

A) Hardcoded strings use more memory B) Source code is often stored in version control systems where secrets become visible to anyone with repository access C) Python does not allow string constants D) Secrets must be encrypted

Answer **B) Source code is often stored in version control systems where secrets become visible to anyone with repository access** Once a secret is committed to a Git repository, it persists in the repository history even if deleted in a later commit. Anyone with access to the repository can find it. Secrets should be stored in environment variables, dedicated secret management systems, or encrypted configuration files that are excluded from version control.

Question 22: What is path traversal?

A) Navigating through a directory structure in code B) An attack where a user manipulates file paths to access files outside the intended directory C) A programming technique for searching directory trees D) A way to resolve relative paths

Answer **B) An attack where a user manipulates file paths to access files outside the intended directory** For example, if code reads a file based on user input like `filename = "../../../etc/passwd"`, the attacker can escape the intended directory and read sensitive system files. The defense is to resolve the final path and verify it still falls within the allowed base directory.

Question 23: When should you use isinstance() type checking in Python code?

A) On every function parameter B) Never — Python is dynamically typed C) At trust boundaries such as API endpoints, user input processing, and deserialization D) Only on integers and strings

Answer **C) At trust boundaries such as API endpoints, user input processing, and deserialization** Type checking at every function call is overly defensive and un-Pythonic (section 7.5, Pattern 4). However, at boundaries where external data enters the system — user input, API requests, file loading — validation including type checking is appropriate and important.

Question 24: What is the reading-to-writing ratio for professional developers?

A) 1:10 (write 10 lines for every 1 read) B) 1:1 (equal reading and writing) C) 10:1 (read 10 lines for every 1 written) D) 100:1 (read 100 lines for every 1 written)

Answer **C) 10:1 (read 10 lines for every 1 written)** Research and industry experience suggest that developers spend roughly 10 times more time reading code than writing it. In vibe coding, this ratio is even higher because the AI handles most of the writing, making reading and evaluation the primary developer activity.

Question 25: What should you do after finding a new type of issue during a code review that your checklist did not cover?

A) Nothing — the checklist is already comprehensive B) Add the new check to your personal code review checklist C) Report it as an AI bug D) Start using a different AI tool

Answer **B) Add the new check to your personal code review checklist** The code review checklist is a living document that should evolve based on your experience. Every new issue you discover is an opportunity to improve your checklist. Over time, this creates a personalized safety net that reflects the specific kinds of issues you encounter in your projects and with your chosen AI tools.