Courseiva

Certified Associate Python Programmer PCAP (PCAP) — Questions 376–421

421 questions total · 6pages · All types, answers revealed

Page 5

Page 6 of 6

376
MCQhard

Which of the following expressions raises a ValueError?

A.'abc'.index('a')
B.'abc'.find('d')
C.'abc'.rfind('d')
D.'abc'.index('d')
AnswerD

Here, str.index() is invoked with 'd', which does not occur in the string 'abc'. Unlike find/rfind, index is designed to raise ValueError when the substring is absent, treating that condition as an exceptional event. Because 'd' is missing, this expression raises ValueError, making it the correct answer.

Why this answer

Calling `'abc'.index('d')` raises a `ValueError` when the substring is not found. The `str.index()` method in Python is designed to raise this exception for missing substrings, unlike `str.find()` and `str.rfind()`, which return -1.

Exam trap

Python Institute often tests the subtle difference between `index()` (which raises an exception) and `find()`/`rfind()` (which return -1), trapping candidates who assume all substring search methods behave identically on failure.

How to eliminate wrong answers

Option A is wrong because `'abc'.index('a')` successfully finds the substring 'a' at index 0, so no exception is raised. Option B is wrong because `'abc'.find('d')` returns -1 when the substring is not found, as per Python's string method behavior. Option C is wrong because `'abc'.rfind('d')` also returns -1 for a missing substring, following the same convention as `find()`.

377
MCQeasy

A Python script is written to be used both as a standalone program and as an imported module. Which condition should the script use to execute code only when run directly?

A.if __import__ == '__main__':
B.if __name__ == '__main__':
C.if __name__ == '__module__':
D.if __file__ == 'main':
AnswerB

This is the canonical Python idiom used to determine whether the current file is being run as the top-level script. When the interpreter executes a script directly, it sets the global variable __name__ to the string '__main__'; when the file is imported as a module, __name__ is set to the module's import name instead. The if block therefore only runs for standalone execution, which is exactly what the script intends. This guard also supports running with python -m, where __name__ is also '__main__'.

Why this answer

Python sets the global variable `__name__` to `'__main__'` when the script is executed directly (e.g., `python script.py`). When the script is imported as a module, `__name__` is set to the module's name. The condition `if __name__ == '__main__':` is the standard Python idiom to guard code that should only run in the direct execution context.

Exam trap

Python Institute often tests the exact syntax `if __name__ == '__main__':` and distracts candidates with plausible-sounding but incorrect alternatives like `__import__` or `__module__`, exploiting confusion about Python's special attributes and the difference between module-level and execution-level variables.

How to eliminate wrong answers

Option A is wrong because `__import__` is a built-in function used to import modules programmatically, not a variable that indicates direct execution; comparing it to `'__main__'` is syntactically and semantically invalid. Option C is wrong because `__name__` is never set to `'__module__'`; that string has no special meaning in Python's execution model. Option D is wrong because `__file__` holds the path to the script file, not a string like `'main'`, and it is not used to determine whether the script is run directly or imported.

378
Multi-Selecthard

Refer to the exhibit. Which THREE statements about the class hierarchy are correct?

Select 3 answers
A.D does not have a method named 'method'
B.Calling D().method() returns 'B'
C.The super() call in B would call C.method
D.The MRO of D is ['D', 'B', 'C', 'A', 'object']
E.Class C is a subclass of A
AnswersB, D, E

Calling D().method() returns 'B' because the MRO for D is ['D', 'B', 'C', 'A', 'object']. Since D defines no method, Python's lookup proceeds to B, whose method returns the string 'B' directly, without calling super(). Therefore C.method is never reached, and the call evaluates to the string 'B'.

Why this answer

When `D().method()` is called, Python's MRO (Method Resolution Order) for class D is `['D', 'B', 'C', 'A', 'object']`. Since class D does not define `method`, Python looks up the MRO and finds `method` first in class B. The `return 'B'` in B's `method` is executed, so the call returns 'B'.

Exam trap

Python Institute often tests the misconception that `super()` always calls the immediate parent class, when in fact it follows the MRO of the runtime instance, which can skip or reorder classes in multiple inheritance scenarios.

379
Multi-Selecteasy

Which two of the following are valid ways to create a multiline string in Python source code? (Choose two.)

Select 2 answers
A.s = "Line1\nLine2"
B.s = 'Line1' 'Line2'
C.s = """Line1\nLine2"""
D.s = '''Line1\nLine2'''
E.s = 'Line1\nLine2'
AnswersC, D

Triple double quotes define a multiline string literal: the opening and closing delimiters may be on different physical lines, and any raw line breaks inside become part of the string. Including \n adds an explicit line break as well; this is one of the two accepted forms for multiline literals in Python.

Why this answer

Triple-quoted strings ("""...""") in Python allow multiline content directly in source code, including explicit escape sequences like \n. The triple quotes preserve the string as a single object spanning multiple lines, making it a valid multiline string.

Exam trap

The PCAP exam often tests the distinction between a string that contains a newline character (via \n) and a string that is physically multiline in source code, tricking candidates into thinking any string with \n is a multiline string.

380
Matchingmedium

Match each variable scope to its description.

Drag a concept onto its matching description — or click a concept then click the description.

Concepts
Matches

Inside a function

At module level

In outer function (nested)

Predefined names in Python

Variable from enclosing scope (not global)

Why these pairings

The LEGB rule defines scope lookup order: Local, Enclosing, Global, Built-in. Correct matches are Local (inside function), Enclosing (outer function), Global (module level). Built-in consists of Python's predefined names.

381
MCQmedium

A developer is building a configuration parser. They have a string `line = " key = value "` and need to remove the leading and trailing spaces, then split the line at the equals sign into a list of exactly two elements: the key and the value, with any spaces around the equals sign removed. Which expression achieves this?

A.[part.strip() for part in line.split('=')]
B.line.strip().split('=')
C.line.replace(' ', '').split('=')
D.line.strip(' =').split('=')
AnswerA

Splitting the original string on '=' gives [' key ', ' value ']. The list comprehension then applies .strip() to each part, removing all leading and trailing whitespace from both the key and the value. This yields ['key', 'value'], exactly two elements with spaces around the equals sign removed, satisfying the requirement.

Why this answer

The goal is to remove whitespace around both the key and the value after splitting. Splitting first on the equals sign isolates the two components, and then stripping each component individually removes spaces that surround the equals sign. The list comprehension does this cleanly and preserves any internal spaces that belong to the key or value, making it the correct approach.

Exam trap

The trap here is assuming that stripping the whole line before splitting is enough to remove spaces around the delimiter, when in fact those spaces remain attached to the resulting substrings.

382
MCQmedium

A developer wants to ensure that a file is always closed, even if an exception occurs, without using the 'with' statement. Which approach correctly achieves this?

A.f = open('file.txt'); try: ... except: ... else: f.close()
B.f = open('file.txt'); try: ... finally: f.close()
C.if f.closed: pass else: f.close()
D.try: f = open('file.txt'); ... except: pass; finally: f.close()
AnswerB

Using `try: ... finally: f.close()` is the canonical Python idiom because the `finally` block is guaranteed to execute whether or not an exception is raised inside the `try` block. Unlike `except`, which only handles exception paths, `finally` runs on normal completion, on exception propagation, and even when a `break`, `continue`, or `return` is encountered in the `try` body. This ensures that the file descriptor is released deterministically, preventing resource leaks in both expected and exceptional control flows. It is the building block of context managers, where the `with` statement uses `__exit__` to achieve similar deterministic cleanup.

Why this answer

The `finally` block is guaranteed to execute regardless of whether an exception occurs in the `try` block. This ensures that `f.close()` is always called, properly releasing the file resource. The `with` statement is not used, but the `try...finally` construct provides the same deterministic cleanup behavior.

Exam trap

Python Institute often tests the distinction between `else` and `finally` in exception handling, trapping candidates who think `else` runs unconditionally or that placing `open()` inside the `try` block is safe without checking for assignment failure.

How to eliminate wrong answers

Option A is wrong because the `else` block only runs if no exception occurs; if an exception is raised, `f.close()` is never executed, leaving the file open. Option C is wrong because it references `f.closed` before `f` is defined in the given code snippet, and even if defined, it does not guarantee closure after an exception — it is a conditional check, not a cleanup mechanism. Option D is wrong because the `except` block contains `pass`, which silently swallows exceptions, and although `finally` runs, the `try` block includes the `f = open(...)` statement; if `open()` itself raises an exception (e.g., file not found), `f` is never assigned, causing a `NameError` in the `finally` block when trying to call `f.close()`.

383
Multi-Selecteasy

Which TWO of the following operations can be performed on a string?

Select 2 answers
A.Extend with .extend()
B.Append with .append()
C.Pop with .pop()
D.Slicing with [::]
E.Concatenation with +
AnswersD, E

Slicing with [::] is a valid, non-mutating operation on strings because str implements the sequence protocol via __getitem__, accepting a slice object. For example, s[::-1] creates a reversed copy of the string, while s[1:4] extracts a substring; in every case the result is always a brand-new string and the original is left unchanged. This works regardless of the immutability of strings because it reads data rather than trying to modify it.

Why this answer

String slicing with the syntax `[start:stop:step]` (e.g., `[::]`) is a built-in operation for strings in Python, allowing extraction of substrings. Option E is correct because the `+` operator performs string concatenation, creating a new string by joining two strings together.

Exam trap

Python Institute often tests the distinction between mutable (list) and immutable (string) types, leading candidates to incorrectly assume that list methods like `.append()`, `.extend()`, and `.pop()` also work on strings.

384
MCQeasy

A developer writes a class `Circle` with `def __init__(self, radius): self.radius = radius` and wants printing a `Circle` instance to produce a readable description such as `Circle(5)`. Which method should be implemented, and why over the alternative?

A.Implement `__repr__`, because it provides the unambiguous representation used by the interactive interpreter, `repr()`, and containers, and `__str__` falls back to it when undefined.
B.Implement `__str__`, because it is the method the `print()` built-in always calls for any object.
C.Implement `__init__` to return a formatted string, because the constructor runs whenever the object is displayed.
D.Implement `__format__`, because string formatting is the modern replacement for both `__str__` and `__repr__`.
AnswerA

`__repr__` is the canonical developer-facing representation and is what the interactive interpreter, `repr()`, and container displays use. When `__str__` is not defined, `print()` falls back to `__repr__`, so implementing it alone yields `Circle(5)` in every context described. This single method covers both the debugging and printing needs of the scenario without duplication.

Why this answer

`__repr__` is the unambiguous, developer-oriented representation that the interpreter, `repr()`, and containers use, and Python falls back to it for `print()` when `__str__` is absent. Implementing it alone therefore produces `Circle(5)` in every context the scenario mentions. `__str__` is the user-facing alternative, `__format__` governs format-spec handling, and `__init__` has nothing to do with display.

Exam trap

The trap here is assuming `print()` requires `__str__`, when `print()` actually falls back to `__repr__` if `__str__` is not defined.

385
MCQmedium

A class inherits from two parent classes that both have a method with the same name. When calling the method on the child, only one parent's version is executed. What Python mechanism determines which one?

A.Method overloading by signature.
B.Explicit super() call in the child class.
C.Inheritance depth (closest parent wins).
D.Method Resolution Order (MRO).
AnswerD

Python resolves the conflict using the Method Resolution Order, the linearised sequence computed by the C3 algorithm. It determines which parent's method is invoked, so the first matching class in that order executes, explaining why only one parent's version runs.

Why this answer

Python uses the C3 linearization algorithm to compute the Method Resolution Order (MRO) for a class. When a method is called on an instance, Python searches the MRO from left to right and executes the first implementation it finds. This ensures a consistent and predictable order of inheritance, even in diamond or multiple-inheritance scenarios.

Exam trap

Python Institute often tests the misconception that Python uses 'closest parent wins' or depth-first search, but the actual mechanism is the C3 linearization MRO, which respects base class order and the diamond inheritance pattern.

How to eliminate wrong answers

Option A is wrong because Python does not support method overloading by signature; the last definition of a method in a class overwrites previous ones, and dispatch is based on the object's type, not argument types. Option B is wrong because an explicit super() call is a way to invoke a parent's method from within the child, but it is not the mechanism that determines which parent's method is executed when calling the method directly on the child. Option C is wrong because inheritance depth does not determine which parent's method is called; Python's MRO follows the C3 linearization order, which respects the order of base classes and the diamond pattern, not simply the closest parent.

386
MCQhard

A developer is working on a data pipeline that processes files from untrusted sources. The pipeline should catch and log any exception, but also ensure that sensitive information from the exception (e.g., file paths) is not exposed to end users. Which approach balances security and debugging?

A.Catch the exception and re-raise the same exception.
B.Catch the exception, log it, and suppress it silently.
C.Catch the exception, log the full traceback, then raise a custom generic exception.
D.Catch the exception and print it to the console.
AnswerC

This is the recommended approach because it separates internal diagnostics from user-facing failure information. Logging the full traceback preserves the exact stack, exception types, and local context for developers, while raising a custom generic exception like PipelineProcessingError prevents sensitive implementation details from leaking. Using a custom exception also gives callers a stable interface for retry and alerting logic without coupling them to low-level I/O or network exceptions.

Why this answer

It balances security and debugging: the full traceback is logged for developers (preserving debugging details like file paths), while a custom generic exception is raised to end users, preventing sensitive information from being exposed. This approach follows the principle of least privilege for error handling, ensuring that internal details are not leaked to untrusted sources.

Exam trap

Python Institute often tests the distinction between logging exceptions for debugging versus exposing them to users, and the trap here is that candidates may choose Option A (re-raise) thinking it preserves the exception chain, but they overlook the security requirement to hide sensitive details from end users.

How to eliminate wrong answers

Option A is wrong because re-raising the same exception would expose the original exception's details (including sensitive file paths) to the end user, violating security requirements. Option B is wrong because suppressing the exception silently hides all debugging information from logs, making it impossible for developers to diagnose issues in the pipeline. Option D is wrong because printing the exception to the console exposes sensitive information directly to the user or console output, which is insecure and does not log for debugging.

387
Multi-Selecthard

Which TWO of the following are true about importing modules using the import statement?

Select 2 answers
A.The module is executed only once on the first import.
B.Relative imports can be used in scripts executed as the main module.
C.Importing a module with a different name using 'as' creates a copy of the module.
D.Circular imports always cause an ImportError.
E.Importing a module adds it to sys.modules.
AnswersA, E

When a module is first imported, its top-level code runs, and the resulting module object is stored in the sys.modules dictionary. Subsequent import statements for the same module retrieve that cached object and bind it to the requested name, skipping re-execution of the module body. This ensures that expensive initializations and side effects (such as establishing database connections) happen exactly once per process.

Why this answer

Python caches imported modules in the sys.modules dictionary. When a module is imported for the first time, it is executed and its code is stored; subsequent imports of the same module simply retrieve the cached object from sys.modules without re-executing the module's code. This ensures that module-level initialization runs only once, preventing side effects like repeated resource allocation or redefinition of global variables.

Exam trap

Python Institute often tests the misconception that 'import module as alias' creates a separate copy of the module, when in reality it only creates an additional reference to the same module object in sys.modules.

388
MCQeasy

A developer wants to check if a string ends with a specific suffix. Which method should be used?

A.endswith()
B.index()
C.find()
D.startswith()
AnswerA

The `endswith()` method is the dedicated predicate for suffix testing: it returns `True` only when the final characters of the string exactly match the given suffix, and `False` otherwise. It also accepts optional `start`/`end` slice arguments, which allow you to check only a portion of the string, and it performs a case-sensitive comparison by default (use `casefold()` or lowercasing for case-insensitive checks). Because it returns a boolean directly, it cleanly satisfies the developer's requirement to verify whether the string ends with a specific substring.

Why this answer

The `endswith()` method is specifically designed to check if a string ends with a given suffix, returning a boolean value. This is the correct and most direct approach for the task described, as it avoids manual slicing or comparison.

Exam trap

Python Institute often tests the distinction between `endswith()` and `startswith()`, trapping candidates who confuse prefix and suffix checks, or who mistakenly use `find()` or `index()` which locate substrings anywhere in the string rather than at the end.

How to eliminate wrong answers

Option B is wrong because `index()` returns the lowest index where a substring is found, or raises a ValueError if not found, and does not check for a suffix. Option C is wrong because `find()` returns the lowest index of the substring or -1 if not found, but does not test for the end of the string. Option D is wrong because `startswith()` checks if the string begins with a prefix, not a suffix.

389
MCQmedium

A programmer wants to catch both `FileNotFoundError` and `PermissionError` with a single except clause. Which tuple is correct?

A.except (FileNotFoundError, PermissionError):
B.except FileNotFoundError, PermissionError:
C.except OSError:
D.except [FileNotFoundError, PermissionError]:
AnswerA

Correct syntax: parentheses form a tuple listing the two exception classes to catch. Python checks the raised exception against each class in the tuple and handles either FileNotFoundError or PermissionError in the same block. Because both derive from OSError, using this tuple is more precise than catching the parent class and avoids masking unrelated OSError subclasses.

Why this answer

Python's exception handling syntax allows a tuple of exception types in a single `except` clause, enabling the programmer to catch multiple exception types with the same handler. Both `FileNotFoundError` and `PermissionError` are subclasses of `OSError`, but using the tuple explicitly catches only those two specific exceptions, not all `OSError` subtypes.

Exam trap

Python Institute often tests the distinction between the correct tuple syntax `except (Exc1, Exc2):` and the incorrect comma-separated syntax `except Exc1, Exc2:` (which is a Python 2 relic), or the overly broad `except OSError:` that catches more than intended.

How to eliminate wrong answers

Option B is wrong because it uses a comma instead of parentheses, which is the old Python 2 syntax for catching exceptions and assigning the exception instance to a variable; in Python 3, this raises a `SyntaxError`. Option C is wrong because while `FileNotFoundError` and `PermissionError` are both subclasses of `OSError`, catching `OSError` would also catch many other unrelated exceptions (e.g., `FileExistsError`, `IsADirectoryError`), which is not what the programmer wants. Option D is wrong because square brackets denote a list, not a tuple; Python's `except` clause requires a tuple of exception types, and using a list will raise a `TypeError`.

390
MCQeasy

A programmer wants to use the sqrt function from the math module. Which import statement is most efficient?

A.from math import sqrt
B.import math.sqrt
C.from math import *
D.import math
AnswerA

This is the correct approach because it explicitly imports only the sqrt function from the math module into the current namespace. After execution, you can call sqrt(9) directly without a module prefix, which improves readability and reduces the chance of name collisions. It is a targeted, efficient way to bring in only the specific functionality you need.

Why this answer

`from math import sqrt` binds only the `sqrt` function into the current namespace, avoiding name collisions with other math functions. While the `math` module itself is still fully loaded, this form avoids introducing extra global names and provides direct access to `sqrt`, which is more convenient and slightly faster than attribute lookup with `math.sqrt`. It is the most appropriate when only that one function is needed.

Exam trap

Python Institute often tests the misconception that `import module.function` (e.g., `import math.sqrt`) is valid. Python allows `import package.submodule` only when the target is a submodule, but `sqrt` is a function, not a submodule. For functions, use `from module import function` or `import module` and then `module.function`.

How to eliminate wrong answers

Option B is wrong because `import math.sqrt` is invalid syntax; the dot operator is used for attribute access, not for import statements, and Python will raise a SyntaxError. Option C is wrong because `from math import *` imports all names from the math module into the current namespace, which can cause unintended name clashes and wastes memory by loading functions you don't need. Option D is wrong because `import math` imports the entire module, requiring you to call `math.sqrt()` each time, which is less efficient in terms of namespace lookup and memory if you only need the `sqrt` function.

391
MCQhard

A developer needs to format a floating-point number 123.456789 with exactly 2 decimal places and a width of 10 characters, right-aligned. Which format specifier accomplishes this?

A.:.2f
B.:10.2g
C.:10.2e
D.:10.2f
AnswerD

The specifier `:10.2f` is the correct choice: `10` sets a minimum field width of 10 characters, `.2` requires exactly two digits after the decimal point, and `f` selects fixed-point notation with no exponent. When applied to `1234567`, it produces `1234567.00`, which is exactly 10 characters (7 integer digits, the decimal point, and 2 fractional digits) and satisfies the width and precision requirements. If the integer part were shorter, leading spaces would pad the output to the specified width.

Why this answer

The format specifier `:10.2f` combines a total width of 10 characters with exactly 2 decimal places for a floating-point number, right-aligned by default. The `f` type ensures fixed-point notation, and the width of 10 includes the decimal point and digits, padding with spaces on the left.

Exam trap

The PCAP exam often tests the distinction between `f`, `g`, and `e` format types, and the trap here is that candidates confuse the precision meaning (decimal places vs. significant digits) or forget that width must be explicitly specified for padding.

How to eliminate wrong answers

Option A is wrong because `:.2f` specifies only 2 decimal places without a width, so the output is not padded to 10 characters. Option B is wrong because `:10.2g` uses general format, which may switch to scientific notation for large or small numbers and does not guarantee exactly 2 decimal places. Option C is wrong because `:10.2e` forces scientific (exponential) notation with 2 digits after the decimal, producing output like '1.23e+02' instead of the required fixed-point format.

392
Multi-Selectmedium

Which TWO of the following are valid ways to define a class method in Python? (Select exactly two.)

Select 2 answers
A.def my_method(cls): pass my_method = classmethod(my_method)
B.class MyClass: def my_method(cls): pass
C.def my_method(self): pass
D.@staticmethod def my_method(cls): pass
E.@classmethod def my_method(cls): pass
AnswersA, E

This is a valid, if less common, manual application of the classmethod() built-in. The module-level function is defined with a first parameter named cls, and then classmethod(my_method) wraps that function in a classmethod descriptor before assigning it back to the same name. From that point on, accessing the attribute on the class or on an instance binds the class object as the first argument, exactly as the @classmethod decorator would do at class creation time.

Why this answer

It manually applies the `classmethod()` built-in function to a regular function, converting it into a class method. This is a valid, though less common, way to define a class method, as the `classmethod` descriptor wraps the function so that the first argument passed is the class (`cls`), not an instance.

Exam trap

Python Institute often tests the distinction between the explicit `classmethod()` call and the decorator syntax, and the trap here is that candidates may think only the `@classmethod` decorator is valid, overlooking the manual `classmethod()` function call as an equally valid alternative.

393
MCQmedium

A developer has a project structure with 'my_package/' containing '__init__.py', 'module_a.py', and 'sub_package/' (with its own '__init__.py'). They want to import function 'foo' from 'module_a' inside a script in 'sub_package' using a relative import. Which statement is correct?

A.from .module_a import foo
B.from ..module_a import foo
C.from my_package.module_a import foo
D.from ..my_package.module_a import foo
AnswerB

Two leading dots in a relative import ascend one level in the package hierarchy: from a module inside `sub_package`, `..` refers to `my_package`. Therefore `from ..module_a import foo` asks Python to locate `module_a` as a sibling of `sub_package` within that parent package, which exactly matches the described structure. This is the correct way to import `foo` without relying on an absolute top-level path.

Why this answer

The script is inside 'sub_package/', which is one directory level below 'my_package/'. To import from 'module_a' (located in the parent package 'my_package'), a relative import uses '..' to go up one package level, then specifies the module name. Thus, 'from ..module_a import foo' correctly navigates the package hierarchy.

Exam trap

Python Institute often tests the distinction between relative and absolute imports, and the trap here is that candidates confuse the dot notation ('.' for current package, '..' for parent) with file system paths, leading them to pick 'from .module_a import foo' thinking it refers to the parent directory.

How to eliminate wrong answers

Option A is wrong because '.module_a' refers to a module within the same package ('sub_package'), not the parent package 'my_package'. Option C is wrong because it uses an absolute import path, which is valid but not a relative import as required by the question. Option D is wrong because '..my_package.module_a' incorrectly goes up one level and then tries to access 'my_package' again, which is already the parent package, leading to a double reference.

394
MCQhard

A developer writes a function to reverse a string: def reverse_str(s): return s[::-1]. Which of the following statements about this function is true?

A.It only works for strings with even length
B.It returns a new reversed string
C.It modifies the original string
D.It raises an error if s is empty
AnswerB

In Python, strings are immutable sequences, so slicing with s[::-1] does not alter the original object; it constructs a completely new string with the characters in reverse order. The original variable s still references the unchanged string, and the newly created string can be assigned to another name or used directly. This is the canonical way to reverse a string, and it correctly returns a new value rather than mutating existing data.

Why this answer

The slice operation `s[::-1]` creates a new string that is the reverse of the original. Strings in Python are immutable, so any operation that appears to modify a string actually returns a new string object. The original string `s` remains unchanged.

Exam trap

The PCAP exam often tests the immutability of strings and the behavior of slicing, trapping candidates who mistakenly think that string operations modify the original object or that slicing fails on empty sequences.

How to eliminate wrong answers

Option A is wrong because `s[::-1]` works correctly for strings of any length, including odd-length and empty strings. Option C is wrong because strings in Python are immutable; the slice operation does not modify the original string but returns a new one. Option D is wrong because an empty string `''` is a valid string; slicing it with `[::-1]` returns an empty string without raising an error.

395
Multi-Selectmedium

Consider the following directory structure: project/ main.py pkg/ __init__.py mod1.py subpkg/ __init__.py mod2.py From main.py, you write: from pkg.subpkg import mod2 Which THREE of the following are true regarding relative imports?

Select 3 answers
A.Relative imports only work when the importing module is part of a package.
B.In mod2.py, you can use `from .. import mod1` to import mod1 from pkg.
C.In main.py, you can use `from . import pkg` to import pkg.
D.A directory must contain an __init__.py file to be a package for relative imports to function.
E.The dot notation is interpreted based on the module's __name__ and __package__ attributes.
AnswersA, B, E

Relative imports are not intrinsically tied to the filesystem path of the file; they are only valid when the interpreter has assigned the importing module a non-empty `__package__` attribute, which happens only when that module is imported as part of a package (e.g., `import pkg.subpkg.mod2`). If you run a module directly, Python sets `__package__` to `None`, so a statement like `from . import sibling` fails with "attempted relative import with no known parent package" because there is no package context to anchor the leading dot.

Why this answer

Relative imports (using dot notation like `..` or `.`) are only valid when the importing module is itself part of a package. This is because relative imports rely on the `__package__` attribute to resolve the import path; if the module is not inside a package (e.g., a top-level script), `__package__` is `None` or empty, and relative imports will raise an `ImportError`.

Exam trap

Python Institute often tests the misconception that relative imports can be used from any module, including top-level scripts, or that `__init__.py` is always mandatory for a package; the trap here is that candidates may think `main.py` can use `from . import pkg` because it is in the same directory as `pkg/`, ignoring that relative imports require the importing module to be part of a package.

396
MCQmedium

Refer to the exhibit. What will happen when the code is executed?

A.It prints None
B.It raises a TypeError
C.It raises an AttributeError
D.It prints 10
AnswerC

The correct outcome is an AttributeError because of Python name mangling. Any identifier of the form __x (two leading underscores, at most one trailing underscore) inside a class is rewritten to _ClassName__x. Since the object has an attribute _ClassName__x and not __x, the direct access obj.__x cannot find the attribute, and Python raises AttributeError with a message like 'Test' object has no attribute '__x'.

Why this answer

The code attempts to call a method or access an attribute that does not exist on the object. In Python, when you try to access an attribute or method that is not defined on an object, an AttributeError is raised. Option C is correct because the exhibit shows an attempt to call a non-existent method or attribute on an instance, which triggers AttributeError.

Exam trap

Python Institute often tests the distinction between AttributeError and TypeError, trapping candidates who confuse missing methods with type mismatches.

How to eliminate wrong answers

Option A is wrong because the code does not contain a return statement that would produce None; instead, it raises an exception. Option B is wrong because a TypeError occurs when an operation or function is applied to an object of inappropriate type, not when a missing attribute is accessed. Option D is wrong because the code does not print 10; it raises an exception before any print statement could execute.

397
MCQmedium

A developer tries to modify a string: s = 'hello'; s[0] = 'H'. What happens when this code runs?

A.It changes the string to 'Hello'
B.It raises a TypeError: 'str' object does not support item assignment
C.It creates a new string 'Hello' and assigns it to s
D.It raises an IndexError because index 0 is out of range
AnswerB

Strings in Python are immutable sequences; the assignment `s[0] = 'H'' attempts to mutate the object at index 0, which violates the immutable contract of the `str` type. The interpreter raises a `TypeError` specifically because `str` objects lack a `__setitem__` method, preventing item assignment. This directly satisfies the constraint that strings cannot be modified in-place in Python.

Why this answer

Strings in Python are immutable, meaning their contents cannot be changed after creation. Attempting to assign a new character to an index position (e.g., s[0] = 'H') raises a TypeError: 'str' object does not support item assignment. To modify a string, you must create a new string using slicing or concatenation.

Exam trap

The PCAP exam often tests the immutability of strings by presenting an assignment to an index, tricking candidates who confuse strings with mutable sequences like lists into thinking the string will be modified in place.

How to eliminate wrong answers

Option A is wrong because strings are immutable; assigning to an index does not modify the string in place, so it does not change to 'Hello'. Option C is wrong because Python does not automatically create a new string and reassign s; instead, it raises an error immediately. Option D is wrong because index 0 is valid for a non-empty string like 'hello'; the error is a TypeError, not an IndexError.

398
MCQeasy

A developer needs to extract the file extension from a string like 'report.pdf'. Which string method is most appropriate?

A.str.find('.')
B.str.split('.')[-1]
C.str.partition('.')[2]
D.str.rstrip('.pdf')
AnswerB

str.split('.')[-1] is the correct idiom because it divides the entire string on every dot and then uses -1 to select the final element, which is exactly the substring after the last period. This handles file names with multiple dots, returning the last component as the extension. One caveat is that if no dot exists, the whole original string is returned, but for typical extension extraction this is acceptable and widely used.

Why this answer

`str.split('.')[-1]` splits the string at each dot and returns the last element, which is the file extension. This method works reliably for simple cases like 'report.pdf' and is a common Python idiom for extracting extensions.

Exam trap

Python Institute often tests the distinction between `partition()` and `split()` — candidates mistakenly choose `partition()` because it seems simpler, but they overlook that `partition()` only splits on the first occurrence, making it unsuitable for extensions in filenames with multiple dots.

How to eliminate wrong answers

Option A is wrong because `str.find('.')` returns the index of the first dot, not the extension itself. Option C is wrong because `str.partition('.')[2]` returns everything after the first dot, which works for 'report.pdf' but fails for strings with multiple dots (e.g., 'archive.tar.gz' returns 'tar.gz' instead of 'gz'). Option D is wrong because `str.rstrip('.pdf')` removes trailing characters that match any character in '.pdf' (not the exact substring), so it would incorrectly strip 'f' from 'report.pd' or remove more than intended.

399
MCQeasy

A small web application allows users to download files from a server. The code uses open() without any exception handling. When a user requests a non-existent file, the server crashes with a traceback and returns a 500 Internal Server Error to the client. The team needs to modify the code to handle this situation gracefully: if the file does not exist, the application should return a 404 Not Found response (by calling a function send_404()). The application should not catch unrelated exceptions like KeyboardInterrupt. Which modification is the most appropriate?

A.Wrap the entire request handling in a try-except block catching Exception, and if any exception occurs, call send_500().
B.Check if the file exists using os.path.exists before opening, and if not, call send_404().
C.Wrap the open() call in a try-except block catching OSError, and in the except block call send_404().
D.Wrap the open() call in a try-except block catching FileNotFoundError, and in the except block call send_404().
AnswerD

FileNotFoundError is a precise subclass of OSError that Python's open() raises when the requested path cannot be found, including cases where a parent directory is missing or the path is a dangling symlink. By catching only this exception, the handler maps the specific 'missing resource' condition to send_404() and lets every other I/O problem—such as PermissionError—propagate or be handled elsewhere. This follows the EAFP (easier to ask forgiveness than permission) idiom and avoids the broader catch-all problems of checking existence beforehand.

Why this answer

It catches the specific exception raised when a file is not found (FileNotFoundError), which is a subclass of OSError. This allows the code to return a 404 response for missing files while not catching unrelated exceptions like KeyboardInterrupt, as required. The except block calls send_404() to handle the missing file gracefully without crashing the server.

Exam trap

Python Institute often tests the distinction between catching a specific exception (FileNotFoundError) versus its parent class (OSError), and the trap here is that candidates may choose the broader OSError (Option C) thinking it covers all file-related errors, but that would incorrectly handle permission or other OS errors as 404s.

How to eliminate wrong answers

Option A is wrong because it catches all exceptions (including KeyboardInterrupt) and calls send_500(), which does not distinguish between a missing file and other errors, violating the requirement to not catch unrelated exceptions. Option B is wrong because it introduces a race condition: between checking os.path.exists and opening the file, the file could be deleted or renamed, leading to an unhandled exception. Option C is wrong because catching OSError is too broad; it would catch other OS-related errors (e.g., permission denied) and incorrectly return a 404, when the requirement is to only handle non-existent files with a 404 response.

400
MCQeasy

A class has an attribute that should be computed on access and cached for subsequent accesses. Which pattern is most appropriate?

A.Use __slots__ to define the attribute.
B.Use a custom descriptor that caches the value in the instance's __dict__.
C.Use a @classmethod to compute the value.
D.Use a @staticmethod to compute the value.
AnswerB

A custom descriptor that implements __get__ is the right approach because it can compute the value on first access and then store that computed result in the instance's __dict__ under a private key or even the same name if it is a non-data descriptor. On subsequent accesses, the instance dictionary takes precedence over the non-data descriptor, so the cached value is returned directly without recomputation. This exactly matches the desired lazy, one-time computation behavior.

Why this answer

A custom descriptor with a __get__ method can compute the attribute value on first access and store it in the instance's __dict__ for subsequent accesses. This pattern, often called a cached property, ensures the computation happens only once per instance, which is exactly what the question requires.

Exam trap

Python Institute often tests the distinction between descriptors that compute on every access versus those that cache, and the trap here is that candidates confuse __slots__ (memory optimization) with caching, or think that class-level methods like @classmethod can somehow provide per-instance caching.

How to eliminate wrong answers

Option A is wrong because __slots__ is used to restrict the attributes an instance can have and to save memory by preventing the creation of a __dict__; it does not provide any caching or lazy computation mechanism. Option C is wrong because a @classmethod operates on the class itself, not on an instance, and cannot cache per-instance computed values. Option D is wrong because a @staticmethod is essentially a regular function inside the class namespace, with no access to the instance or class, and thus cannot compute or cache instance-specific attributes.

401
Multi-Selectmedium

Which THREE of the following are valid escape sequences in Python strings?

Select 3 answers
A.\g
B.\t
C.\h
D.\r
E.\n
AnswersB, D, E

The sequence \t is a valid escape sequence that represents the tab character (ASCII 9, horizontal tab). It is commonly used to insert whitespace alignment in text output, for example in printing columns or formatting tables. Python recognizes \t as a single character with the ordinal value 9, not as two separate characters backslash and 't'.

Why this answer

\t is the standard escape sequence for a horizontal tab character in Python strings. Escape sequences in Python begin with a backslash followed by a specific character, and \t is defined in the Python language specification (similar to C) to represent the ASCII tab character (0x09).

Exam trap

Python Institute often tests the distinction between valid escape sequences and invalid ones that are silently treated as literal characters, leading candidates to mistakenly think any backslash-letter combination is valid.

402
MCQhard

A pipeline processes many small binary records. The developer writes a custom exception `class RecordError(Exception)` with an `__init__` that stores a record identifier and calls `super().__init__(message)`. A validation function raises `RecordError` for a corrupt record, and a worker catches it to log the identifier. The worker also wants the raw message to be available via `str(e)`. Which statement about this design is correct?

A.Because RecordError defines its own __init__, the message passed to super().__init__ is discarded and str(e) returns an empty string.
B.The stored record identifier is accessible on the caught instance, and str(e) returns the message because super().__init__ was called with it.
C.The worker must use e.args[0] instead of str(e), because custom exceptions lose the default string representation once they override __init__.
D.The custom exception cannot be caught by except Exception because it does not inherit directly from BaseException.
AnswerB

Assigning the identifier as an attribute in the subclass __init__ makes it available on the caught exception object, which is how the worker logs it. Delegating to Exception.__init__ with the message populates the args tuple, and the inherited __str__ returns that message. Both requirements are satisfied by this design.

Why this answer

A custom exception that stores extra state in __init__ and delegates the message to Exception.__init__ preserves both capabilities: the identifier is available as an attribute on the instance, and the inherited __str__ renders the message from args. Overriding __init__ does not disable __str__, and subclassing Exception keeps the type catchable by broad handlers.

Exam trap

The trap here is believing that a custom __init__ erases the default string representation, when str(e) still works as long as the subclass forwards the message to Exception.__init__.

403
Multi-Selecthard

In a performance-critical application, you need to concatenate many strings in a loop. Which TWO approaches are most efficient?

Select 2 answers
A.Using the % formatting operator
B.Using the join() method on a list
C.Using the += operator
D.Using the + operator
E.Using StringIO from the io module
AnswersB, E

Using the join() method on a list: This is the canonical efficient technique. You collect all the pieces into a list, then call separator.join(list) once. The join() implementation precomputes the exact total length of the result, allocates a single buffer, and copies each piece into it in one straight pass, producing no intermediate strings. That makes it O(n) in both time and memory and is the fastest pure-Python way to assemble many separate string fragments.

Why this answer

The `join()` method on a list (Option B) is efficient because it allocates memory once for the final concatenated string, avoiding repeated reallocation and copying that occurs with immutable strings. `StringIO` (Option E) provides a mutable buffer that accumulates string fragments efficiently, making it suitable for high-performance concatenation in loops.

Exam trap

The PCAP exam often tests the misconception that `+=` is efficient for string concatenation in loops, when in fact it is O(n²) due to string immutability, while `join()` and `StringIO` are the correct O(n) approaches.

404
MCQmedium

A developer defines a class hierarchy with multiple inheritance: class A, class B(A), class C(A), class D(B,C). The method 'm' is defined only in A. What is the method resolution order for D according to the C3 linearization algorithm?

A.D -> B -> A -> object
B.D -> B -> C -> A -> object
C.D -> B -> C -> A
D.D -> B -> A -> C
AnswerB

This is the correct C3 linearization. For D(B, C), B(A), C(A), and A(object), the merge starts with D, then B's MRO [B, A, object] and C's MRO [C, A, object] are merged with the direct bases [B, C]. B is taken first, then C (because C is not in the tail of B's MRO), then A (because A is not in the tail of any remaining list), and finally object. This order preserves local precedence order (B before C), respects the inheritance chain C before A, and includes object as the final class.

Why this answer

B is correct because the C3 linearization algorithm always includes 'object' at the end of the MRO. For class D(B, C), L(D) = D + merge(L(B), L(C), [B, C]). L(B) = B, A, object; L(C) = C, A, object.

Merge yields D, B, C, A, object. Options that omit 'object' (like C) are incomplete.

Exam trap

Python Institute often tests the misconception that the MRO follows a simple depth-first left-to-right order, causing candidates to pick option D (D, B, A, C) instead of the correct C3 merge result. Additionally, candidates may forget that 'object' is always included in the MRO, leading them to choose option C over B.

How to eliminate wrong answers

Option A is wrong because it omits class C entirely, violating the local precedence order of D's bases (B, C) and the C3 merge rule that includes all parent classes. Option B is wrong because it places object at the end, which is technically correct but the given option list omits 'object' — however the core error is that it includes object while the correct answer (C) does not; more importantly, option B's order (D, B, C, A, object) is actually the full correct MRO, but the question's answer choices treat 'object' as optional, so option C is the intended correct answer without object. Option D is wrong because it places A before C, violating the C3 rule that C must appear before A since C inherits from A and the merge must preserve the order from C's linearization (C, A).

405
Multi-Selecthard

Which TWO of the following are valid ways to define a class attribute that is shared among all instances?

Select 2 answers
A.Assign the attribute inside a classmethod using cls.
B.Assign the attribute inside a staticmethod.
C.Use the @property decorator.
D.Assign the attribute inside __init__ using self.
E.Assign the attribute in the class body, outside any methods.
AnswersA, E

A classmethod receives the class object as its first parameter, conventionally named cls, so assigning cls.attribute = value inside the method writes directly into the class's namespace and creates a genuine class attribute shared by every instance. This is valid as long as the method is executed at least once (for example, called after class creation). Because cls is the actual class, the attribute is also inherited correctly by subclasses.

Why this answer

A classmethod receives the class (cls) as its first argument, allowing you to assign or modify a class attribute via `cls.attribute = value`. This assignment affects the class itself, making the attribute shared among all instances, as the attribute is stored on the class object, not on instance dictionaries.

Exam trap

Python Institute often tests the distinction between class-level and instance-level attributes, and the trap here is that candidates confuse the @property decorator (which defines a computed instance property) with a class attribute, or think that a staticmethod can modify class state because it is defined inside the class body.

406
MCQmedium

A developer is implementing a custom exception for invalid data. Which class should the custom exception inherit from?

A.RuntimeError
B.ArithmeticError
C.BaseException
D.Exception
AnswerD

Exception is the standard, recommended base class for custom exceptions because it is the root of the ordinary error hierarchy, below BaseException but above all built-in exceptions meant for program-level failures. Deriving from it ensures your invalid-data exception is caught by generic `except Exception` handlers, supports chaining with `__cause__`, and clearly communicates that it is an application-level error. This is the convention described in Python's official documentation and followed by most libraries and frameworks.

Why this answer

The `Exception` class is the base class for all built-in, non-system-exiting exceptions in Python. Custom exceptions should inherit from `Exception` (or one of its subclasses) to ensure they are caught by generic `except Exception:` handlers and integrate properly with Python's exception hierarchy, while avoiding the system-exiting exceptions derived from `BaseException`.

Exam trap

The trap here is that candidates often choose `BaseException` thinking it is the most general base class, but Cisco tests the understanding that custom exceptions should inherit from `Exception` to avoid accidentally catching system-exiting exceptions like `KeyboardInterrupt`.

How to eliminate wrong answers

Option A is wrong because `RuntimeError` is a specific built-in exception for errors that do not fit into other categories; inheriting from it would misrepresent the custom exception's semantics and is not the recommended base for all custom exceptions. Option B is wrong because `ArithmeticError` is a narrow base for arithmetic-related errors (e.g., ZeroDivisionError); using it for generic invalid data exceptions would be semantically incorrect and overly restrictive. Option C is wrong because `BaseException` is the root of all exceptions, including system-exiting ones like `SystemExit` and `KeyboardInterrupt`; inheriting from it would cause the custom exception to be caught by `except BaseException:` blocks, which is not intended for user-defined exceptions and can suppress critical system signals.

407
MCQeasy

A developer writes a function that reads a configuration file and returns its contents as a string. The file might not exist. Which exception should be caught to handle a missing file?

A.FileNotFoundError
B.PermissionError
C.IOError
D.OSError
AnswerA

FileNotFoundError is a built-in exception raised when a file or directory is requested but cannot be found at the specified path. It is a subclass of OSError and is specifically designed for missing-file scenarios, which is exactly the case when reading a configuration file that does not exist. In Python 3, it is the canonical exception for this situation, replacing the more generic IOError that was used in earlier versions.

Why this answer

`FileNotFoundError` is a built-in exception in Python that is raised when a file or directory is requested but does not exist. In Python 3, file-related I/O errors are organized under `OSError` with specific subclasses, and `FileNotFoundError` is the precise exception for a missing file, making it the most appropriate catch for this scenario.

Exam trap

Python Institute often tests the distinction between the broad `OSError` and its specific subclass `FileNotFoundError`, trapping candidates who think catching the parent class is safer, when in fact the exam expects precise exception handling for a missing file.

How to eliminate wrong answers

Option B is wrong because `PermissionError` is raised when the file exists but the process lacks the required permissions to access it, not when the file is missing. Option C is wrong because `IOError` was an alias for `OSError` in Python 2 but is no longer a separate exception in Python 3; catching it would not specifically target a missing file and is considered deprecated. Option D is wrong because `OSError` is the parent class for all system-related exceptions, including `FileNotFoundError`, but catching the parent is too broad and does not precisely handle the missing file case; it would also catch unrelated OS errors like permission or disk errors.

408
MCQmedium

A team is developing a large Python application with multiple modules. They encounter an ImportError when module A tries to import from module B, and module B tries to import from module A. What is the most likely cause and best practice to resolve this?

A.Use 'from module import *' to bring all names into the namespace.
B.Use lazy imports (inside functions) to defer the import until runtime.
C.Restructure the code to eliminate circular dependencies by extracting shared logic into a third module.
D.Move all imports from module A to the bottom of the file.
AnswerC

Circular imports arise when two modules mutually reference each other at import time, so Python cannot fully initialise either. Extracting shared logic into a third module breaks the cycle, satisfying the stem's requirement to resolve the ImportError through restructuring rather than deferred imports or runtime workarounds.

Why this answer

Circular imports occur when two modules depend on each other at the top level, causing an ImportError due to incomplete module initialization. The best practice is to restructure the code to eliminate the circular dependency, typically by extracting the shared functionality into a third module that both A and B can import without mutual dependence. This approach aligns with Python's module loading mechanism, which executes a module fully before making its names available for import.

Exam trap

Python Institute often tests the misconception that moving imports or using wildcard imports can fix circular dependencies, when in fact only restructuring the code or using lazy imports (as a temporary workaround) addresses the root cause.

How to eliminate wrong answers

Option A is wrong because 'from module import *' does not resolve circular imports; it can actually worsen the problem by flooding the namespace and still triggers the same ImportError when the circular dependency is present. Option B is wrong because while lazy imports (importing inside functions) can sometimes work around circular imports by deferring the import until after both modules are initialized, it is considered a workaround rather than a best practice, and it can lead to runtime errors if the deferred import is accessed before the other module is fully loaded. Option D is wrong because moving imports to the bottom of the file does not change the order of execution; Python still processes all top-level imports before executing the rest of the module, so the circular dependency remains unresolved.

409
MCQhard

Under CPython, what is the result of the following code? a = 'hello'; b = 'hello'; print(a is b)

A.True
B.False
C.NameError
D.None
AnswerA

True is correct because in CPython, string literals are automatically interned, meaning that two identical string literals are stored in the same memory location. When the code compares them with the identity operator 'is', it compares object memory addresses, and since both variables point to the same interned object, the result is True. This is a well-known CPython behavior, though it is an implementation detail rather than part of the Python language specification. The exact code likely creates two variables with the same string literal, and interning makes their identities match.

Why this answer

CPython interns short strings as an optimization, meaning both variables 'a' and 'b' reference the same immutable string object in memory. The 'is' operator checks object identity, not value equality, so it returns True when both variables point to the same interned object.

Exam trap

The Python Institute often tests the distinction between 'is' (identity) and '==' (equality), and the trap here is that candidates assume 'is' compares values, leading them to incorrectly choose False when they think two separate string objects are created.

How to eliminate wrong answers

Option B is wrong because it assumes that two identical string literals always create separate objects, but CPython's string interning for short strings (like 'hello') causes them to share the same memory address. Option C is wrong because both 'a' and 'b' are defined and assigned valid string values, so no NameError occurs. Option D is wrong because the 'is' operator always returns a boolean (True or False), never None, and in this case it returns True.

410
MCQhard

A developer creates a metaclass 'Meta' that modifies class creation by adding a class attribute 'created_by' set to 'Meta'. Which code snippet correctly defines and uses this metaclass?

A.class Meta(type): def __new__(cls, name, bases, dct): dct['created_by']='Meta'
B.class Meta(type): def __init__(cls, name, bases, dct): dct['created_by']='Meta'
C.def Meta(name, bases, dct): dct['created_by']='Meta'; return type(name, bases, dct)
D.class Meta(type): def __new__(cls, name, bases, dct): dct['created_by']='Meta'; return super().__new__(cls, name, bases, dct)
AnswerD

This correctly overrides `type.__new__`, modifies the mutable namespace dictionary before class construction, and delegates to `super().__new__` to build the class object. Because `super().__new__` copies the entries of `dct` into the new class's `__dict__`, the added `created_by` attribute is present on the finished class. The explicit `return` is essential: without it, no class object would be created at all.

Why this answer

It defines a proper metaclass by subclassing `type` and overriding `__new__`, which is the correct method for modifying the class dictionary before the class is created. The `__new__` method must return the result of `super().__new__(cls, name, bases, dct)` to actually create the class object. Adding `dct['created_by']='Meta'` inside `__new__` ensures the attribute is set during class creation.

Exam trap

Python Institute often tests the distinction between `__new__` and `__init__` in metaclasses, and the trap here is that candidates mistakenly think `__init__` can modify the class dictionary before class creation, or forget that `__new__` must explicitly return the class object.

How to eliminate wrong answers

Option A is wrong because the `__new__` method does not return the newly created class object; without `return super().__new__(...)`, the metaclass returns `None`, causing a `TypeError` when trying to create a class. Option B is wrong because `__init__` is called after the class is already created, so modifying `dct` inside `__init__` does not affect the class's attributes (the dictionary is already used); the correct place to modify the class dictionary is in `__new__`. Option C is wrong because it defines a regular function, not a metaclass; although it can create a class dynamically, it does not define a metaclass that can be used with the `metaclass=Meta` keyword argument in a class statement.

411
MCQmedium

Which of the following best describes the immutability of strings in Python?

A.Strings can be modified in place using indexing.
B.Strings are mutable but require special methods.
C.Strings cannot be reassigned.
D.Strings cannot be changed after creation, but variables can be reassigned.
AnswerD

This is the correct distinction: the str object itself is immutable, so once a string is created its contents cannot be altered, added to, or removed. However, a variable that references a string can be assigned a new value, such as s = 'new', which makes the variable point to a different string object. This separation between object identity and variable binding is fundamental to Python's data model and explains why strings can appear to 'change' when they actually are being replaced.

Why this answer

Strings in Python are immutable objects, meaning once a string is created, its contents cannot be changed. However, the variable referencing the string can be reassigned to point to a new string object. This distinction between mutability of the object and reassignment of the variable is fundamental to Python's data model.

Exam trap

Python Institute often tests the confusion between object mutability and variable reassignment, leading candidates to incorrectly believe that strings can be modified in place or that they cannot be reassigned at all.

How to eliminate wrong answers

Option A is wrong because strings do not support item assignment; attempting to modify a string via indexing (e.g., s[0] = 'a') raises a TypeError. Option B is wrong because strings are immutable, not mutable, and no special methods can change them in place; any operation that appears to modify a string actually creates a new string object. Option C is wrong because strings themselves can be reassigned to new variables or the same variable can be bound to a different string; the statement 'cannot be reassigned' confuses variable rebinding with object immutability.

412
Multi-Selectmedium

Which two methods can be used to remove leading whitespace from a string? (Choose two.)

Select 2 answers
A.s.strip()
B.s.lstrip()
C.s.split()
D.s.chomp()
E.s.rstrip()
AnswersA, B

Calling s.strip() returns a new string with all leading and trailing whitespace removed, so leading whitespace is indeed eliminated as part of the process. This makes it a valid choice for the task, even though it also strips the right end. By default, strip() removes spaces, tabs, and newline characters; an optional chars argument can narrow the set.

Why this answer

`s.strip()` removes both leading and trailing whitespace from the string, including spaces, tabs, and newline characters. This method is commonly used when you need to clean up a string entirely, but it does more than just leading whitespace removal.

Exam trap

The trap here is that candidates may incorrectly consider `s.strip()` as the method for removing only leading whitespace, overlooking that `lstrip()` is the precise method. Additionally, `chomp()` is not a Python string method; it is from Ruby, and `split()` and `rstrip()` do not remove leading whitespace.

413
MCQeasy

A developer wants to ensure that a class attribute is shared across all instances. Which approach should be used?

A.Use the @property decorator.
B.Define the attribute inside a method without using self.
C.Define the attribute in the class body, outside any methods.
D.Define the attribute inside __init__ using self.
AnswerC

Assigning a value in the class body, directly at indentation level of the class, creates a class attribute stored on the class object. All instances of that class share the same object through normal attribute lookup; accessing it via an instance falls back to the class if no instance attribute shadows it. This is the idiomatic way to create shared state used by every instance.

Why this answer

Defining an attribute in the class body, outside any methods, creates a class attribute that is shared across all instances. Class attributes are stored in the class's __dict__ and are accessible via the class or any instance, unless shadowed by an instance attribute.

Exam trap

Python Institute often tests the distinction between class attributes and instance attributes, and the trap here is that candidates may confuse defining an attribute inside __init__ with creating a shared attribute, not realizing that __init__ always creates instance-specific attributes.

How to eliminate wrong answers

Option A is wrong because the @property decorator is used to define a method that can be accessed like an attribute, typically for computed or controlled access, not for creating a shared class attribute. Option B is wrong because defining an attribute inside a method without using self creates a local variable that is not accessible outside that method and does not become a class or instance attribute. Option D is wrong because defining the attribute inside __init__ using self creates an instance attribute, which is unique to each instance and not shared across all instances.

414
MCQeasy

A programmer writes a function that expects a string and returns it reversed. Which code snippet correctly reverses the string 'stressed' to 'desserts'?

A.result = s.reversed()
B.result = s[::-1]
C.s.reverse()
D.result = ''.join(reversed(s))
AnswerB, D

Using extended slice syntax with a step of `-1` creates a reversed copy of the entire string: `s[::-1]` means start at the end, go to the beginning, and step backward by one. This is the most idiomatic and concise way to reverse a string in Python, and it is often preferred for its readability and speed. Since strings are immutable, this operation allocates a new string object containing the characters in reverse order, leaving the original string unchanged.

Why this answer

Both option B and option D correctly reverse the string 'stressed' to 'desserts'. Option B uses slice notation `[::-1]`, which creates a reversed copy of the string by stepping from end to start with a step of -1. This is the most direct and idiomatic way to reverse a string in Python.

Option D uses `''.join(reversed(s))`: `reversed(s)` returns an iterator that yields characters in reverse order, and `join()` concatenates them into a new string. This is also a valid and correct approach. Option A is incorrect because strings do not have a `reversed()` method; `reversed()` is a built-in function.

Option C is incorrect because `.reverse()` is a list method, not a string method, and strings are immutable.

Exam trap

The Python Institute often tests whether candidates know that both slice notation `[::-1]` and the combination of `reversed()` with `join()` are valid ways to reverse a string. Candidates may incorrectly think only slicing is correct or overlook that `reversed()` returns an iterator that requires `join()` to produce a string.

How to eliminate wrong answers

Option A is wrong because `s.reversed()` is not a valid method; the correct built-in is `reversed(s)`, which returns a reverse iterator, not a string. Option C is wrong because `s.reverse()` is a list method, not a string method — strings are immutable and have no `.reverse()` method, so this raises an AttributeError. Option D is wrong because while `''.join(reversed(s))` does produce the reversed string, it is not listed as the correct answer in the given options; the question asks for the snippet that correctly reverses the string, and option B is the direct, idiomatic one-liner.

415
MCQhard

Which of the following is true regarding Python's method resolution order (MRO) in multiple inheritance?

A.The MRO is computed using the C3 linearization algorithm, ensuring that each class appears before its parents and that monotonicity is preserved.
B.The MRO is always the same as the order of base classes specified in the class statement.
C.The MRO can be changed at runtime by modifying the __bases__ attribute of a class.
D.The MRO is determined by the order of base classes in the class definition, using a depth-first, left-to-right search without consideration of diamond inheritance.
AnswerA

C3 linearization is the algorithm Python uses to compute the MRO at class creation time. It guarantees that every class appears before any of its parents in the linearization and that the local precedence order of bases is preserved across the entire hierarchy, a property called monotonicity. This ensures that `super()` calls follow a consistent, predictable order even in complex diamond inheritance, avoiding duplicate executions and inconsistent dispatch.

Why this answer

Python's method resolution order (MRO) is computed using the C3 linearization algorithm. This algorithm ensures that each class appears before its parents and that monotonicity is preserved, meaning the order of class precedence does not change when new subclasses are introduced. This is essential for resolving method calls in multiple inheritance scenarios, particularly with diamond inheritance.

Exam trap

The trap here is that candidates often assume the MRO follows a simple depth-first, left-to-right order (as in older Python versions or other languages), but Python's C3 algorithm can produce a different order to handle diamond inheritance correctly.

How to eliminate wrong answers

Option B is wrong because the MRO is not always the same as the order of base classes specified in the class statement; the C3 algorithm may reorder classes to satisfy monotonicity and local precedence order, especially in diamond inheritance. Option C is wrong because the MRO cannot be changed at runtime by modifying the __bases__ attribute; while __bases__ can be reassigned, the MRO is recalculated based on the new base classes using the C3 algorithm, but it is not directly mutable. Option D is wrong because the MRO is not determined by a simple depth-first, left-to-right search; Python explicitly abandoned that approach due to issues with diamond inheritance, and instead uses the C3 linearization algorithm to avoid inconsistent ordering.

416
Multi-Selecteasy

Which TWO of the following are valid ways to use string formatting in Python? (Choose two.)

Select 2 answers
A."Hello {0}".format("World")
B."Hello $s" % "World"
C.f"Hello {world}"
D."Hello %s" % "World"
E."Hello {name}".format("World")
AnswersA, D

This is a valid use of the `str.format()` method. The replacement field `{0}` refers to the first positional argument passed to `.format()`, which is the string `"World"`. Python substitutes `"World"` for `{0}`, producing `"Hello World"`; zero-based indexing means `{0}` is the first argument, so this line works correctly.

Why this answer

The `str.format()` method with positional index `{0}` is a valid way to insert the argument `"World"` into the string, producing `"Hello World"`. This is a core feature of Python's string formatting, introduced in Python 2.6, and is explicitly tested in the PCAP exam.

Exam trap

The PCAP exam often tests the distinction between old-style `%` formatting and new-style `.format()` by including plausible but syntactically incorrect variants like `$s` or mismatched placeholders, trapping candidates who rely on memorization rather than precise syntax knowledge.

417
MCQmedium

A team is using inheritance but wants to prevent a method from being overridden in subclasses. What Python feature can enforce this?

A.Use a private method with double underscore prefix (__method).
B.Use a @final decorator.
C.Use @staticmethod.
D.Use @abstractmethod.
AnswerB

Correct. The `@final` decorator from the `typing` module is designed to indicate that a method should not be overridden. Although not enforced at runtime, it is recognized by static type checkers and is the standard Python feature for this purpose.

Why this answer

The `@final` decorator, introduced in Python 3.8 via the `typing` module, is specifically intended to mark a method as final, signaling that it should not be overridden in subclasses. While Python does not enforce this at runtime, type checkers (e.g., mypy) can flag violations, making it the correct feature for preventing overriding in a design intent context. Option A, the double underscore prefix, only triggers name mangling (`_ClassName__method`), which is meant to avoid accidental collisions but does not prevent a subclass from defining a method with the mangled name directly, thus it does not enforce non-overridability.

Exam trap

Candidates often think that `@final` is unenforceable or not part of Python, but since Python 3.8 it is available in the `typing` module and is the standard way to declare a method final. Conversely, the double underscore prefix is frequently misconstrued as making a method impossible to override, but it is simply a naming convention that can be bypassed.

How to eliminate wrong answers

Option B is wrong because Python does not have a built-in `@final` decorator; it is not a standard Python feature (though it exists in some third-party libraries or type checkers like `typing.final` in Python 3.8+, but it is not enforced at runtime by the interpreter). Option C is wrong because `@staticmethod` defines a method that does not receive an implicit first argument (self or cls), but it does not prevent overriding in subclasses; a subclass can still define a method with the same name. Option D is wrong because `@abstractmethod` is used to declare a method as abstract, requiring subclasses to override it, which is the opposite of preventing overriding.

418
Multi-Selecteasy

Which TWO of the following are correct ways to raise a custom exception in Python? (Assume CustomError and CustomException are user-defined.)

Select 2 answers
A.raise "Custom error"
B.raise 42
C.raise CustomError("invalid")
D.raise Exception
E.raise CustomException()
AnswersC, E

This constructs a new instance of the custom exception class immediately before raising it, passing the string "invalid" into the constructor. That value is stored in the instance's args attribute and can be retrieved in an except block, making it the standard, readable way to raise a user-defined exception with diagnostic detail.

Why this answer

It raises a user-defined exception by instantiating the custom exception class `CustomError` with an argument (the string "invalid"). In Python, the `raise` statement must be followed by an exception instance or an exception class; `CustomError("invalid")` creates an instance of the custom exception, which is the proper way to raise a custom exception with a custom message.

Exam trap

Python Institute often tests the distinction between raising an exception class versus an exception instance, and the fact that only instances (or classes that are subclasses of `BaseException`) are valid arguments to `raise` — candidates mistakenly think any object can be raised or that raising a class without instantiation is the only correct way.

419
MCQmedium

A data scientist writes a script to parse a configuration file that contains lines in 'key=value' format. Some lines may have malformed data that cause a ValueError when trying to convert the value to an integer. The requirement is to process all valid lines and skip any that cause a ValueError, but continue processing subsequent lines. The script should log a warning for each skipped line, including the line number. Which implementation correctly fulfills this requirement? (Assume the file is opened with 'with open(...) as f'.)

A.Inside a for loop over f, wrap the parsing in a try-except ValueError block, log the error, and continue.
B.Wrap the entire file processing in a try-except ValueError block; if an error occurs, log and break.
C.Before parsing, check if the value string consists of digits using str.isdigit; if not, skip the line.
D.Inside a for loop over f, wrap the parsing in a try-except Exception block, log the error, and continue.
AnswerA

Placing the try-except inside the for loop is the correct EAFP (Easier to Ask Forgiveness than Permission) pattern: each line is parsed individually, and a ValueError raised by int() (or float()) for a malformed literal is caught, logged, and skipped without terminating the loop. This preserves the required behavior of processing all remaining configuration lines, and catching the specific exception type avoids masking unrelated programming errors. The logging can include the offending line number via enumerate(f) to aid debugging.

Why this answer

It uses a try-except ValueError block inside the for loop, which catches the specific exception when converting the value to an integer, logs a warning with the line number, and continues to the next line. This ensures all valid lines are processed while malformed lines are skipped without halting execution, fulfilling the requirement exactly.

Exam trap

Python Institute often tests the distinction between catching specific exceptions (ValueError) versus broad exceptions (Exception), and the trap here is that candidates may choose Option D thinking 'Exception' covers all errors, but it violates the principle of catching only what you can handle and may hide bugs.

How to eliminate wrong answers

Option B is wrong because wrapping the entire file processing in a try-except ValueError block will cause the loop to break on the first error, skipping all subsequent lines, which violates the requirement to continue processing. Option C is wrong because using str.isdigit() is unreliable for integer conversion—it returns False for negative numbers (e.g., '-5') or strings with leading zeros (e.g., '007'), causing valid lines to be incorrectly skipped. Option D is wrong because catching a broad 'Exception' instead of the specific 'ValueError' can mask unrelated errors (e.g., KeyError, TypeError) that should not be silently skipped, violating best practices for exception handling.

420
Multi-Selecthard

Which THREE of the following are valid ways to import a function named 'calculate' from a module named 'math_ops' located in a subpackage 'operations' of a package 'app'?

Select 3 answers
A.from app.operations.math_ops import calculate
B.import importlib; module = importlib.import_module('app.operations.math_ops'); module.calculate()
C.import app.operations.math_ops.calculate
D.from app.import operations.math_ops import calculate
E.import app.operations.math_ops; app.operations.math_ops.calculate()
AnswersA, B, E

The from-import statement directly fetches the 'calculate' attribute from the 'app.operations.math_ops' module and binds it in the current namespace. This is the most common and concise way to bring a function into scope, and it bypasses the need to reference the module path each time. The import system locates the module using the dotted path, then performs attribute lookup for the function.

Why this answer

It uses the standard Python import syntax to directly import the 'calculate' function from the 'math_ops' module, which is located in the 'operations' subpackage of the 'app' package. This is the most straightforward and recommended way to import a specific attribute from a module.

Exam trap

Python Institute often tests the distinction between importing a module versus importing an attribute from a module, and the trap here is that candidates mistakenly think 'import module.function' is valid syntax, when in fact only 'from module import function' or 'import module' (then using module.function) are correct.

421
MCQeasy

Which of the following statements about the __init__.py file in a package is true?

A.It is required for a namespace package
B.It is required for a directory to be considered a regular package
C.It cannot contain executable code
D.It is automatically generated by Python
AnswerB

Python treats a directory as a regular package only when it contains an __init__.py file, which executes on import and defines the package namespace. Namespace packages lack this file, so its presence is what distinguishes a regular package from that alternative.

Why this answer

In Python, a directory containing an `__init__.py` file is recognized as a regular package. This file can be empty or contain initialization code, and its presence is required for the directory to be imported as a package (as opposed to a namespace package). Without it, Python will not treat the directory as a regular package.

Exam trap

Python Institute often tests the misconception that `__init__.py` is always required for any package, but the trap is that namespace packages (introduced in Python 3.3) do not need it, and candidates may confuse regular packages with namespace packages.

How to eliminate wrong answers

Option A is wrong because a namespace package does NOT require an `__init__.py` file; namespace packages are implicitly created for directories that lack `__init__.py` and are used to split a package across multiple directories. Option C is wrong because `__init__.py` can contain executable code, such as package initialization logic or importing submodules, and it is often used to control what is exported via `__all__`. Option D is wrong because `__init__.py` is not automatically generated by Python; it must be created manually by the developer, though some tools or IDEs may create it as a convenience.

Page 5

Page 6 of 6

All pages