PCPP1 study materials
PCPP1 study resources

PCPP1: Best Practices and Standardization

PCPP1 · Work through your exam, one topic at a time.

All guide sections

Best Practices and Standardization

This domain is policy, not puzzles: PEP 8 layout and naming, PEP 257 docstrings, the logging hierarchy, unittest structure, type hints and packaging. Questions usually ask which line violates the standard or what a logger actually emits, so precision about constants such as the 79-character limit is what earns marks.

PEP 8 essentials

  • Four spaces per indent level, 79-character lines, two blank lines around top-level definitions and one between methods.
  • snake_case for functions and variables, CapWords for classes, UPPER_CASE for module constants, a leading underscore for internal names.
  • One import per line, grouped standard library → third-party → local; no space around = in keyword arguments: f(a=1).

PEP 257 docstrings

  • The docstring is the first statement of the module, function or class; anything before it turns it into a plain string expression.
  • Triple double quotes, a one-line summary ending with a period, a blank line, then detail; it becomes __doc__.

Logging and testing

  • Levels ascend DEBUG(10) → INFO(20) → WARNING(30) → ERROR(40) → CRITICAL(50); the root logger defaults to WARNING, so info() vanishes unless basicConfig(level=logging.INFO) runs.
  • Prefer logging.getLogger(__name__) and lazy formatting: log.info('x %s', v), not an f-string.
  • unittest.TestCase methods must start with test to be discovered; setUp/tearDown run around each test; assertRaises works as a context manager.

Worked example

"""Invoice helpers."""
import logging
log = logging.getLogger(__name__)

def total(items):
    """Return the sum of item amounts."""
    log.info('summing %d items', len(items))
    return sum(items)

Reasoning: importing this module prints nothing, because the root level is WARNING and info sits below it; adding logging.basicConfig(level=logging.INFO) before the call makes the line appear. The docstring is the first statement, so total.__doc__ is populated.

Traps

  • Mutable defaults (def f(x, acc=[])) persist between calls; use None and build inside.
  • Naming a module after a standard-library module (logging.py, json.py) shadows it on import, and a test class not inheriting TestCase is never run.