Skip to content

BuildNot yet confirmed elsewhere1 publisher2 min readPublished

Python 3.15 adds a lazy import keyword that defers each module until first use

Python 3.15, released 9 October 2026, adds a lazy soft keyword that waits to load a module until code first touches its name. CLIs and test runners start faster, and a missing or misspelled module now raises only when that code path first runs.

The Engineer · Build desk

How we use AISend a correction

What happened

  • The same release makes UTF-8 the default encoding, adds two builtin types and a sampling profiler, and allows * and ** inside comprehensions, per a dev.to walkthrough.
  • Lazy loading can be set globally with -X lazy_imports or PYTHON_LAZY_IMPORTS, and the default mode, normal, honours only the lazy keyword.
  • A program can switch laziness at runtime, module by module, through sys.set_lazy_imports_filter().
  • The new frozendict builtin cannot be modified after creation and is hashable when its contents are, so it can be a dict key or a set member.

Why it matters

  • constraint Optional-dependency guards written as try/except ImportError cannot use the keyword on those lines, because lazy inside a try block is a SyntaxError.
  • exposure A dependency missing from a production image can stay hidden through startup and fail later, the first time a rarely used path runs, unless tests exercise that path.
  • decision Libraries that still support pre-3.15 interpreters have to pick the __lazy_modules__ list over the keyword to get faster startup without dropping older versions.
  • cost Code that gates on isinstance(x, dict) has to be edited before it will accept a frozendict, and config loaders are the likely place to hit it.

Until now, deferring an import meant moving the statement inside the function that used it and hoping the linter stayed quiet [3]. With the 3.15 keyword, imports stay at the top of the file and each module loads on first use [1]. In the walkthrough's example, `lazy import json` and `lazy from pathlib import Path` sit above a print call that loads neither module. json loads at the `json.loads` call and pathlib at `Path(".")` [4].

How much a project saves depends on which modules each run touches. If a run never reaches the code that needs json, json never loads [2]. A CLI whose `--help` path touches none of its heavy dependencies gets the full saving. One whose help path imports them anyway saves nothing. The walkthrough names CLI tools, serverless functions and test runners as the main beneficiaries [17], and it labels the load costs in its own diagram as illustrative [12]. We'd use the sampling profiler that ships in the same release [6] to find where a given tool's startup time goes before rewriting any imports. The walkthrough text available for this report lists the UTF-8 default and the removals without saying what they break.

The breakage it does document comes from laziness itself. A misspelled or missing module no longer raises at the import line. It raises at first use, though the traceback still includes the original import line [10]. The keyword is legal only at module scope. Inside a function, a class, or a try/except/finally block it is a SyntaxError, and star imports and `__future__` imports cannot be lazy [11].

For projects that still support older interpreters, the walkthrough points to a module-level list: `__lazy_modules__ = ["json", "pathlib"]` makes plain import statements for those modules lazy [9]. We'd expect libraries to adopt that form before the keyword. It is the one the walkthrough recommends for code that must keep running on older versions [9].

The second documented trap is in a new builtin. frozendict inherits from object, so `isinstance(x, dict)` returns False for it, and the walkthrough suggests testing against `collections.abc.Mapping` instead [14]. Its equality ignores insertion order, so two frozendicts with the same items compare equal however they were built [15]. The cleanest use is configuration. Passing `object_pairs_hook=frozendict, array_hook=tuple` to `json.loads` gives a parsed document that cannot be mutated after loading [16].

What to watch

  • Measured startup times from CLI and test-runner projects that adopt lazy imports, replacing the walkthrough's illustrative figures.
  • Bug reports from teams moving to 3.15 whose code relied on the previous default encoding.
  • Whether -X lazy_imports=all becomes a common setting in serverless images and CI configurations.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence45
Adoption
Insufficient
Hype gap+15
Incentives
Insufficient
Confidence55
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    A new lazy soft keyword tells Python not to load a module until it is used; imports are still written at the top of the file and Python does not pay for them until the name is touched.

    ReportedSupportedSource: dev.to walkthrough2 sources— create a free account to open themView cited source
  2. [2]

    If a run never reaches the code that needs json, json never loads.

    ReportedSupportedSource: dev.to walkthrough2 sources— create a free account to open themView cited source
  3. [3]

    The usual previous fix for slow startup was to put import statements inside functions and hope the linter did not complain.

    ReportedSupportedSource: dev.to walkthrough2 sources— create a free account to open themView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · October 10, 2026

    Python 3.15 just dropped. Here's everything that changed from 3.14

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

Entities

Loading related stories