Free Python Institute PCAP Practice Questions: Section 3: Strings
Practice 10 free Python Institute PCAP - Certified Associate Python Programmer (PCAP-31-03) questions on Section 3: Strings, with answers, explanations, and the IT Mastery next step.
Try the IT Mastery web app for a richer interactive practice experience with mixed sets, timed mocks, topic drills, explanations, and progress tracking.
Topic snapshot
| Field | Detail |
|---|---|
| Practice target | Python Institute PCAP |
| Topic area | Section 3: Strings |
| Blueprint weight | 18% |
| Page purpose | Focused sample questions before returning to mixed practice |
How to use this topic drill
Use this page to isolate Section 3: Strings for Python Institute PCAP. Work through the 10 questions first, then review the explanations and return to mixed practice in IT Mastery.
| Pass | What to do | What to record |
|---|---|---|
| First attempt | Answer without checking the explanation first. | The fact, rule, calculation, or judgment point that controlled your answer. |
| Review | Read the explanation even when you were correct. | Why the best answer is stronger than the closest distractor. |
| Repair | Repeat only missed or uncertain items after a short break. | The pattern behind misses, not the answer letter. |
| Transfer | Return to mixed practice once the topic feels stable. | Whether the same skill holds up when the topic is no longer obvious. |
Blueprint context: 18% of the practice outline. A focused topic score can overstate readiness if you recognize the pattern too quickly, so use it as repair work before timed mixed sets.
Sample questions
These are original IT Mastery practice questions aligned to this topic area. 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 topic drills, mixed sets, and timed mocks in IT Mastery.
Question 1
Topic: Section 3: Strings
A developer is troubleshooting a failed file open on Windows. This code prints a strange path and then raises FileNotFoundError:
path = "C:\new\test.txt"
print(path)
with open(path, "r") as f:
print(f.readline())
What is the best explanation for the failure?
Options:
A. Text mode cannot open file paths that contain backslashes.
B.
\nand\twere interpreted as newline and tab in the string literal.C.
print()modifies the path value beforeopen()uses it.D.
open()requires forward slashes instead of backslashes on Windows.
Best answer: B
Explanation: In a normal Python string literal, some backslash combinations are escape sequences. Here, \n becomes a newline and \t becomes a tab, so the path passed to open() is different from the intended Windows path.
The core concept is that backslashes inside a normal string literal can introduce escape sequences. In "C:\new\test.txt", Python does not keep every backslash as a literal character: \n is parsed as a newline and \t as a tab. That means the resulting string no longer matches the real file path, so open() looks for the wrong location and raises FileNotFoundError.
To keep backslashes literal in this kind of path, use doubled backslashes like "C:\\new\\test.txt" or a raw string such as r"C:\new\test.txt".
The key takeaway is that the problem comes from string-literal parsing, not from open() or print().
- Text mode confusion fails because text mode affects file contents, not how the path literal itself is parsed.
- Forward slash myth fails because Windows paths can be used without requiring forward slashes.
print()side effect fails becauseprint()only displays the current string; it does not change it.
Question 2
Topic: Section 3: Strings
A support script should extract a file’s final extension, but it gives the wrong result for names with multiple dots.
name = "report.final.csv"
pos = name.find(".")
print(name[pos + 1:])
The script prints final.csv, but the requirement is to get only csv. Some filenames may also contain no dot, and that case should not raise an exception. Which change is the best fix?
Options:
A. Use
name.index(".")and rely on-1when the dot is missing.B. Use
name.rfind(".")and treat-1as no extension.C. Use
name.find(".")after checking"." in name.D. Use
sorted(name)before searching for".".
Best answer: B
Explanation: The requirement is to search from the right and avoid an exception when no dot exists. rfind() returns the last matching position, and if the substring is absent it returns -1, which can be handled before slicing.
This is a string-search method selection problem. find() searches from left to right, so it returns the first dot in report.final.csv, which makes the slice start at final.csv instead of the final extension. index() also searches from the left, but unlike find(), it raises ValueError if the substring is missing.
rfind() is the best fit because it searches for the last occurrence of "." and returns -1 when there is no match. That directly matches both requirements: use the final dot, and do not raise an exception for filenames without one. The closest distractor is checking membership before find(), which avoids a missing-dot issue but still finds the wrong dot.
index()confusion fails becauseindex()raisesValueErrorwhen"."is absent and still finds the first dot.- Membership check only avoids a missing-dot crash, but
find()still returns the first dot rather than the last one. - Sorting first changes the character order instead of searching the original filename.
Question 3
Topic: Section 3: Strings
A developer wants this code to print B. The condition should compare the code point of c with the code point of D, but the if line is broken.
c = "A"
if ord(c) < "D":
print(chr(ord(c) + 1))
Which replacement for the if line is the best fix?
Options:
A. if ord(c) < ord(“D”):
B. if c.ord() < ord(“D”):
C. if chr(ord(c)) < ord(“D”):
D. if ord(c, 1) < ord(“D”):
Best answer: A
Explanation: ord() returns an integer code point for a one-character string, while chr() turns an integer back into a character. The broken line compares an int with a str, so the fix is to apply ord() to "D" as well before using <.
This question tests matching types when using ord() and chr(). In the broken condition, ord(c) returns an integer, but "D" is still a string, and Python 3 cannot compare those with <. Replacing "D" with ord("D") makes both sides integers, so the condition can be evaluated correctly.
ord("A")is65ord("D")is6865 < 68isTruechr(65 + 1)is"B"
A close distractor rebuilds c with chr(ord(c)), but that returns a string again and leaves the type mismatch in the comparison.
- The option using
chr(ord(c))still puts a string on the left side of<, so it does not fix the mixed-type comparison. - The option using
c.ord()is invalid becauseord()is a built-in function, not a string method. - The option using
ord(c, 1)is invalid becauseord()accepts exactly one argument.
Question 4
Topic: Section 3: Strings
A developer stores message text in an object and searches it from an instance method. Assume no extra exception handling.
class Note:
def __init__(self, text):
self.text = text
def position(self, fragment):
return self.text.index(fragment)
n = Note("spam ham eggs")
print(n.position("toast"))
Which statement is correct?
Options:
A.
.index()raisesAttributeError;self.textis an instance variable.B.
.index()raisesValueError; using.find()here would return-1.C.
.index()returns-1; using.find()here would raiseValueError.D.
.index()returnsNone;.find()would also returnNone.
Best answer: B
Explanation: str.index() and str.find() differ only in how they report a missing substring. Here, self.text is a normal string, so searching for "toast" with .index() raises ValueError; .find() would return -1 instead.
str.index() and str.find() both search for a substring inside a string, but they handle the “not found” case differently. In this example, the method position() calls .index() on self.text, which is just a str stored in an instance variable. Because "toast" does not appear in "spam ham eggs", .index() raises ValueError, so print() never receives a numeric result.
- Use
.index()when absence should be treated as an error. - Use
.find()when you want a position if found, or-1if not found.
The fact that the call happens inside a class method does not change the string method’s behavior.
- Swapped behaviors fails because
.find()is the method that returns-1when the substring is missing. - Wrong exception type fails because this is not an attribute lookup problem; the missing value causes a search failure, not
AttributeError. - Wrong return value fails because neither method returns
Nonefor an absent substring.
Question 5
Topic: Section 3: Strings
A support script should print match only when the substring 'disk' appears anywhere in a log message. The current code raises an error:
text = "Error: disk full"
if text.index("disk") in text:
print("match")
Which replacement for the if line is the best fix?
Options:
A.
if text.find["disk"] >= 0:B.
if "disk" in text:C.
if find(text, "disk") >= 0:D.
if "disk".find(text) >= 0:
Best answer: B
Explanation: The broken line mixes two different operations: index() returns an integer position, while in performs a membership test. Since the goal is only to check whether 'disk' occurs in the string, the direct membership form is the correct repair.
String membership and string search methods are related but not interchangeable. text.index("disk") returns the starting position of the substring, or raises ValueError if the substring is absent. The in operator expects a substring on the left and a string on the right.
In the broken code, Python first evaluates text.index("disk"), which produces an integer, and then tries to evaluate whether that integer is in the string. That is the wrong operand type for string membership.
If the task is only a yes/no test, use:
if "disk" in text:
Use find() or index() only when the actual position matters. A close distractor is using find, but here the simplest correct fix is the membership operator itself.
text.find["disk"] >= 0fails becausefindis a method call, not something accessed with brackets."disk".find(text) >= 0reverses the search target and looks for the whole message inside the shorter substring.find(text, "disk") >= 0fails becausefindis a string method, not a standalone built-in function.
Question 6
Topic: Section 3: Strings
A developer suspects a bad string index, but the bug may actually be in byte handling. What is printed by this code?
word = "naïve"
raw = word.encode("utf-8")
print(word[2], ord(word[2]), raw[2])
try:
print(raw[2:3].decode("utf-8"))
except UnicodeDecodeError:
print("decode error")
Options:
- A. ```text ï 239 239 decode error
- B. ```text
ï 239 195
ï
- C. ```text ï 239 b’\xc3' decode error
- D. ```text
ï 239 195
decode error
Best answer: D
Explanation: The string index is valid: word[2] returns ï. The problem is byte representation in UTF-8—ï uses more than one byte, so raw[2:3] contains an incomplete sequence and decoding it raises UnicodeDecodeError, which is caught.
word is a Unicode string, so indexing it works by characters, not by UTF-8 bytes. The third character is ï, and ord(word[2]) is its Unicode code point, 239. After encode("utf-8"), that same character is stored as two bytes, 195 and 175, so raw[2] is just the first byte of the encoded form.
print(word[2], ord(word[2]), raw[2])printsï 239 195raw[2:3]is a one-byte slice, not a complete UTF-8 character- Decoding that incomplete byte sequence raises
UnicodeDecodeError - The
exceptblock then printsdecode error
The key point is that the failure comes from decoding incomplete bytes, not from string indexing.
- Treating
raw[2]as239confuses the character’s Unicode code point with its first UTF-8 byte. - Treating
raw[2:3].decode("utf-8")asïignores thatïneeds two bytes in UTF-8. - Treating
raw[2]asb'\xc3'confuses byte indexing with byte slicing; indexing abytesobject returns an integer.
Question 7
Topic: Section 3: Strings
A developer initializes an object from a status line and relies on .split() to separate fields using its default behavior. What is printed?
class StatusLine:
def __init__(self, raw):
self.parts = raw.split()
s = StatusLine(" cpu high\ttemp ")
print(s.__dict__)
Options:
A.
{'parts': ['cpu', 'high', 'temp']}B.
{'parts': ['cpu', 'high\ttemp']}C.
{'parts': ['', '', 'cpu', '', '', 'high\ttemp', '', '']}D.
{'parts': [' cpu high', 'temp ']}
Best answer: A
Explanation: str.split() with no separator uses default whitespace splitting. It removes leading and trailing whitespace, collapses consecutive whitespace, and treats tabs as separators, so the instance attribute becomes a three-item list.
The key concept is the default behavior of str.split() when no separator is provided. In that form, Python splits on any whitespace character, including spaces and tabs, and it does not keep empty strings caused by leading, trailing, or repeated whitespace. In the constructor, the result is stored in the instance attribute parts, so printing s.__dict__ shows that attribute and its list value.
For the given string, the tokens are:
cpuhightemp
So the object’s dictionary contains one key, parts, mapped to ['cpu', 'high', 'temp']. The closest mistakes come from confusing split() with split(" ") or forgetting that \t is also whitespace.
- Empty strings included matches
split(" "), notsplit()with no argument. - Tab kept inside text fails because default
split()treats\tas whitespace too. - Only two parts would fit splitting only on the tab, which the code does not do.
Question 8
Topic: Section 3: Strings
A text import routine receives records like Ann||QA. The program must turn each record into a list of fields using | as the separator, and an empty field between two separators must remain ''. Which string method best matches this requirement?
Options:
A.
record.strip('|')B.
'|'.join(record)C.
record.find('|')D.
record.split('|')
Best answer: D
Explanation: split('|') is the right choice because it parses the string into a list wherever | appears. With an explicit separator, consecutive delimiters preserve empty fields, so Ann||QA becomes ['Ann', '', 'QA'] as required.
Use split() when you need to parse delimited text into separate fields. Passing '|' tells Python exactly where to cut the string, and adjacent separators create an empty string in the result. That directly matches the requirement to preserve a blank middle field.
Ann||QA.split('|') produces['Ann', '', 'QA']- The result is a list of field values
- Empty fields are preserved when a separator is explicitly provided
The key distinction is that split() parses a record, while methods like strip() only remove characters from the ends.
- End trimming only the option using
strip('|')removes|only from the start or end, not between fields. - Search, not parse the option using
find('|')returns an index, not the list of fields. - Wrong direction the option using
'|'.join(record)builds one string from an iterable and would place|between characters here.
Question 9
Topic: Section 3: Strings
A developer is checking how escape sequences in a string literal become characters at runtime. What is printed by this code?
msg = "A\\nB\nC"
print(msg)
print(len(msg))
Options:
- A. ```text A\nB\nC 7
- B. ```text
A\\nB
C
6
- C. ```text A\nB C 5
- D. ```text
A
B
C
5
Best answer: B
Explanation: Python interprets escape sequences while reading the string literal. In "A\\nB\nC", \\ produces a literal backslash, so \\n becomes the two characters \ and n, while the later \n becomes a real newline.
Escape sequences are part of the source-code representation of a string literal. Python converts them into characters when the program is parsed. In this example, \\ becomes one backslash character, so the first \\n does not become a newline; it becomes the two runtime characters \ and n. The second \n is a real newline character.
That means the runtime string contains 6 characters: A, \, n, B, newline, and C. So print(msg) displays A\nB on the first line and C on the second line, and print(len(msg)) then prints 6.
The closest mistake is to treat \\n as if it were another newline escape.
- Both newlines fails because the first
\\nis not a newline;\\first becomes a literal backslash. - Wrong length gets the displayed lines right but counts
\andnas one character instead of two. - No escape processing fails because Python does interpret
\nin string literals, so the second one cannot remain literal.
Question 10
Topic: Section 3: Strings
A developer wants to confirm Python’s default string ordering before sorting labels. What is printed by this code?
data = ["cat", "catalog", "Cat", "20", "3"]
print(sorted(data))
Options:
A.
['20', '3', 'cat', 'Cat', 'catalog']B.
['20', '3', 'Cat', 'catalog', 'cat']C.
['20', '3', 'Cat', 'cat', 'catalog']D.
['3', '20', 'Cat', 'cat', 'catalog']
Best answer: C
Explanation: Python compares strings lexicographically, character by character, using Unicode code points. Here, digit-starting strings come first, Cat comes before cat, and cat comes before catalog because it is the shorter matching prefix.
The key concept is lexicographic string comparison in Python. sorted() uses the same ordering as other string comparisons: it checks characters from left to right by Unicode code point, and if one string ends while all compared characters still match, the shorter string is considered smaller.
"20"comes before"3"because'2'is less than'3'."Cat"comes before the lowercase words because'C'has a smaller code point than'c'."cat"comes before"catalog"because both start withcat, and the shorter equal-prefix string sorts first.
The usual mistakes are treating digit strings as numbers, assuming lowercase sorts before uppercase, or placing the longer prefix first.
- The list starting with
"3"treats the digit strings as numeric values instead of strings. - The list placing
"cat"before"Cat"ignores Python’s case-sensitive character ordering. - The list placing
"catalog"before"cat"reverses the prefix rule for string comparison.
Continue in the web app
Use IT Mastery for interactive Python Institute PCAP practice with mixed sets, timed mocks, topic drills, explanations, and progress tracking.
Try Python Institute PCAP on Web