Free Python Institute PCEP Practice Exam: Entry-Level Python Programmer
Try 30 free Python Institute PCEP - Certified Entry-Level Python Programmer (PCEP-30-02) questions across the exam domains, with explanations, then continue with IT Mastery practice.
This free full-length Python Institute PCEP practice exam includes 30 original IT Mastery questions across the exam domains.
These are original IT Mastery practice questions. They are not official Python Institute questions, copied live-exam content, or exam dumps. Use them to preview question style and explanation depth before continuing with mixed sets, topic drills, and timed mocks in IT Mastery.
Count note: this page uses the full-length practice count maintained in the Mastery exam catalog. Some certification vendors publish total questions, scored questions, duration, or unscored/pretest-item rules differently; always confirm exam-day rules with the sponsor.
Try the IT Mastery web app for a richer interactive practice experience with mixed sets, timed mocks, topic drills, explanations, and progress tracking.
Exam snapshot
- Practice target: Python Institute PCEP
- Practice-set question count: 30
- Time limit: 40 minutes
- Practice style: mixed-domain diagnostic run with answer explanations
Full-length exam mix
| Domain | Weight |
|---|---|
| Block 1: Computer Programming and Python Fundamentals | 18% |
| Block 2: Control Flow - Conditional Blocks and Loops | 29% |
| Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings | 25% |
| Block 4: Functions and Exceptions | 28% |
Use this as one diagnostic run. IT Mastery gives you timed mocks, topic drills, analytics, code-reading practice where relevant, and interactive practice.
Practice questions
Questions 1-25
Question 1
Topic: Block 4: Functions and Exceptions
A beginner wants this program to print Hello Mia three times, but the last line fails.
def repeat_msg(name, count):
for _ in range(count):
print("Hello", name)
repeat_msg("Mia")
Without changing the function definition, which change best fixes the program?
Options:
A.
repeat_msg(name="Mia")B.
repeat_msg(3, "Mia")C.
repeat_msg("Mia", 3)D.
repeat_msg()
Best answer: C
Explanation: repeat_msg has two required parameters: name and count. The call currently passes only one value, so the fix is to supply the missing second argument, such as 3.
In Python, a function call must provide a value for every required parameter unless that parameter has a default value. Here, repeat_msg(name, count) defines two required parameters, and neither has a default. That means repeat_msg("Mia") raises a TypeError because count is missing.
The program is supposed to print the same greeting three times, so the call needs both pieces of information:
- the name:
"Mia" - the repeat count:
3
So the working call is repeat_msg("Mia", 3). Calls that still omit count remain invalid, and swapping the argument order sends the wrong values into the parameters. Match the function call to the function definition exactly.
- The option with
3first swaps the values, socountreceives"Mia", which breaksrange(count). - The option using only
name="Mia"still leaves the requiredcountargument missing. - The empty call is also invalid because it omits both required arguments.
Question 2
Topic: Block 4: Functions and Exceptions
What happens when this Python 3 code runs?
def show(message):
print(message)
word = "Hi"
show(word, "!")
Options:
A. It raises
TypeErrorB. It prints
Hi!C. It raises
NameErrorD. It prints
Hi
Best answer: A
Explanation: message is the only parameter in the function definition, so show() accepts one positional input. The call supplies two arguments, word and "!", so Python raises TypeError before the function body runs.
A parameter is the name listed in a function definition, and an argument is the actual value or expression supplied in the function call. In def show(message):, message is the single parameter, so the function expects exactly one positional argument.
In show(word, "!"), Python supplies two arguments:
- the value stored in
word - the string
"!"
Because the number of arguments does not match the number of parameters, Python stops with a TypeError. The print(message) line is never executed.
A common mistake is to think the function will print both values, but argument checking happens before the function body starts.
- Expecting
Hi!fails becauseshow()is rejected before it can print anything. - Expecting
Hifails because Python does not ignore the extra argument in a normal function call. - Expecting
NameErrorfails becausewordis defined; the problem is the argument count.
Question 3
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student wants this program to print Not found only when target is absent from the list. With the current code, nothing is printed for the shown values. What is the best fix?
numbers = [1, 3, 5]
target = 4
for n in numbers:
if n != target:
break
else:
print("Not found")
Options:
A. Replace
breakwithcontinueB. Delete the
elseand print after the loopC. Move
print("Not found")inside the loopD. Change the condition to
if n == target:
Best answer: D
Explanation: In Python, a loop else block runs only if the loop finishes without break. The current code breaks on the first non-matching value, so the search stops too early and the else block is skipped.
The core concept is Python’s for ... else behavior: the else block is tied to the loop, and it runs only when the loop ends normally. If break executes, the else block does not run.
Here, if n != target: is backwards for a search. Since the first value (1) is not equal to 4, the loop breaks immediately. The loop never finishes checking the whole list, so print("Not found") is skipped.
for n in numbers:
if n == target:
break
else:
print("Not found")
This pattern searches the list and uses else only when no match was found.
- Replacing
breakwithcontinuekeeps the loop running, but theelseblock would still run even if the target exists. - Printing
Not foundinside the loop can happen after the first non-match, before all items are checked. - Printing after the loop would show
Not foundevery time, including when a match was found.
Question 4
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A student wants this program to print bAnana by changing only the character at index 1 and keeping text as a string:
text = "banana"
text[1] = "A"
print(text)
Which replacement for the broken assignment line is the best fix?
Options:
A.
text = text[:1] + "A" + text[2:]B.
text = "A" + text[1:]C.
text[1:2] = "A"D.
text = text.replace("a", "A")
Best answer: A
Explanation: Strings are immutable in Python, so you cannot assign directly to a character position. The correct fix creates a new string by joining the part before index 1, the new character, and the part after index 1.
A Python string cannot be changed in place after it is created. That is why assigning to text[1] fails: indexing lets you read a character, but not overwrite it. To change one character, you must build a new string.
For this case:
text[:1]gives"b""A"is the replacement charactertext[2:]gives"nana"
Combining those parts produces "bAnana". This keeps text as a string and changes only the character at the required position. A tempting alternative is using replace(), but that works by matching values, not by targeting one index.
replace("a", "A")changes every matchinga, so it does not target only index1."A" + text[1:]replaces the first character, not the second one.- Assigning to
text[1:2]still tries to modify the existing string, which is not allowed.
Question 5
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student wants this program to print 3, 2, 1 and then stop, but it keeps printing larger numbers and never ends. What is the best cause of the problem?
count = 3
while count > 0:
print(count)
count += 1
Options:
A.
count += 1movescountaway from 0, so the condition stays true.B. The loop needs a
breakstatement afterprint(count).C.
print(count)should be outside the loop.D. The condition should be
count >= 0.
Best answer: A
Explanation: The loop condition is count > 0, but count starts at 3 and is increased each time. Tracing the values gives 3, 4, 5, and so on, so the condition never becomes false and the loop is infinite.
To trace a while loop, follow the control variable from its initial value through each update. Here, count starts at 3, and the loop runs while count > 0. Inside the loop, count += 1 makes the value larger, not smaller, so every new value still satisfies the condition.
- Start:
countis 3, so the loop begins. - After one pass:
countbecomes 4. - After another pass:
countbecomes 5. - The same pattern continues indefinitely.
A while loop stops only when its condition becomes false. If the goal is to count down to 0, the update must move toward 0, such as count -= 1.
- Changing the condition to
count >= 0does not help, because 3, 4, 5, and later values still satisfy it. - Moving
print(count)outside the loop changes the output behavior, but it does not fix the loop control problem. - Adding
breakcould force an exit, but it does not identify the actual bug in the loop update.
Question 6
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A ticket-check program stores valid ticket IDs in a list.
ticket_id = "B12"
valid_ids = ["A10", "B12", "C07"]
Which TWO expressions correctly evaluate to True when ticket_id is present in valid_ids? Select TWO.
Options:
A.
ticket_id in valid_idsB.
ticket_id not in valid_idsC.
valid_ids in ticket_idD.
ticket_id == valid_idsE.
valid_ids[ticket_id]F.
bool(ticket_id in valid_ids)
Correct answers: A and F
Explanation: Python uses in to check whether a value appears as an element in a list. Both the plain membership expression and the same expression wrapped in bool() correctly return True here because "B12" is one of the items in valid_ids.
The core concept is list membership testing with in. In Python, the searched value goes on the left and the list goes on the right: value in some_list. That expression already evaluates to a Boolean value.
In this scenario, ticket_id is "B12", and valid_ids contains "B12", so the membership test is True.
ticket_id in valid_idsis the standard membership check.bool(ticket_id in valid_ids)is also correct because it converts an already Boolean result toTrueorFalse.
Common mistakes are reversing the operands, comparing a single value to the whole list, or using not in, which checks the opposite condition.
- Reversed operands fails because the value should be checked inside the list, not the list inside the string.
- Whole-list comparison fails because comparing one string to an entire list does not test membership.
- Opposite condition fails because
not inisTrueonly when the value is absent. - Index confusion fails because list indexing uses integer positions, not a membership test string.
Question 7
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student is drafting a function and wants to leave one branch unfinished for now. The code must stay valid, and the later print() and return lines should still run normally.
def check_age(age):
if age < 0:
# validation will be added later
???
print("checked")
return age
Which statement should replace ????
Options:
A. continue
B. pass
C. return
D. break
Best answer: B
Explanation: pass is Python’s placeholder statement for an empty block. It satisfies the if body requirement without exiting the function or changing what runs next.
Python requires an indented statement after an if. When you want that block to exist for now but do nothing, use pass. In this function, pass lets the if age < 0 branch stay empty while control flow continues normally to print("checked") and then return age.
passdoes nothing.- It keeps the code syntactically correct.
- It does not stop the function or skip later statements.
The closest wrong choice is return, because it is valid inside a function, but it would end the function early instead of acting as a placeholder.
returnchanges the function’s flow by exiting immediately.continuecan be used only inside a loop, not in this standaloneifblock.breakalso requires a loop and cannot be used here.
Question 8
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student wants to count all (row, col) pairs in a 3 x 2 grid, but the update line is indented as shown.
count = 0
for row in range(3):
for col in range(2):
print(row, col)
count += 1
print("count =", count)
What is the final line printed?
Options:
A. It raises
IndentationError.B. It prints
count = 3.C. It prints
count = 6.D. It prints
count = 2.
Best answer: B
Explanation: Indentation decides which loop controls a statement. Here, count += 1 is outside the inner loop but inside the outer loop, so it runs once for each row. Since there are 3 outer iterations, the final line is count = 3.
In nested loops, a line runs only in the block where it is indented. The inner loop here contains only print(row, col). The line count += 1 is aligned with the inner for, so it is not part of the inner loop body.
That means this happens:
- the inner loop prints two
(row, col)pairs for one row - then
countincreases by 1 - this repeats for 3 rows
So count changes from 0 to 3. To get 6, the increment would need to be indented one level deeper so it runs for every (row, col) pair.
- The option claiming
count = 6assumes the increment is inside the inner loop. - The option claiming
count = 2confuses the number of columns with the number of times the update runs. - The option claiming
IndentationErroris incorrect because the code is indented validly; the problem is logical, not syntactic.
Question 9
Topic: Block 4: Functions and Exceptions
A beginner is troubleshooting why this program does not end with an uncaught exception. What is the output?
def calc():
return 10 / 0
try:
calc()
print("try")
except ZeroDivisionError:
print("except")
print("end")
Options:
A. It ends with an uncaught
ZeroDivisionError.B. It prints only
except.C. It prints
exceptand thenend.D. It prints
tryand thenend.
Best answer: C
Explanation: The function call raises ZeroDivisionError inside the caller’s try block. That exception is caught by the matching except, so print("try") is skipped and execution continues to the final print("end").
When calc() runs, 10 / 0 raises ZeroDivisionError. Because that call happens inside the try block, control immediately leaves the rest of the try block, so print("try") never runs.
The caller has a matching except ZeroDivisionError, so the exception is handled there and print("except") runs. After the exception is handled, the program continues normally with the next statement after the try/except, so it also prints end.
An uncaught traceback would appear only if there were no matching handler in the caller.
- The option claiming
tryis printed fails because execution stops thetryblock as soon ascalc()raises. - The option claiming only
exceptis printed fails because the program continues after a handled exception. - The traceback option fails because the caller explicitly catches
ZeroDivisionError.
Question 10
Topic: Block 2: Control Flow - Conditional Blocks and Loops
What is printed by this code?
def check(values):
for v in values:
if v < 0:
break
else:
return "all non-negative"
return "negative found"
print(check([3, 1, 0]))
Options:
A. Nothing is printed
B. all non-negative
C. None
D. negative found
Best answer: B
Explanation: In Python, a loop else runs only when the loop finishes normally, not when it is ended by break. Here, no value in [3, 1, 0] is negative, so the function returns all non-negative and print() displays it.
The key concept is that a loop else belongs to the for loop, not to the if statement inside it. Python executes the loop else only if the loop completes all iterations without hitting break.
In this function, the values are 3, 1, and 0. For each value, the condition v < 0 is checked, and it is false every time. Because no break happens, the for loop finishes normally, so the else block runs and returns "all non-negative".
That returned string is then passed to print(). The common mistake is to think the else is paired with if, but here it is paired with the loop.
- The option with
negative foundfails because that return happens only after abreak, and no negative value appears. - The option with
Nonefails because both possible paths in the function return a string. - The option claiming nothing is printed fails because
print()always displays the function’s returned string here.
Question 11
Topic: Block 1: Computer Programming and Python Fundamentals
A beginner is testing a console checkout script. After the user enters data, the program has:
is_member = True
has_coupon = False
is_guest = False
Which TWO if conditions evaluate to True in Python?
Options:
A.
is_member and not has_coupon or is_guestB.
not is_guest or has_coupon and not is_memberC.
not is_member and has_coupon or is_guestD.
not is_member or has_coupon or is_guestE.
is_guest or has_coupon and is_memberF.
not is_guest and has_coupon or not is_member
Correct answers: A and B
Explanation: Python evaluates logical operators in this order: not, then and, then or. Using is_member = True, has_coupon = False, and is_guest = False, only two expressions reduce to True after applying that precedence.
The key concept is Python’s logical operator precedence: not is evaluated first, then and, and finally or. That means you should simplify each expression in that order instead of reading straight from left to right.
is_member and not has_coupon or is_guestbecomesTrue and True or False, thenTrue or False, so it isTrue.not is_guest or has_coupon and not is_memberbecomesTrue or False and False, thenTrue or False, so it isTrue.
All other options reduce to False because their and parts or remaining or terms are false. A common mistake is to treat or as if it were checked before and, but Python does the opposite.
- The option with
not is_member and has_coupon or is_guestfails because each part becomesFalse. - The option with
not is_guest and has_coupon or not is_memberfails becauseTrue and FalsebecomesFalse, andnot is_memberis alsoFalse. - The option with
is_guest or has_coupon and is_memberfails becausehas_couponisFalse, so both sides oforare false. - The option with
not is_member or has_coupon or is_guestfails because all three terms evaluate toFalse.
Question 12
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A student wants to label a collection as editable only when its elements can be changed in place.
collections = [(1, 2), [3, 4]]
for data in collections:
if type(data) == list:
print("editable")
else:
print("fixed")
Which statement correctly describes this control flow?
Options:
A. It raises an error because a
forloop cannot iterate over a tuple and a list in one outer list.B. It prints
fixedtheneditablebecause tuples are immutable and lists are mutable.C. It prints
editabletwice because both collections can store multiple values.D. It prints
fixedtwice because both collections are sequences.
Best answer: B
Explanation: The for loop checks each collection one at a time. A tuple is not a list, so it prints fixed first; the second item is a list, so it prints editable next.
This question combines simple control flow with the difference between tuples and lists. The loop visits the first item, (1, 2), and the condition type(data) == list is false, so the else branch prints fixed. Then it visits the second item, [3, 4], and the condition is true, so the if branch prints editable.
The important collection concept is that tuples are immutable, meaning their elements cannot be reassigned after creation. Lists are mutable, so their elements can be changed in place. Being a sequence or holding multiple values does not make a collection mutable.
The key takeaway is that both tuples and lists can be looped over, but only lists are meant for later modification.
- Multiple values is not enough; both tuples and lists can store several items, but only lists are mutable.
- Both are sequences is true, but sequence type does not mean both follow the same branch.
- Loop error is incorrect because a
forloop can iterate over an outer list containing different collection types.
Question 13
Topic: Block 4: Functions and Exceptions
What is the output of this Python 3 code?
price = 20
def show_price():
price = 15
print(price)
show_price()
print(price)
Options:
A. First
20, then20B. It raises an error because
priceis defined twiceC. First
15, then20D. First
15, then15
Best answer: C
Explanation: A variable assigned inside a function is local unless the function uses global. Here, the function prints its own local price, but the variable outside the function keeps its original value.
This code demonstrates local scope and shadowing. The name price exists outside the function with value 20, but price = 15 inside show_price() creates a separate local variable for that function call. That local variable is used only inside the function body, so the first print(price) shows 15.
After the function finishes, the local variable disappears. The outer price was never changed, so the final print(price) shows 20.
The closest wrong idea is that assigning price inside the function also updates the outer variable, but that would require using global.
- The choice with
15twice assumes the assignment inside the function changes the outer variable, which it does not. - The choice with
20twice ignores that the function prints its own localprice. - The error choice fails because Python allows a local variable to shadow a variable defined outside the function.
Question 14
Topic: Block 1: Computer Programming and Python Fundamentals
What is the exact console output of this Python 3 code?
print("A", "B", sep=":", end="*")
print("C", "D", sep="-", end="!")
Options:
A.
A:B*C D!B.
A:B*C-D!C.
A B*C-D!D.
A:B*C-D!
Best answer: D
Explanation: The first print() joins A and B with : and ends with * instead of a newline. The second print() continues on the same line, joins C and D with -, and ends with !, so the display is A:B*C-D!.
print() has two optional arguments that matter here: sep changes the text placed between multiple values, and end changes what is printed after them. In the first call, sep=":" makes the output A:B, and end="*" adds * instead of the usual newline. Because no newline is printed, the next print() starts immediately after that *.
In the second call, sep="-" makes C-D, and end="!" adds the final exclamation mark. Putting both calls together produces A:B*C-D!.
A common mistake is to think end adds its text and then still moves to a new line, but it replaces the newline.
- The two-line option assumes the first
print()still moves to a new line after printing*. - The option showing
A Bignoressep=":"in the firstprint(). - The option showing
C Dignoressep="-"in the secondprint().
Question 15
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
The program should add a new key-value pair to the user dictionary, but it uses the wrong operation. Which replacement line is the best fix?
user = {"name": "Lena", "age": 19}
user.append("city", "Paris")
print(user)
Options:
A.
user["city"] = "Paris"B.
user.update("city", "Paris")C.
user.add("city", "Paris")D.
user.insert("city", "Paris")
Best answer: A
Explanation: Dictionaries add one new entry by key assignment with square brackets. Using user["city"] = "Paris" creates the city key and stores its value in the existing dictionary.
The core concept is dictionary mutation by item assignment. In Python, the normal way to add one key-value pair is dictionary[key] = value. If the key does not exist yet, Python creates it; if it already exists, Python updates its value.
In this program, append() is the problem because that method is used with lists, not dictionaries. Replacing that line with user["city"] = "Paris" correctly adds a new entry to the dictionary without changing the rest of the code.
This is the simplest and most direct fix for adding exactly one new key-value pair.
add()is not the method used to add a single key-value pair to a dictionary.insert()is associated with list-style position-based insertion, not dictionary keys.update("city", "Paris")uses a real dictionary method name, but the arguments are in the wrong form forupdate().
Question 16
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student wants to rewrite this loop so it uses sequence iteration because item positions are never needed. The program should print each code until STOP is found, then stop.
codes = ["A12", "B34", "STOP", "C56"]
for i in range(len(codes)):
if codes[i] == "STOP":
break
print(codes[i])
Which change is correct?
Options:
A. Use
for i in codes, then testcodes[i]againstSTOPbefore printing.B. Use
for i in range(len(codes)), but testiagainstSTOPbefore printing.C. Use
for code in codes, comparecodetoSTOP, andbreakwhen it matches.D. Use
for code in codes, but replacebreakwithcontinuewhencodeisSTOP.
Best answer: C
Explanation: The loop only needs each list value, not its position, so direct iteration is the right control flow. Iterating with for code in codes keeps the same behavior: print each code in order and stop immediately when STOP is reached.
When indexes are not needed, Python code should usually iterate over the sequence elements directly with for item in sequence. In this case, the task is to examine each code value, print it, and stop when the sentinel value STOP appears. That means the loop variable should hold each string from the list, not a numeric position.
for code in codesgives each code directly.breakends the loop as soon asSTOPis found.range(len(codes))is unnecessary here because the index is never used for a separate purpose.
The closest distractor changes break to continue, but that would skip STOP and keep processing later items.
- Using
for i in codeswithcodes[i]fails because the loop variable would be a code string, not a valid list index. - Replacing
breakwithcontinuechanges the behavior from stopping atSTOPto skipping it and continuing. - Comparing the index from
range(len(codes))toSTOPfails because the index is an integer, not a list element.
Question 17
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student runs this script:
total = 0
for i in range(1, 5):
if i == 3:
break
total += i
else:
total += 10
print(total)
What is printed?
Options:
A. It prints
13B. It prints
16C. It prints
3D. It prints
6
Best answer: C
Explanation: The script prints 3. The loop adds 1 and 2, then stops when i becomes 3. In a for loop, the else block runs only if the loop finishes without break, so it does not run here.
In a for loop, break immediately ends the loop, and a loop else runs only when the loop completes all iterations normally. Here, range(1, 5) produces 1, 2, 3, and 4. The variable total starts at 0, becomes 1 after the first pass, and 3 after the second pass. On the next pass, i is 3, so the if i == 3 condition is true and break executes before total += i can run. Because the loop ended with break, the else block is skipped, so 10 is not added. The final printed value is 3. The main trap is treating loop else like a normal if/else; it depends on whether the loop was broken early.
- The
6choice assumes3is added beforebreak, butbreakhappens first. - The
13choice assumes the loopelsealways runs, butbreakprevents it. - The
16choice combines both mistakes by adding3and also adding10from the skippedelseblock.
Question 18
Topic: Block 4: Functions and Exceptions
A beginner is writing helper functions for a console app. Which TWO headers could start a valid Python function definition?
Options:
A.
function greet():B.
def class():C.
def 2greet():D.
greet def():E.
def print_total(value):F.
def greet():
Correct answers: E and F
Explanation: A valid Python function header uses def, then a legal identifier, then parentheses and a colon. greet and print_total follow those rules, so both can begin user-defined function definitions.
In Python, a user-defined function starts with a header in the form def name(parameters):. The function name must be a valid identifier: it may use letters, digits, and underscores, but it cannot start with a digit and it cannot be a reserved keyword such as class. Both greet and print_total satisfy those naming rules, and both headers use the required def keyword, parentheses, and trailing colon. Options that use a different keyword, an illegal name, or the wrong word order do not match Python syntax. The key check is simple: correct def syntax plus a legal function name.
- Wrong keyword The option using
functionfails because Python defines functions withdef. - Starts with digit The option naming the function
2greetfails because identifiers cannot begin with a number. - Reserved word The option using
classfails because Python keywords cannot be used as function names. - Wrong order The option placing
greetbeforedefdoes not follow Python’s function-definition syntax.
Question 19
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A program should print adult for any user age 18 or older, and print adult member only when that outer age test has already succeeded. The code is broken:
age = 16
member = True
if age >= 18:
print("adult")
if member:
print("adult member")
What is the best fix?
Options:
A. Make
if member:the outer test and nest the age testB. Replace the second
ifwithelif member:C. Indent
if member:underif age >= 18:D. Change the first test to
if age >= 18 and member:
Best answer: C
Explanation: The fix is to nest the membership check inside the age check. In Python, an inner if runs only when the outer if is true, so adult member cannot print for someone under 18 while adult still prints for any adult.
This tests nested conditional flow and indentation. Two separate if statements are independent, so the second condition is checked whether or not the first one passed. In the broken code, member is tested even when age >= 18 is false, which lets adult member print for a minor.
To make the second test depend on the first, put it inside the first block:
- Outer test:
age >= 18 - Inner test:
member - Result:
adultprints for every adult, andadult memberprints only for adult members
Using elif is the opposite flow because it runs when the first test fails, and combining both conditions into one outer test removes the separate adult case.
- Nesting the membership test under the age test matches the requirement that the inner check runs only after adulthood is confirmed.
- Using
elif memberfails becauseelifis evaluated whenage >= 18is false. - Combining both checks in one outer condition is too strict and skips
adultfor adult non-members. - Making membership the outer test changes which condition controls the inner block.
Question 20
Topic: Block 4: Functions and Exceptions
What is printed by this code?
def label(first, second, third):
print(first + "-" + second + "-" + third)
label("red", third="blue", second="green")
label("up", second="left", third="right")
Options:
A. First line:
red-blue-green; second line:up-left-rightB. First line:
red-green-blue; second line:up-right-leftC. First line:
red-green-blue; second line:up-left-rightD. First line:
red-blue-green; second line:up-right-left
Best answer: C
Explanation: Python assigns positional arguments first, then matches keyword arguments by name. That means the first call prints red-green-blue and the second prints up-left-right, even though the keyword arguments are written in a different order.
This tests how Python binds arguments in a valid mixed function call. A positional argument fills the next available parameter from left to right. After that, keyword arguments are matched to parameters by their names, not by the order they appear.
- In
label("red", third="blue", second="green"),firstgets"red",secondgets"green", andthirdgets"blue". - In
label("up", second="left", third="right"),firstgets"up",secondgets"left", andthirdgets"right".
So the function prints red-green-blue on the first line and up-left-right on the second. The closest distractors come from treating keyword order as if it changed parameter order.
- The option with
red-blue-greentreatsthird="blue"as if it filled the second slot, but keywords match by name. - The option with
up-right-leftmakes the same mistake in the second call by swappingsecondandthird. - The option swapping both lines assumes keyword arguments are processed by appearance order instead of parameter names.
Question 21
Topic: Block 1: Computer Programming and Python Fundamentals
A beginner wants this program to print nananana Batman!, but it raises an error:
part = "na"
line = part + 4 + " Batman!"
print(line)
Which replacement for the second line is the best fix?
Options:
A.
line = part + part + " Batman!"B.
line = part * "4" + " Batman!"C.
line = part * 4 + " Batman!"D.
line = part + str(4) + " Batman!"
Best answer: C
Explanation: Strings use + to join strings and * with an integer to repeat a string. The fixed expression must repeat "na" four times and then append " Batman!".
Python treats string concatenation and string repetition as different operations. The + operator joins one string to another string, while the * operator repeats a string only when the other operand is an integer. In the broken code, part + 4 fails because Python cannot concatenate a str and an int directly.
part * 4becomesnananananananana + " Batman!"becomesnananana Batman!
A common nearby mistake is turning 4 into the string "4"; that removes the type mismatch but still does not repeat the text.
- Converting
4to"4"avoids the original mismatch but producesna4 Batman!. - Multiplying by
"4"is still invalid because string repetition needs an integer count. - Adding
partonly twice createsnana Batman!, which is too short.
Question 22
Topic: Block 4: Functions and Exceptions
A student wants this program to print True because "cat" is inside "concatenate", but it prints False. Without changing the function body, which replacement for the last line fixes the bug?
def has_fragment(text, fragment):
return fragment in text
print(has_fragment("cat", "concatenate"))
Options:
A.
print(has_fragment("concatenate", "cat"))B.
print(has_fragment(fragment="concatenate", text="cat"))C.
print(has_fragment("cat", fragment="concatenate"))D.
print(has_fragment(text="cat", fragment="concatenate"))
Best answer: A
Explanation: The function expects the larger text first and the smaller fragment second because it checks fragment in text. The original call reverses those positional arguments, so it tests whether "concatenate" is inside "cat", which is False.
This bug comes from how positional arguments are matched: Python assigns them by order. In has_fragment(text, fragment), the first argument becomes text and the second becomes fragment.
The function returns fragment in text, so the call must provide:
- the full string as
text - the smaller search string as
fragment
With the original call, Python evaluates "concatenate" in "cat", which is False. Swapping the arguments makes the check "cat" in "concatenate", which is True.
Keyword arguments can also prevent order mistakes, but only if the correct values are assigned to the correct parameter names.
- The keyword-based call with
fragment="concatenate"andtext="cat"is still reversed, even though the order on the line changes. - The mixed call keeps
"cat"as the first argument, sotextstill gets the wrong value. - The all-keyword call is explicit, but it explicitly assigns the wrong values to the parameters.
Question 23
Topic: Block 4: Functions and Exceptions
A student is writing a loop that should keep asking for an age. If the entry is not a valid integer, the program should print Invalid age and ask again. It should stop only when the entered age is 0. Which change correctly preserves that control flow and catches the right exception?
while True:
text = input("Age: ")
try:
age = int(text)
# replace here
if age == 0:
break
print(age)
Options:
A. Add
except TypeError:then printInvalid ageandcontinue.B. Add
except ValueError:then printInvalid ageandcontinue.C. Add
except ValueError:then printInvalid ageandbreak.D. Add
except IndexError:then printInvalid ageandcontinue.
Best answer: B
Explanation: When int() cannot convert text like abc, Python raises ValueError. To keep the while loop asking again after bad input, the handler should catch ValueError and use continue, not break.
This item combines exception handling with loop control. In Python, int(text) raises ValueError when the string does not contain a valid integer. That means the handler should be specific to ValueError, not an unrelated exception such as TypeError or IndexError.
After printing the error message, continue skips the rest of the current loop iteration and goes back to the top of the while True loop for another prompt. Using break would end the loop immediately, which does not match the requirement to ask again after invalid input.
The key idea is to match the except clause to the actual failure that can happen, then choose loop control that fits the required behavior.
- The option using
TypeErrorfails because invalid numeric text inint()does not raise that exception. - The option using
breakstops the loop after bad input instead of prompting again. - The option using
IndexErrorfails because no indexing operation is involved here.
Question 24
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A student wants this exact one-line output:
C:\new\test
But this program prints the text on two lines and includes a tab:
print("C:\new\test")
What is the best fix?
Options:
A. Add
end=""to theprint()call.B. Use triple quotes around the same text.
C. Use single quotes around the same text.
D. Replace each
\with\\in the string.
Best answer: D
Explanation: Backslashes in Python strings begin escape sequences like \n for newline and \t for tab. Because C:\new\test contains both patterns, Python changes the text before printing. Escaping each backslash as \\ keeps the output on one line and shows the path exactly.
When Python reads a string literal, it interprets backslash escapes before print() runs. In C:\new\test, the \n becomes a newline and the \t becomes a tab, so the text is not displayed as a normal path.
print("C:\\new\\test")
Each \\ in the source code represents one literal backslash in the output. After escaping both backslashes, Python prints C:\new\test exactly as written. The key idea is that the problem is inside the string literal, not in the print() function itself.
- Single quotes do not change how
\nand\tare interpreted. - Triple quotes allow multiline literals, but backslash escapes still work inside them.
end=""only changes whatprint()adds after the string, not the characters already inside the string.
Question 25
Topic: Block 1: Computer Programming and Python Fundamentals
A beginner writes this code to test whether a calculation equals 0.3:
total = 0.1 + 0.2
if total == 0.3:
print("match")
else:
print("different")
The program should treat tiny floating-point representation errors as equal. Which TWO replacements for the if line are appropriate?
Options:
A.
if str(total) == "0.3":B.
if abs(total - 0.3) < 1e-9:C.
if total == float("0.3"):D.
if round(total, 10) == round(0.3, 10):E.
if int(total) == int(0.3):F.
if round(total) == round(0.3):
Correct answers: B and D
Explanation: Floating-point numbers such as 0.1 and 0.2 are not stored exactly in binary, so direct == comparisons can fail for values that are mathematically equal. Using a small tolerance with abs() or rounding both sides to a known precision are common ways to compare them safely.
The core issue is floating-point representation. In Python, 0.1 + 0.2 may be stored as a value very close to 0.3, not exactly 0.3, so == can report False even though the math result is what you expect. A tolerance check like abs(total - 0.3) < 1e-9 asks whether the numbers are close enough, which is a standard fix. Rounding both values to the same number of decimal places can also work when the required precision is known in advance. By contrast, converting to int, comparing strings, or creating another float value such as float("0.3") does not solve the underlying precision problem. The key takeaway is to avoid exact equality for simple float results when tiny representation errors are acceptable.
- Integer cast drops the fractional part, so many different decimal values can compare equal.
- Exact float literal still performs direct float equality, which is the original problem.
- Whole-number rounding reduces both values to
0, which is too imprecise for checking0.3. - String comparison checks text formatting rather than numeric closeness.
Questions 26-30
Question 26
Topic: Block 2: Control Flow - Conditional Blocks and Loops
A student wants to print each word in uppercase. Indexes are not needed for this task, but the program raises an error:
words = ["code", "loop", "list"]
for word in range(len(words)):
print(word.upper())
Which replacement for the for line is the best fix?
Options:
A.
for word in range(words):B.
for word in len(words):C.
for word in range(len(words)):D.
for word in words:
Best answer: D
Explanation: When indexes are not needed, iterate directly over the sequence. Using for word in words: makes word hold each string from the list, so calling upper() works correctly.
The core idea is direct sequence iteration: use for item in sequence: when you need each element but not its position. In the broken code, range(len(words)) produces the integers 0, 1, and 2, so word becomes an integer instead of a string. Because integers do not have an upper() method, the loop fails.
Direct iteration fixes that immediately:
for word in words:assigns each list element toword- each element is a string
word.upper()then prints the uppercase version
Using indexes is unnecessary here and makes the loop harder to read for this task.
len(words)returns one integer, so it cannot be used directly as the iterable in aforloop.range(words)is invalid becauserange()expects an integer argument, not a list.- Keeping
range(len(words))still makeswordan integer, soword.upper()still fails.
Question 27
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A beginner says this program takes the wrong branch. With word = "python", they expected pypyn because "th" is in the word, but the program prints pypyp.
word = "python"
piece = word[0:2] * 2
if "th" in piece:
print(piece + word[-1])
else:
print(piece + word[0])
What is the best fix?
Options:
A. Build
piecewithword[0:3] * 2.B. Concatenate
word[-1] + pieceinstead.C. Build
piecewithword[2:4] * 2.D. Check
"th"inword, not inpiece.
Best answer: D
Explanation: The condition is checking the wrong string. piece becomes "pypy", so "th" in piece is False, even though "th" is in word; changing the condition to use word produces the expected pypyn.
The key concept is that the membership operator in checks only the string on its right. Here, word[0:2] gives "py", and * 2 repeats it to make piece = "pypy". Because "th" in "pypy" is False, Python runs the else branch and prints piece + word[0], which is "pypyp".
word[0:2]gets the first two characters.* 2repeats that slice.word[-1]would correctly give"n", but that branch never runs.- If the decision should depend on the original word, the condition must be
if "th" in word:.
Changing the slice or the concatenation order changes the output text, but it does not fix the real cause of the wrong branch.
- Changing
piecetoword[2:4] * 2makes the repeated text"thth", so it no longer matches the expected"pypy"part. - Changing
piecetoword[0:3] * 2produces"pytpyt"and still leaves the condition tied to the wrong string. - Reversing the concatenation order affects only the final output format; it does not fix the incorrect branch choice.
Question 28
Topic: Block 1: Computer Programming and Python Fundamentals
A beginner wants latest_points to store the updated total after 4 points are added, using the current value of points. The program prints 10 instead of 14.
points = 10
latest_points = points
points = points + 4
print(latest_points)
Which change is the best fix?
Options:
A. Replace
latest_points = pointswithlatest_points = 14.B. Change
points = points + 4topoints == points + 4.C. Move
latest_points = pointsbelowpoints = points + 4.D. Change
print(latest_points)toprint(points).
Best answer: C
Explanation: Assignment binds a name to the value it has at that moment. latest_points gets 10 before points is reassigned, so it stays 10. Moving the assignment after the update makes latest_points receive 14.
In Python, a variable name does not automatically follow later changes to another variable. When latest_points = points runs, latest_points is assigned the current value of points, which is 10. Then points = points + 4 reassigns points to 14, but latest_points is still 10 until it is assigned again.
A correct fix is to update points first and then assign that updated value to latest_points:
points = 10
points = points + 4
latest_points = points
print(latest_points)
The key takeaway is that reassignment changes the value bound to one name; it does not automatically change other names assigned earlier.
- Using
==compares values and does not reassignpoints. - Printing
pointswould show14, butlatest_pointsstill would not store the updated total. - Hard-coding
14ignores the actual variable value and does not demonstrate correct reassignment.
Question 29
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A student is debugging this code. The summarize() function must receive a list, even when it gets only one value.
temps = [18, 21, 19, 23]
summarize(???)
Which expression should replace ??? so that summarize() receives a list containing only 21?
Options:
A.
temps[2:3]B.
temps[:1]C.
temps[1:2]D.
temps[1]
Best answer: C
Explanation: Use temps[1:2] because slicing returns a new list, even when the slice has just one item. Simple indexing with temps[1] returns the element itself, not a one-element list.
In Python, list indexing and list slicing look similar but produce different kinds of results. Indexing with one position, such as temps[1], returns a single element, so the result is the integer 21. Slicing with a start and stop, such as temps[1:2], returns a new list containing the selected range.
Because the stop index is excluded, 1:2 includes only the item at index 1. That makes the result [21], which matches a function that expects a list argument. A slice can contain one element, many elements, or even be empty, but it is still a list. The closest mistakes here use valid slices with the wrong boundaries, so they return the wrong value.
temps[1]gets the correct value, but it returns21, not a list.temps[:1]is a slice, but it returns[18], which contains the first item.temps[2:3]is also a one-item slice, but it returns[19], not[21].
Question 30
Topic: Block 3: Data Collections - Tuples, Dictionaries, Lists, and Strings
A student is debugging a function that should change the first character of any non-empty string to J. The code fails because it treats a string like a mutable list.
def fix_name(name):
name[0] = "J"
return name
print(fix_name("mark"))
Which replacement for the two indented lines inside fix_name makes the function work as intended for any non-empty string?
Options:
A.
return "J" + name[1:]B.
return name[:1] + "J" + name[1:]C.
return name[1:] + "J"D.
return name.replace(name[0], "J")
Best answer: A
Explanation: In Python, strings are immutable, so name[0] = "J" is invalid. The fix is to return a new string made from the replacement character and the rest of the original string.
A Python string cannot be changed in place with indexed assignment. That works for lists, but with strings it raises a TypeError. When a function needs an updated string, it must create and return a new one instead.
Here, name[1:] returns all characters after the first one. Concatenating "J" in front gives the same string except for index 0.
def fix_name(name):
return "J" + name[1:]
The key idea is to rebuild the string with slicing rather than trying to mutate it.
- The option adding
name[:1]keeps the original first character and insertsJafter it. - The option appending
Jchanges the last position, not the first one. - The option using
replace(name[0], "J")can change every matching character, not just index0.
Continue in the web app
Use IT Mastery for interactive Python Institute PCEP practice with mixed sets, timed mocks, topic drills, explanations, and progress tracking.
Try Python Institute PCEP on Web