Prepare for PCEP: Certified Entry-Level Python Programmer (PCEP-30-02) with free sample questions, a full-length diagnostic, topic drills, timed practice, syntax, control flow, collections, functions, exceptions, beginner code-reading drills, and detailed explanations in IT Mastery.
PCEP is Certified Entry-Level Python Programmer, the Python Institute entry route for candidates who need to prove basic Python syntax, programming concepts, data collections, functions, exceptions, and simple problem solving.
IT Mastery practice for PCEP-30-02 is live now. Use this page to start the web simulator, review the exam snapshot, work through 24 public sample questions, and continue into full IT Mastery practice with the same IT Mastery account on web, iOS, iPadOS, macOS, or Android.
Start a practice session for PCEP: Certified Entry-Level Python Programmer (PCEP-30-02) below, or open the full app in a new tab. For the best experience, open the full app in a new tab and navigate with swipes/gestures or the mouse wheel—just like on your phone or tablet.
Open Full App in a New TabA small set of questions is available for free preview. Subscribers can unlock full access by signing in with the same app-family account they use on web and mobile.
Prefer to practice on your phone or tablet? Download the IT Mastery – AWS, Azure, GCP & CompTIA exam prep app for iOS or IT Mastery app on Google Play (Android) and use the same IT Mastery account across web and mobile.
Free diagnostic: Try the 30-question PCEP-30-02 full-length practice exam before subscribing. Use it as one entry-level Python baseline, then return to IT Mastery for timed mocks, topic drills, explanations, and the full PCEP question bank.
| Domain | Weight |
|---|---|
| Computer Programming and Python Fundamentals | 18% |
| Control Flow - Conditional Blocks and Loops | 29% |
| Data Collections - Tuples, Dictionaries, Lists, and Strings | 25% |
| Functions and Exceptions | 28% |
Use these filters when a simple-looking snippet has multiple tempting answers:
break, continue, and else behavior.| Day | Practice focus |
|---|---|
| 7 | Take the free full-length diagnostic and tag misses by fundamentals, control flow, collections, or functions/exceptions. |
| 6 | Drill variables, operators, literals, input/output, conversions, and basic expression behavior. |
| 5 | Drill if, loops, truthiness, ranges, break, continue, and nested control flow. |
| 4 | Drill strings, lists, tuples, dictionaries, slicing, membership, and mutability. |
| 3 | Drill functions, parameters, returns, simple scope, exceptions, and traceback interpretation. |
| 2 | Complete a timed mixed set and explain the exact Python behavior behind every miss. |
| 1 | Review weak tracing patterns; avoid trying to learn new Python topics late. |
If several unseen mixed attempts are above roughly 75% and you can trace the Python behavior behind each answer, you are likely ready. More practice should build confidence and speed, not turn beginner snippets into memorized output.
Use these child pages when you want focused IT Mastery practice before returning to mixed sets and timed mocks.
Need concept review first? Read the PCEP-30-02 Cheat Sheet on Tech Exam Lexicon, then return here for timed mocks, topic drills, and full IT Mastery practice.
These are original IT Mastery practice questions aligned to the live PCEP-30-02 route and the main blueprint areas shown above. Use them to test readiness here, then continue in IT Mastery with mixed sets, topic drills, and timed mocks.
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student wants this program to add only positive numbers. Negative numbers should be ignored, and the loop should keep checking the rest of the list. Which change is the best fix?
numbers = [4, -2, 7, -1, 3]
total = 0
for n in numbers:
if n < 0:
pass
total += n
print(total)
pass with continue.pass with break.if n < 0: to if n > 0:.total += n so it is inside the if block.Best answer: A
Explanation: The right fix is to use continue inside the if n < 0 block. Unlike pass, it skips the rest of the current iteration, so negative numbers are not added while the loop still processes later values. continue is used in loops when you want to skip the remaining statements for the current item and go straight to the next iteration. In this program, pass does nothing, so after Python checks if n < 0:, it still runs total += n. That means negative numbers are added anyway.
By replacing pass with continue, the loop behaves as intended:
n is negative, Python skips total += n.total += n and are added.The key difference is that continue skips one iteration, while other changes either stop the loop or change the logic incorrectly.
Topic: Block 4: Functions and Exceptions
Consider this code:
def to_number(text):
return int(text)
def show(values):
for item in values:
try:
number = to_number(item)
except ValueError:
print("skip")
continue
print(number)
print("done")
show(["5", "x", "2"])
Which statement correctly describes the control flow when item is "x"?
to_number() handles the ValueError, so show() prints 0 and keeps looping.ValueError propagates to show(), and continue ends the whole show() function.ValueError propagates to show(), skip is printed, and the loop continues with "2".ValueError stops the program before show() can run its except block.Best answer: C
Explanation: An exception raised in a function does not stay there if that function has no matching except block. Here, int("x") raises ValueError inside to_number(), then control jumps to show(), where the except ValueError block prints skip and continue resumes the for loop. Exception propagation means Python immediately leaves the current function when an exception is raised and no local handler matches it. In this code, int("x") raises ValueError inside to_number(). Because to_number() has no try-except, that call ends at once and Python looks in the caller, show(), for a matching handler.
except ValueError in show() catches the error.print("skip") runs.continue skips print(number) for that iteration and moves to the next item.So the loop still processes "2", and print("done") runs after the loop. The key point is that continue affects only the loop iteration, not the whole function.
Topic: Block 1: Computer Programming and Python Fundamentals
A beginner runs the following program. Which statement correctly describes the control flow?
value = 2 + 3 * 2 ** 2
if value == 20:
print("first")
elif value == 14:
print("second")
else:
print("third")
elif block runs and prints second.if block runs and prints first.else block runs and prints third.TypeError.Best answer: A
Explanation: Python applies operator precedence before choosing a branch. In 2 + 3 * 2 ** 2, exponentiation happens first, then multiplication, then addition, so the result is 14; that makes the if test false and the elif test true. This question tests operator binding in an arithmetic expression that feeds an if/elif/else decision. Python evaluates ** before *, and * before +.
2 ** 2 becomes 43 * 4 becomes 122 + 12 becomes 14So value is 14. The first condition, value == 20, is false. The next condition, value == 14, is true, so Python enters the elif block and prints second.
The closest mistake is to act as if addition happened before multiplication, but that would require parentheses.
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A beginner tests a helper function that changes a list and returns a sorted version. What is printed?
def organize(labels):
labels.append("x")
labels.insert(1, "y")
del labels[2]
return sorted(labels)
items = ["b", "a", "c"]
result = organize(items)
print(items)
print(result)
['b', 'c', 'x', 'y']; second: ['b', 'c', 'x', 'y']['b', 'y', 'a', 'x']; second: ['a', 'b', 'x', 'y']['b', 'y', 'c', 'x']; second: ['b', 'c', 'x', 'y']['b', 'a', 'c']; second: ['b', 'c', 'x', 'y']Best answer: C
Explanation: append(), insert(), and del change the original list object passed to the function, so items is modified before it is printed. sorted() is different because it creates and returns a new sorted list instead of replacing items. In this function, the parameter labels refers to the same list object as items, so list-mutating operations affect the original list. Starting with ['b', 'a', 'c'], append('x') gives ['b', 'a', 'c', 'x']. Then insert(1, 'y') places 'y' at index 1 and shifts the later elements right, producing ['b', 'y', 'a', 'c', 'x']. Next, del labels[2] removes 'a', leaving ['b', 'y', 'c', 'x']. Finally, sorted(labels) returns a new list, ['b', 'c', 'x', 'y'], but it does not change items in place. So the first print() shows the mutated original list, and the second print() shows the separate sorted result. The key idea is the difference between mutation and returning a new list.
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student expects the function to ignore negative numbers. What does this program display?
def total_values(values):
total = 0
for v in values:
if v < 0:
pass
total += v
return total
print(total_values([2, -1, 3]))
52None4Best answer: D
Explanation: pass is only a placeholder statement; it does not skip the current loop iteration or stop the loop. Because total += v runs on every iteration, the function adds 2, -1, and 3, giving 4. The core concept is that pass is a no-op statement. When Python reaches pass, nothing special happens, and execution simply continues with the next line.
In this function, the line total += v is outside the if block, so it runs for every value in the list, including -1.
total = 02 - total = 2-1, execute pass, then add -1 - total = 13 - total = 4If the goal were to skip negative numbers, the loop would need continue, not pass.
Topic: Block 4: Functions and Exceptions
A beginner wants parse_count() to do only the conversion, and main() to handle bad data for the whole program. When main() runs, what is printed? Each option shows the printed lines in order.
def parse_count(text):
print("parse")
return int(text)
def main():
print("begin")
try:
count = parse_count("cat")
print(count * 2)
except ValueError:
print("invalid")
print("end")
main()
begin | invalid | endbegin | parse | invalid | endbegin | parse | endbegin | parse | invalidBest answer: B
Explanation: The exception is raised inside parse_count(), but it is handled by the caller, main(). So begin prints first, parse prints before the failed conversion, invalid is printed by the except block, and end prints afterward. This tests exception propagation across a function boundary. parse_count() prints parse and then tries int(text). Because "cat" is not a valid integer, int() raises ValueError before the function can return a number, so print(count * 2) never runs.
The important boundary choice is that the exception is not handled inside parse_count(); it is delegated to main(). That means the error travels back to the caller, where except ValueError: prints invalid. After a handled exception, execution continues with the next statement after the try/except, so end is printed too.
A common beginner mistake is forgetting that parse is printed before the conversion fails.
Topic: Block 1: Computer Programming and Python Fundamentals
A student reviews this Python program and counts only executable instructions. Comments and blank lines should not be counted.
# start
def double(n):
# multiply by 2
return n * 2
value = 4
print(double(value))
How many executable instructions are in the program?
Best answer: A
Explanation: The program contains four executable instructions. The two lines beginning with # are comments, and the empty line is a blank line, so none of those are counted. In Python, comments and blank lines are ignored by the interpreter. Executable instructions are statements such as a function definition, a return statement, an assignment, and a function call.
In this program, the executable instructions are:
def double(n):return n * 2value = 4print(double(value))That gives a total of four. A common mistake is to ignore the def line or to count a comment as if it were an instruction.
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A beginner stores product codes in a tuple and prints one item plus a slice.
codes = ("AA", "BB", "CC", "DD", "EE")
print(codes[2], codes[1:4])
What is displayed?
CC ('BB', 'CC', 'DD', 'EE')('CC',) ('BB', 'CC', 'DD')BB ('CC', 'DD', 'EE')CC ('BB', 'CC', 'DD')Best answer: D
Explanation: Tuple indexing is zero-based, so codes[2] is the third item: CC. Tuple slicing includes the start index and excludes the stop index, so codes[1:4] becomes ('BB', 'CC', 'DD'). With tuples, a single index returns one element, while a slice returns a new tuple. Python counts from zero, so index 0 is AA, index 1 is BB, and index 2 is CC. That makes codes[2] a single string, not a one-item tuple.
For codes[1:4], Python starts at index 1 and stops before index 4. So it includes indices 1, 2, and 3, which are BB, CC, and DD. The print() call displays its two arguments separated by a space, giving CC ('BB', 'CC', 'DD').
The closest mistake is treating the slice stop value as inclusive, but Python slices do not include the stop position.
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student wants to print how many times the inner loop runs for each outer-loop iteration, but the second line is too large.
count = 0
for row in range(2):
for col in range(3):
count += 1
print(row, count)
The student expects this output because the inner loop should run 3 times for each row:
0 3
1 3
Which change is the best fix?
range(2).count inside the outer loop before the inner loop starts.count inside the inner loop.Best answer: B
Explanation: In a nested loop, the inner loop finishes all its iterations for each single outer-loop iteration. Here it runs 3 times for row = 0 and 3 times again for row = 1, but count is never reset, so the totals accumulate to 3 and then 6. The key idea is that the inner loop runs completely once for every pass of the outer loop. With range(2), the outer loop has 2 iterations, and with range(3), the inner loop has 3 iterations during each of those outer iterations.
Because count is created before the outer loop, it keeps its value from the previous row. That means:
count becomes 3If the goal is to count inner-loop executions separately for each outer-loop iteration, reset count at the start of each outer-loop pass. Changing the ranges or moving the print statement does not fix the counting logic.
Topic: Block 4: Functions and Exceptions
Running this code with report(8, 0) stops with ZeroDivisionError: division by zero instead of printing a friendly message. What is the best fix?
def get_ratio(a, b):
return a / b
def report(a, b):
try:
print(get_ratio(a, b))
except ValueError:
print("Bad input")
report(8, 0)
return before print(get_ratio(a, b)).ZeroDivisionError in report.except ValueError with except TypeError./ to // in get_ratio.Best answer: B
Explanation: get_ratio raises the exception, but it happens while report is inside its try block. Because only matching handlers catch propagated exceptions, except ValueError does not handle ZeroDivisionError. This is an exception propagation problem. The division by zero occurs inside get_ratio, but Python does not require the same function to handle the exception. If a called function raises an exception and does not catch it, the exception travels back to the caller.
report enters the try block.get_ratio(8, 0) raises ZeroDivisionError.report.except clause must name the same exception type to handle it.Here, except ValueError does not match, so the program stops with an uncaught exception. The key takeaway is that exceptions can be handled in a different function, but only by a matching except block.
Topic: Block 1: Computer Programming and Python Fundamentals
A student writes this small Python program that works with a list and a string. How many executable instructions does it contain?
items = ["pen", "pencil"]
# choose the first item
first = items[0] # store value
label = "#1 item"
print(first)
print(label)
Best answer: C
Explanation: This program has five executable instructions. Python runs the three assignment statements and the two print() calls, while the full comment line and blank lines are ignored. In Python, executable instructions are statements the interpreter actually runs, such as assignments and function calls. In this snippet, items = [...], first = items[0], label = "#1 item", print(first), and print(label) are all executable. The line starting with # is only a comment, so Python skips it, and blank lines have no effect.
A common beginner mistake is to treat any line containing # as a comment. That is not how Python works:
# is a comment.# still runs; the rest of that line is just an inline comment.# inside quotes is part of a string literal.So the deciding idea is to count statements Python executes, not every visible line.
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A beginner wants move_x((2, 5)) to return (3, 5), but this function fails:
def move_x(point):
point[0] = point[0] + 1
return point
Which change correctly fixes the function?
global point inside the function before the assignment.point to a list, update index 0, and return a new tuple.return point with print(point) inside the function.move_x(point=(2, 5)) instead of move_x((2, 5)).Best answer: B
Explanation: The problem is tuple immutability. Inside the function, point[0] = ... tries to change an existing tuple element, which raises TypeError, so the fix is to create and return a new tuple instead. In Python, tuples cannot be changed after they are created. When the function receives (2, 5), the parameter point refers to that tuple, and point[0] = point[0] + 1 attempts an illegal item assignment. That causes a TypeError.
A simple fix is to create new data:
This keeps the function’s purpose the same: it returns updated coordinates without trying to mutate the original tuple. Changing scope with global, changing how the argument is passed, or printing instead of returning does not solve tuple immutability.
Topic: Block 2: Control Flow - Conditional Blocks and Loops
What is printed by this program?
def count_items(rows):
total = 0
for row in rows:
for value in row:
if value == 0:
break
total += 1
return total
print(count_items([[1, 2, 0, 3], [4, 0, 5], [6, 7]]))
2.7.SyntaxError.5.Best answer: D
Explanation: In Python, break stops only the nearest enclosing loop. Here it stops the inner for value in row loop when 0 is found, but the outer loop still moves to the next row, so the final count is 5. The key concept is that break terminates only the loop it is directly inside. In this function, break belongs to the inner loop that scans values in one row, so reaching 0 stops scanning that row only.
[1, 2, 0, 3], the function counts 1 and 2, then stops that row.[4, 0, 5], it counts 4, then stops that row.[6, 7], there is no 0, so it counts both values.That gives a total of 2 + 1 + 2 = 5. A return would end the whole function, but break only exits the nearest loop.
Topic: Block 4: Functions and Exceptions
A beginner writes this function to repeat a greeting. Which call raises a TypeError because a required argument is missing?
def greet(name, times, punctuation="!"):
print((name + punctuation) * times)
greet("Ana", 2)greet(name="Ana", times=2)greet("Ana", 2, punctuation="?")greet("Ana", punctuation="?")Best answer: D
Explanation: A required parameter is one without a default value. In this function, name and times are required, so a call that skips times is invalid and raises TypeError. In Python, every parameter without a default value must receive an argument when the function is called. In greet(name, times, punctuation="!"), name and times are required parameters, while punctuation is optional because it has a default value.
A function call can provide arguments positionally, by keyword, or by mixing both forms, as long as each required parameter gets exactly one value. The call using greet("Ana", punctuation="?") provides name and punctuation, but it never provides a value for times. Python therefore stops the call and raises TypeError.
The key check is simple: count the required parameters and make sure each one is supplied.
Topic: Block 1: Computer Programming and Python Fundamentals
A beginner expects this program to print the sum of all values in nums.
nums = [2, 4, 6]
total = 0
for n in nums:
total = n
print(total)
Which option best describes the defect?
SyntaxError.12.6.Best answer: D
Explanation: This is a semantic defect. Python can tokenize, parse, and run the code, but the loop assigns each item to total instead of adding, so the final output is 6 rather than the intended sum 12. A lexical defect means Python cannot form valid tokens, and a syntactic defect means the tokens do not follow Python grammar. Neither happens here: the names, numbers, brackets, colon, and indentation are all valid, so the program runs.
During execution, total changes like this:
0246Because total = n replaces the old value each time, the loop finishes with the last list element, not the sum. Since the stated goal is to add all values, the problem is in the program’s meaning or logic, so it is a semantic defect. The closest distractor is the syntax claim, but no parsing error occurs.
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
What happens when this Python 3 code runs?
a = [1, 2, 3]
b = (1, 2, 3)
a[1] = 8
b[1] = 8
print(a)
print(b)
TypeError at b[1] = 8.[1, 8, 3] and (1, 8, 3).[1, 8, 3] and (1, 2, 3).SyntaxError because tuples cannot be indexed that way.Best answer: A
Explanation: A list can be changed after it is created, but a tuple cannot. The assignment to a[1] succeeds, then b[1] = 8 causes a TypeError, so the program stops before either print() call runs. The key concept is mutability. In Python, a list created with square brackets like [1, 2, 3] is mutable, so replacing a[1] with 8 is valid. A tuple created with parentheses like (1, 2, 3) is immutable, so trying to assign a new value to b[1] is not allowed.
a[1] = 8 works because a is a list.b[1] = 8 fails because b is a tuple.print() calls are never reached.A common beginner rule is: use a list when values may change, and use a tuple when values should stay fixed.
Topic: Block 2: Control Flow - Conditional Blocks and Loops
Consider this function:
def locate(target, data):
i = 0
while i < len(data):
if data[i] == target:
break
i += 1
else:
return "missing"
return "found"
Which call makes the else clause run?
locate(3, [1, 2, 3])locate(1, [1, 2, 3])locate(2, [2, 5, 7])locate(4, [1, 2, 3])Best answer: D
Explanation: A while loop’s else clause runs only if the loop finishes normally, not if it stops because of break. In this function, that happens only when the target value is not found in the list. In Python, else attached to a while loop executes when the loop condition becomes false without a break. Here, the function checks list elements one by one. If it finds target, it uses break, which skips the else block and then returns "found".
If the target is absent, i keeps increasing until i < len(data) becomes false. That is normal loop termination, so the else block runs and returns "missing".
The key idea is that while ... else is about whether the loop ended naturally or was interrupted by break, not about whether the loop ran zero or many times.
Topic: Block 4: Functions and Exceptions
This code is reused in a small console app. When the user enters ten, the program ends with an uncaught ValueError.
For this menu action only, the program should print Invalid number and stop cleanly. parse_count() should stay reusable so other callers can handle bad input differently.
def parse_count(text):
return int(text)
def get_total():
text = input("How many items? ")
count = parse_count(text)
print("Total:", count * 2)
get_total()
What is the best fix?
ValueError in get_total() around parse_count(text).ValueError in parse_count() and return 0.TypeError in get_total() around count * 2.ValueError around the def parse_count(text): line.Best answer: A
Explanation: The best place to handle this exception is the caller that knows what should happen next. Here, get_total() knows the required behavior for this menu action, while parse_count() should remain a simple conversion function that lets invalid input propagate. This is an exception propagation question. int(text) raises ValueError when the text cannot be converted to an integer, and parse_count() currently just passes that exception up to its caller.
The best boundary for handling it is get_total() because that function knows the required response: print Invalid number and stop this action cleanly. Keeping the try/except there also preserves parse_count() as a reusable helper, so other parts of the program can choose a different response if they need one.
parse_count() should convert text to an integer.get_total() should decide what to do when conversion fails.Returning 0 inside the conversion function would hide the real error and change the program’s meaning.
Topic: Block 1: Computer Programming and Python Fundamentals
A student stores status values in a list:
status = ["True", True, "False", "TRUE"]
Which expression refers to the Boolean literal True, not to a string value?
status[0]status[2]status[1]status[3]Best answer: C
Explanation: In Python, True and False are Boolean literals only when written without quotes. Quoted values like "True" or "TRUE" are strings. In this list, only the second element is the Boolean True. In Python, True and False are special Boolean literals, but only when they appear exactly as True or False and are not inside quotes. Any quoted value is a string, even if its text looks like a Boolean value.
In the list shown, indexing starts at 0:
status[0] is the string "True"status[1] is the Boolean Truestatus[2] is the string "False"status[3] is the string "TRUE"The key point is that quotes determine that a value is text, not Boolean data.
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A beginner writes this function to copy a nested list:
def clone(data):
return data[:]
scores = [[10, 20], [30, 40]]
backup = clone(scores)
backup[0][1] = 99
backup[1] = [50, 60]
print(scores)
print(backup)
What is the output?
[[10, 99], [30, 40]] then [[10, 99], [50, 60]][[10, 20], [30, 40]] then [[10, 99], [50, 60]][[10, 99], [50, 60]] then [[10, 99], [50, 60]][[10, 20], [50, 60]] then [[10, 99], [50, 60]]Best answer: A
Explanation: The function returns a shallow copy of the outer list, not a full recursive copy of all nested lists. Changing an element inside a shared inner list affects both variables, but replacing one whole inner list in the copy affects only the copy. In this code, clone() returns data[:], which creates a new outer list. However, the nested lists inside it are still the same objects referenced by scores. That means backup[0][1] = 99 changes the shared first inner list, so both scores and backup show 99 there.
When backup[1] = [50, 60] runs, it does something different: it replaces the second element of the outer copied list with a brand-new inner list. Since the outer lists are separate objects, that reassignment affects only backup, not scores.
A shallow copy duplicates only the top level; it does not recursively clone nested lists.
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student writes this placeholder loop in Python 3:
count = 0
while count < 3:
# add logic later
print(count)
What happens when the program is run?
0.3.IndentationError before execution.Best answer: C
Explanation: The loop body is effectively empty because a comment is not a Python statement. After while count < 3:, Python expects an indented block, so the program stops with IndentationError before print(count) can run. In Python, a while or if block must contain at least one real statement in its indented body. Comments and blank lines do not satisfy that requirement, so the parser sees this while block as empty. Because of that, the file is rejected with IndentationError before any normal execution happens.
If you want a placeholder block, use pass:
while count < 3:
pass
That makes the code syntactically valid. In this question, the decisive issue is the empty block without pass, not what the loop would do afterward.
Topic: Block 4: Functions and Exceptions
A student is reviewing these user-defined functions in a practice program:
def log_total(total):
print(total)
def show_items(items):
for item in items:
print(item)
def steps_left(n):
if n > 0:
print(n)
steps_left(n - 1)
def start():
steps_left(3)
Which function is recursive?
log_totalsteps_leftshow_itemsstartBest answer: B
Explanation: A recursive function calls itself. In the code, steps_left contains a call to steps_left(n - 1), so it repeats the same function with a smaller value until the condition is no longer true. Recursion means a function solves a task by calling itself, usually with a smaller input and a stopping condition. In this example, steps_left checks whether n > 0; if that condition is true, it prints the current value and then calls steps_left(n - 1). That self-call is what makes the function recursive.
n is not greater than 0, no new self-call is made.n is positive, the function runs again with a smaller value.The other functions are not recursive because they do not call themselves. The closest distractor is start, but it calls a different function, not itself.
Topic: Block 1: Computer Programming and Python Fundamentals
A student copied one helper function from a word processor into a Python file. Which definition contains a lexical issue caused by an invalid character?
def add(a, b): return a + bdef show(name='Bob'): print(name)def greet(name): return “Hi, ” + namedef countdown(n): return 0 if n == 0 else countdown(n - 1)Best answer: C
Explanation: The function using “Hi, ” is the only one with invalid characters. Python accepts straight single or double quotes for strings, but smart quotes from word processors cause a lexical error before normal function processing begins. A lexical issue happens when Python cannot form valid tokens from the source code. Here, the problem is the typographic smart quotes around Hi, . Python string literals must use straight single quotes or straight double quotes. Because “ and ” are different Unicode characters, Python reports an invalid character error before it can evaluate the function definition. The other snippets are valid at the lexical level: one returns a sum, one prints and therefore returns None implicitly, and one uses valid recursion. When you are asked to spot a lexical issue, focus first on invalid characters, malformed literals, or broken tokens rather than on whether the function’s logic is useful.
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A student wants to check whether field is one of a dictionary’s keys, but the program stops with TypeError: argument of type 'builtin_function_or_method' is not iterable.
user = {"name": "Mia", "role": "admin"}
field = "role"
if field in user.keys:
print("found")
else:
print("missing")
What is the best fix?
in with == in the conditionkeys() in the condition: if field in user.keys():user.values() instead of user.keysfield in list() before the ifBest answer: B
Explanation: The error happens because user.keys refers to the method itself, not the result of calling it. Using user.keys() returns the dictionary’s keys, so the membership test works correctly. keys() is a dictionary method. When you write user.keys without parentheses, Python treats it as a method object, not as the collection of keys. The in operator can test membership in an iterable such as the dict_keys view returned by user.keys(), but it cannot search inside the method object itself.
So this line must call the method:
if field in user.keys():
Then Python checks whether "role" is one of the dictionary’s keys. The key point is that inspecting dictionary keys with keys() requires the parentheses.
Use this map after the sample questions to connect individual items to the Python syntax, data type, control-flow, function, and module decisions these practice samples test.
flowchart LR
S1["Read code stem"] --> S2
S2["Resolve syntax names and types"] --> S3
S3["Trace control flow and expressions"] --> S4
S4["Apply function or module rule"] --> S5
S5["Predict output or exception"] --> S6
S6["Select exact result"]
| Cue | What to remember |
|---|---|
| Trace exactly | Follow indentation, branch order, loop updates, and operator precedence carefully. |
| Types | Know strings, numbers, booleans, lists, tuples, dictionaries, and mutability basics. |
| Functions | Track parameters, return values, default arguments, and local scope. |
| Exceptions | Recognize common runtime errors and when code does not reach later lines. |
| Modules | Know imports, standard-library basics, and name resolution. |