PEP 810 – Explicit lazy imports

Overall reception and motivation

  • Many commenters see PEP 810 as one of the cleanest, best‑motivated PEPs in a while: narrowly scoped, explicitly opt‑in, and aimed at a real pain point (slow startup and scattered inline imports).
  • Strong interest from people building CLIs, test runners, large apps (e.g. Django) and scientific stacks where imports of heavy dependencies dominate startup time.

Relation to PEP 690 and prior work

  • PEP 810 is repeatedly contrasted with the rejected PEP 690:
    • 810 is explicit (lazy import) instead of global/implicit.
    • Laziness is per‑statement, doesn’t cascade automatically to dependencies.
    • Implementation uses proxies instead of deep changes to dictionaries/import machinery.
  • Meta’s Cinder / lazy‑import experience is cited: they got big speedups, but also serious breakage in libraries relying on import‑time side effects (NumPy, SciPy, PyTorch, Dash, etc.).

Side effects, correctness, and late failures

  • Major concern: imports do real work at module top level—registration in global registries, monkey‑patching, CLI wiring, etc.—and deferring that can produce subtle, late runtime failures.
  • Some argue “fail fast” via eager imports is a feature, especially for long‑lived services.
  • Others counter that top‑level side effects are a design smell and that tests plus opt‑in usage mitigate the risk.
  • Thread‑safety worries: lazy imports may run at unpredictable times and in arbitrary threads, turning previously “safe at startup” code into Heisenbugs.

CLI startup performance and current workarounds

  • Multiple examples of slow imports (e.g. inflect, PyTorch) severely impacting CLI tools, plugin systems, and pip itself.
  • Common workaround today: move imports inside functions, sometimes guarded by conditions or try/except; this:
    • Duplicates imports across functions.
    • Obscures module dependencies.
    • Fights linters that demand top‑level imports.
  • PEP 810 is seen as a cleaner way to keep imports at the top while deferring cost.

Circular imports and failure timing

  • Some hope lazy imports will “solve” circular imports; others worry it will encourage papering over bad architecture.
  • Counterpoint: even now, many circular‑import issues can be solved by importing the module rather than from module import name.

Syntax, defaults, and alternative designs

  • Significant bikeshedding over lazy as a new keyword; alternatives like defer or decorator‑style statement annotations are proposed.
  • Debate over default: some want lazy‑by‑default with an eager escape hatch; others insist that changing default import semantics would be unacceptably breaking.
  • Alternative design ideas:
    • Modules declaring themselves “lazy‑safe” or “pure” at the top, so importers don’t need lazy.
    • Project‑ or interpreter‑level controls (flags, env vars, config) to turn all imports lazy, seen by some as a “break my libraries” mode.

Library vs caller control

  • One camp: caller knows best when a dependency is actually needed, so lazy control belongs at the import site.
  • Another camp: the module author is best placed to know whether laziness is safe; they point to module‑level __getattr__ and other patterns as existing mechanisms for self‑managed laziness.
  • Concern that heterogeneous ecosystems (some code assuming lazy, some eager) could force libraries to support both modes, increasing maintenance burden.