Domain 1: Modules and Packages
- Python offers three import forms: import module brings in the whole namespace (used as module.name), from module import name binds specific objects directly, and import module as alias renames it; from module import * is discouraged because it floods the local namespace.
- The math module supplies functions like sqrt(), factorial(), floor(), ceil(), trunc(), pow(), and the constants pi and e, and its trigonometric functions such as sin() and cos() operate in radians.
- The random module provides random() for a float in [0.0, 1.0), randint(a, b) for an inclusive integer, randrange() following range() semantics, choice() and shuffle() for sequences, and seed() to make results reproducible.
- The platform module reports the runtime environment through functions such as platform.system(), platform.machine(), platform.processor(), platform.python_version(), and platform.platform().
- The datetime module models dates and times with the date, time, datetime, and timedelta classes; datetime.now() gives the current moment, subtracting two datetimes yields a timedelta, and strftime()/strptime() convert between datetimes and strings.
- dir() lists the names an object or module exposes, which is the standard way to introspect what is available without reading the source, and help() prints an object's documentation.
- The special variable __name__ equals the string '__main__' when a file is run directly and the module's own name when it is imported, so the if __name__ == '__main__': idiom guards code meant to run only on direct execution.
- A package is a directory containing an __init__.py file (which may be empty) and can hold modules and nested subpackages; __init__.py runs the first time the package is imported and can initialize or re-export package-level names.
- sys.path is the list of directories Python searches on import, seeded from the script's directory, the PYTHONPATH variable, and standard locations; each module's top-level code runs only once and is then cached in sys.modules, while pip installs third-party packages from PyPI (the Python Package Index).
Domain 2: Exceptions
- Python exceptions form a class hierarchy rooted at BaseException, with most catchable errors inheriting from Exception; concrete classes such as ValueError, TypeError, IndexError, KeyError, and ZeroDivisionError sit beneath it, and catching a base class also catches all of its subclasses.
- A try block may be followed by except (handles a raised exception), else (runs only when no exception occurred), and finally (always runs, even on a return or an unhandled error), which makes finally the right place for cleanup that must happen no matter what.
- You can handle several exception types in one clause by grouping them in a parenthesized tuple, as in except (ValueError, TypeError) as e:, letting a single block respond to more than one error class.
- When several except clauses are present, order them from most specific to most general because Python runs the first matching handler; placing except Exception ahead of a specific subclass makes the specific handler unreachable.
- The raise statement triggers an exception (for example raise ValueError('bad input')), and a bare raise inside an except block re-raises the exception currently being handled while preserving its original traceback.
- You define a custom exception by subclassing Exception or a more specific built-in, which gives you a meaningful named error type and lets you attach your own attributes or behavior for domain-specific failures.
- A caught exception object carries the values passed to its constructor in the args attribute (a tuple), and calling str() on the exception typically renders those arguments as the human-readable message.
- An assert statement checks a condition and raises AssertionError when it is false (optionally with a message); because assertions are stripped out when Python runs with the -O flag, they are for internal sanity checks, not for validating external input.
Domain 3: Strings
- Python strings are immutable sequences of Unicode characters, so methods that seem to modify a string actually return a brand-new one and leave the original unchanged; you cannot assign to a character by index.
- Strings support indexing (s[0], with negative indexes counting from the end) and slicing (s[start:stop:step] where stop is excluded), and a negative step such as s[::-1] returns a reversed copy.
- ord() returns the integer Unicode code point of a single character and chr() converts a code point back into its character; ASCII occupies code points 0 to 127 as a subset of Unicode, which is what underlies character comparisons.
- Common methods convert and search text: split() and join() move between strings and lists, strip()/lstrip()/rstrip() trim whitespace, find() returns -1 when a substring is absent while index() raises ValueError, and replace(), startswith(), and endswith() round out everyday work.
- Character-test methods such as isdigit(), isalpha(), isalnum(), isspace(), islower(), and isupper() return booleans, while case methods like lower(), upper(), title(), and capitalize() each return a new string.
- f-strings such as f'{value:>10.2f}' and the str.format() method both interpolate expressions with format specifiers that control width, alignment, precision, and type, while the older % operator offers printf-style formatting.
- Escape sequences inside string literals include \n for a newline, \t for a tab, \\ for a literal backslash, \' and \" for quotes, and \uXXXX for a Unicode code point; a raw string prefixed with r treats backslashes literally, which helps with regex patterns and Windows paths.
- String comparison is lexicographic and case-sensitive, comparing characters by their code points position by position, so uppercase letters sort before lowercase ('Z' < 'a') and 'apple' comes before 'apply'.
Domain 4: Object-Oriented Programming
- A class is a blueprint that defines attributes and methods, and an object (instance) is a concrete value produced by calling the class; type(obj) and obj.__class__ both report which class an object came from.
- Instance variables are set per object (usually through self inside __init__) while class variables are defined in the class body and shared by every instance; assigning to the name through an instance creates a shadowing instance attribute instead of changing the class variable.
- __init__ is the initializer that runs immediately after an object is created to set up its starting state, and self is the explicit reference to the current instance that every instance method receives as its first parameter.
- Methods declared in the class body take self as their first parameter, and a method calls another method on the same object through self; Python never passes the instance implicitly, which is why self is always spelled out.
- Encapsulation in Python is largely by convention: a single leading underscore (_name) marks a member as non-public, while a double leading underscore (__name) triggers name mangling to _ClassName__name so subclasses do not clash with it by accident.
- A subclass inherits the attributes and methods of its base class and is declared with class Child(Parent):, and Python supports multiple inheritance (class C(A, B):), which lets one class combine behavior from several bases.
- The method resolution order (MRO), computed by C3 linearization and viewable through ClassName.__mro__ or ClassName.mro(), fixes the left-to-right order Python searches base classes when it looks up an attribute under multiple inheritance.
- super() returns a proxy that dispatches to the next class in the MRO, so super().__init__() cooperatively invokes the parent initializer, and a subclass overrides a method simply by defining one with the same name.
- isinstance(obj, Class) tests whether an object is an instance of a class or one of its subclasses, and issubclass(Sub, Base) tests a class-to-class relationship; both accept a tuple of classes to check several types at once.
- Introspection tools expose object internals: __dict__ holds an instance's or class's attributes, __name__ gives a class's name, __bases__ lists its direct parents, and hasattr(), getattr(), and setattr() read or modify attributes dynamically by name.
- Special (magic or dunder) methods let a class hook into built-in operations: __init__ constructs, __str__ gives the readable string and __repr__ the unambiguous one, __len__ backs len(), and operator methods such as __eq__ and __add__ overload == and +.
Domain 5: Miscellaneous
- A list comprehension builds a list from an iterable in a single expression, [expr for item in iterable], and can filter with a trailing condition ([x for x in nums if x > 0]) or transform values with a conditional expression in the output part.
- A lambda is an anonymous single-expression function such as lambda x: x * 2, with no statement body and no return keyword, most often passed inline where a short callable is needed, like a sort key or a callback.
- map(func, iterable) applies a function to every element and filter(func, iterable) keeps only the elements for which the function is truthy; in Python 3 both return lazy iterators, so wrap them in list() to materialize the results.
- A closure is a nested function that captures and remembers variables from its enclosing scope even after the outer function has returned, and the nonlocal keyword lets the inner function rebind one of those enclosing variables.
- A generator function uses yield to produce values one at a time, suspending and resuming its state between calls; because it is lazy it computes each value only on demand, so it can represent very large or even infinite sequences without building a full list.
- The iterator protocol requires __iter__() to return the iterator object and __next__() to return the next value or raise StopIteration when exhausted; a for loop calls iter() once and then next() repeatedly under the hood.
- sorted(iterable) returns a new sorted list without touching the original and accepts key= (often a lambda) to sort by a computed value plus reverse=True to descend, whereas list.sort() sorts in place and returns None.
- open() returns a file object using modes such as 'r', 'w', 'a', and 'r+', with 'b' for binary and 't' for text; read() returns the whole content, readline() a single line, readlines() a list of lines, and write() sends text out.
- The with statement opens a file as a context manager that closes it automatically even if an error is raised, and text mode decodes to str while binary mode ('rb' or 'wb') works with bytes objects, which are immutable sequences of integers from 0 to 255.
PCAP exam tips
- Object-oriented programming is roughly a third of the exam and its single largest domain, so spend the most preparation there: instance versus class attributes, inheritance, MRO with super(), name mangling, and the common dunder methods.
- Expect many 'what is the output of this code?' questions; trace the code by hand line by line and watch classic traps like mutable default arguments, class-versus-instance attribute shadowing, and generator laziness that yields nothing until iterated.
- For multiple-inheritance questions, work out the method resolution order left to right (C3 linearization) to predict which base class's method or attribute actually wins before you pick an answer.
- Memorize the exception hierarchy and the specific-before-general handler rule, plus the exact roles of else (runs when no exception occurred) and finally (always runs), because these show up as trap questions.
- The exam mixes item types beyond single choice: multiple choice, gap fill, code insertion and ordering, and drag-and-drop; read each stem for how many options to select and pace the 65 minutes so no single item eats too much time.
Study guide FAQ
Do I need to pass PCEP before taking PCAP?
No, PCEP is not a formal prerequisite and anyone can register for PCAP directly. That said, PCAP assumes you already know PCEP-level fundamentals such as data types, control flow, functions, and basic data structures, so PCEP-level knowledge is strongly recommended before you sit it.
How is PCAP different from PCEP?
PCEP (Certified Entry-Level Python Programmer) covers the basics of syntax, control flow, and simple data structures. PCAP (Certified Associate) goes further into modules and packages, exception handling, string processing, object-oriented programming, and topics like list comprehensions, generators, closures, lambdas, and file I/O.
How many questions are on PCAP-31-03 and how long is the exam?
The exam has 40 questions with a 65-minute time limit. Question formats go beyond single choice and include multiple choice, gap fill, code insertion and ordering, and drag-and-drop items.
What score do I need to pass, and is PCAP useful for automation or DevOps roles?
You need 70% to pass. PCAP is a solid credential for automation, scripting, and DevOps or IT work because it validates practical Python 3 skills - writing modular code, handling errors, processing text and files, and using OOP - that those roles depend on day to day.