PCAP · Domain 1 of 5

PCAP Domain 1: Modules and Packages

Section 1 checks how you bring code into a program and organize your own: import forms, the module search path, the math, random and platform modules, and building packages with __init__.py and __name__ checks.

Exam weight
12%
Official objectives
5
Estimated questions estimate
~6
Suggested study time estimate
8–12 hrs

About 13 min read Reviewed October 2026

Overview

Modules and Packages is Section 1 of the PCAP-31-03 syllabus and has five objectives. The first covers the import variants (import, from ... import, import ... as and from ... import *), qualified names for nested modules, the dir() function and the sys.path list. The next three each target one standard library module: math for ceil(), floor(), trunc(), factorial(), hypot() and sqrt(); random for random(), seed(), choice() and sample(); and platform for functions such as system(), machine(), processor(), version(), python_implementation() and python_version_tuple(). The fifth objective covers writing your own modules and packages, including the __pycache__ directory, the __name__ variable, private names, the __init__.py file and how packages map to directory trees.

Exam status: PCAP-31-03 is the active version. The Python Institute lists PCAP-31-04 as pending release, scheduled for October 31, 2026, and describes it as a routine update; its syllabus was not yet published when this page was reviewed.

How it's tested

PCAP items in this section usually show a short snippet and ask what it prints, which line raises an error, or which import statement makes a later line work. Some items list several statements and ask you to select every valid one, so precise knowledge of name binding after each import form matters more than memorized definitions.

  • Predict the output

    A snippet calls math or platform functions, and you choose the exact printed values, including type details such as int versus float.

  • Fix the import

    A later line uses a name, and you pick the import statement that makes the name available without an error.

  • Read the package tree

    A directory layout is shown, and you choose the fully qualified import that reaches a module inside nested packages.

Reasoning it through

Consider import math as m followed by print(math.pi). The alias statement binds only the name m in the current namespace, so the name math is undefined and the second line raises NameError. Candidates who think the alias is added alongside the original name pick 3.14159 as the output. Tracing which names each import binds avoids the trap.

Objectives 5

Official objectives from the OpenEDG Python Institute outline, in outline order.

1.1 Import and use modules and packagesImport variants, qualified names for nested modules, dir() and sys.path.
What it means
This objective covers the four import forms, reaching names inside nested modules with dotted qualification, listing a module's names with dir(), and the sys.path list Python searches when it looks for a module to import.
What to understand
import math binds the name math, so you write math.sqrt(). from math import sqrt binds only sqrt. import math as m binds only m. from math import * copies every public name and can silently overwrite your own names. sys.path is an ordinary list: the script's directory comes first, and appending a path lets Python find modules elsewhere. dir(module) returns a sorted list of the names a module defines.
How it shows up
Expect snippets that use a name after a particular import form and ask whether the call succeeds or raises NameError.
Common confusion
Assuming import math as m still allows math.pi; the alias replaces the original name in that namespace.
1.2 Perform evaluations using the math moduleceil(), floor(), trunc(), factorial(), hypot() and sqrt().
What it means
This objective covers six math functions and the values and types they return. You should be able to evaluate each one by hand for positive and negative arguments.
What to understand
ceil() rounds toward positive infinity and floor() toward negative infinity, while trunc() simply drops the fractional part, rounding toward zero. All three return int. sqrt() always returns a float, so sqrt(16) is 4.0. hypot(3, 4) gives the Euclidean distance 5.0. factorial(0) is 1, and factorial() of a negative number raises ValueError.
How it shows up
Most items mix negative arguments into ceil(), floor() and trunc() and ask for the printed tuple of results.
Common confusion
Treating trunc() and floor() as identical; they differ for negative values, such as -2 versus -3 for -2.7.
1.3 Generate random values using the random modulerandom(), seed(), choice() and sample().
What it means
This objective covers producing pseudo-random values with four functions and understanding that a seed makes the sequence repeatable.
What to understand
random() returns a float in the half-open range from 0.0 up to but not including 1.0. seed() initializes the generator, so calling it with the same value twice reproduces the same sequence. choice() returns one element of a non-empty sequence. sample(population, k) returns a new list of k unique elements chosen without replacement and raises ValueError when k exceeds the population size.
How it shows up
Items ask which outputs are possible, or whether two runs seeded identically print the same numbers.
Common confusion
Expecting sample() to repeat elements or accept a k larger than the population; it samples without replacement.
1.4 Discover host platform properties using the platform moduleplatform(), machine(), processor(), system(), version(), python_implementation(), python_version_tuple().
What it means
This objective covers querying the operating system, hardware and interpreter that run your code, using functions from the platform module.
What to understand
system() returns a generic OS name such as Linux, Windows or Darwin. machine() names the hardware type, processor() the processor (sometimes an empty string), version() the OS version string and platform() a combined descriptive string. python_implementation() returns a name like CPython or PyPy. python_version_tuple() returns three strings, major, minor and patch, not integers.
How it shows up
Expect a question asking which function returns a given kind of value or what type an element of the version tuple has.
Common confusion
Assuming python_version_tuple() holds integers; every element is a string, so comparisons need conversion.
1.5 Create and use user-defined modules and packagesRationale, __pycache__, __name__, private names, __init__.py and nested packages.
What it means
This objective covers writing your own modules and grouping them into packages, including what happens on first import and how Python distinguishes running a file directly from importing it.
What to understand
A module runs its top-level code once, on first import, and Python caches compiled bytecode as .pyc files in a __pycache__ directory. When a file is run directly, __name__ equals "__main__"; when imported, it holds the module name. Names starting with an underscore are private by convention and are skipped by from module import *. A package is a directory of modules, traditionally marked with __init__.py, which runs when the package is imported.
How it shows up
Items show a package tree and a file using if __name__ == "__main__": and ask what runs when the module is imported.
Common confusion
Thinking a leading underscore blocks all access; it only signals intent and excludes the name from star imports.

High-yield concepts

The terms, rules and formulas this domain turns into questions most often.

  • Import binding

    Each import form binds a different name in the current namespace.

    Remember
    import x as y binds only y.
    Tested as
    NameError prediction items.
    Trap
    Using the original module name after aliasing it.
  • from module import *

    Copies all public names of a module into the current namespace.

    Remember
    It can overwrite existing names silently.
    Tested as
    Name collision snippets.
    Trap
    Expecting underscore-prefixed names to be imported.
  • sys.path

    The list of directories Python searches for modules.

    Remember
    It is a list you can modify at runtime.
    Tested as
    Questions on making a module importable.
    Trap
    Thinking sys.path is read-only or a string.
  • dir()

    Returns a sorted list of names defined by an object or module.

    Remember
    Called with a module, it lists its attributes.
    Tested as
    Introspection items.
    Trap
    Confusing it with help(), which prints documentation.
  • floor() vs. trunc()

    floor() rounds down; trunc() rounds toward zero.

    Remember
    They differ only for negative numbers.
    Tested as
    Output prediction with negative floats.
    Trap
    Assuming the two always match.
  • sqrt() and hypot() return float

    Both functions return floating-point results.

    Remember
    sqrt(9) prints 3.0, not 3.
    Tested as
    Type and output questions.
    Trap
    Writing 3 instead of 3.0.
  • seed()

    Initializes the pseudo-random generator.

    Remember
    Same seed, same sequence.
    Tested as
    Reproducibility questions.
    Trap
    Believing seed() makes values truly random.
  • sample() vs. choice()

    sample() returns k unique items in a list; choice() returns one item.

    Remember
    sample() never repeats an element position.
    Tested as
    Possible-output items.
    Trap
    Expecting choice() to return a list.
  • python_version_tuple()

    Returns the interpreter version as a tuple of three strings.

    Remember
    Elements are str, not int.
    Tested as
    Type questions on platform.
    Trap
    Doing arithmetic on the elements without conversion.
  • __name__ == "__main__"

    True only when the file is executed directly.

    Remember
    Imported modules see their own module name instead.
    Tested as
    Run-versus-import questions.
    Trap
    Expecting guarded code to run on import.
  • __pycache__

    Directory where Python stores compiled .pyc bytecode for imported modules.

    Remember
    It speeds up later imports.
    Tested as
    Package behavior questions.
    Trap
    Thinking it holds source code or is required to run.
  • __init__.py

    File that marks a directory as a regular package and runs on package import.

    Remember
    Its code executes once when the package is first imported.
    Tested as
    Package tree items.
    Trap
    Forgetting it runs before submodules load.

Side by side

Concepts candidates mix up, compared on the point that decides the answer.

Import forms

ConceptMeaningKey differenceCommon trap
import math Binds the module name Call as math.sqrt() Calling sqrt() unqualified
from math import sqrt Binds only the chosen name Call as sqrt(); math is undefined Using math.sqrt() afterwards
import math as m Binds an alias only Call as m.sqrt() Assuming math is still bound
from math import * Binds all public names Can overwrite local names Expecting _private names to come too

Rounding functions in math

ConceptMeaningKey differenceCommon trap
ceil(-2.3) Rounds toward positive infinity Result -2 Writing -3
floor(-2.3) Rounds toward negative infinity Result -3 Writing -2
trunc(-2.3) Drops the fractional part Result -2, rounds toward zero Treating it as floor()

Running vs. importing a module

ConceptMeaningKey differenceCommon trap
Run directly __name__ is "__main__" Guarded block executes Expecting the file name in __name__
Imported __name__ is the module name Guarded block is skipped Expecting the guarded block to run
Imported again Module object is reused from the cache Top-level code does not rerun Expecting prints to repeat

Exam traps

Each trap is an answer that looks right. Learn the clue that should change your mind.

  1. Alias keeps the original

    What candidates pick
    Answer that math.pi prints after import math as m.
    Why it looks right
    Aliases look like nicknames that add a name.
    Why it's wrong
    The alias binds only m, so referencing math raises NameError.

    Clue to watch for The snippet uses the full module name after an as clause.

  2. Ceil of a negative

    What candidates pick
    Answer -3 for math.ceil(-2.5).
    Why it looks right
    Ceil sounds like moving away from zero.
    Why it's wrong
    ceil() rounds toward positive infinity, so -2.5 becomes -2.

    Clue to watch for A negative float is passed to ceil().

  3. sqrt returns int

    What candidates pick
    Choose 4 for print(math.sqrt(16)).
    Why it looks right
    The square root of a perfect square is whole.
    Why it's wrong
    sqrt() always returns a float, so the output is 4.0.

    Clue to watch for The options include both 4 and 4.0.

  4. Oversized sample

    What candidates pick
    Choose a five-element list for sample([1, 2, 3], 5).
    Why it looks right
    It seems the function might repeat items.
    Why it's wrong
    sample() selects without replacement and raises ValueError when k exceeds the population.

    Clue to watch for k is larger than the sequence length.

  5. Star import gets everything

    What candidates pick
    Expect _helper to be available after from mod import *.
    Why it looks right
    The star suggests all names.
    Why it's wrong
    Names that begin with an underscore are skipped by a star import unless listed in __all__.

    Clue to watch for The name in question starts with an underscore.

  6. Second import reruns code

    What candidates pick
    Expect a module's print to appear twice after importing it twice.
    Why it looks right
    Each statement looks like it executes the file.
    Why it's wrong
    Python caches loaded modules in sys.modules, so a repeated import reuses the module object.

    Clue to watch for The same import statement appears more than once.

Answer framework

For a Section 1 snippet, use these steps to predict exactly what PCAP-31-03 expects the code to do.

  1. List the names each import statement binds, remembering that aliases replace the original name and star imports skip underscore names.
  2. Check every later reference against that list; a name that was never bound means NameError at that line, even if the module itself was imported successfully.
  3. For math calls, decide the rounding direction and the return type, noting that sqrt() and hypot() give floats.
  4. For random or platform calls, identify the return type and constraints, such as sample() uniqueness and string tuple elements.
  5. For package or module files, decide whether the file is run or imported, then follow __name__, __init__.py and cached imports to the output.

Practice question

A script imports the math module and runs one print call that applies three rounding functions to the same negative value. What is the output of the following code? import math; print(math.floor(-2.5), math.trunc(-2.5), math.ceil(-2.5))

Choose one answer

Want more like this? The PCAP practice test has questions for every domain.

Checklist

0 of 12

Tick each one you can do without notes. Your ticks stay in this browser.

Study strategy

Learn this section at the keyboard. Open an interactive interpreter and try each import form in a fresh session, then call dir() to see which names exist afterwards. Alias a module, try to use its original name, and read the NameError so the rule sticks. Append a directory to sys.path and import a module from it.

Next, build a small table for the math functions with inputs 2.7, -2.7 and 4. Write each result and its type, paying most attention to the negative column. Do the same for the random functions: seed the generator twice with the same value, compare the outputs, and make sample() fail on purpose. Call each platform function on your machine and note which ones return strings, tuples or empty values.

Finally, create a package by hand: a top directory, a nested subpackage, __init__.py files that print a message, and a module with a guarded main block. Import it in different ways, run the module directly, and watch when each print appears and where __pycache__ shows up. The Python Institute's free Python Essentials 2 course on Edube is aligned with PCAP, so pair it with timed practice questions afterwards.

FAQ

How much of PCAP is Section 1, Modules and Packages?

Modules and Packages is 12% of PCAP-31-03, and the official syllabus assigns it 6 of the 40 exam items.

Is PCAP-31-03 still the current exam?

Yes. The Python Institute lists PCAP-31-03 as active and PCAP-31-04 as pending release, scheduled for October 31, 2026. Check which version your voucher and testing date cover.

Do I need to memorize every math module function?

No. The syllabus names six: ceil(), floor(), trunc(), factorial(), hypot() and sqrt(). Know their rounding rules, error cases and return types.

What does python_version_tuple() return?

A tuple of three strings holding the major, minor and patch numbers of the running interpreter, for example ('3', '12', '1').

Is __init__.py required for a package?

Modern Python supports namespace packages without it, but PCAP treats __init__.py as the marker of a regular package and expects you to know that it runs on package import.

Why does a module's print statement appear only once?

Python stores loaded modules in sys.modules, so a later import of the same module reuses the existing object instead of running its top-level code again.

What happens with from module import * and private names?

Names beginning with an underscore are not imported by a star import unless the module lists them in __all__.

Test your Domain 1 knowledge

You have covered import forms, sys.path, the math, random and platform modules, and building packages. Test whether you can predict each snippet's output under exam timing.

Keep going