cd /news/developer-tools/python-3-15-lazy-imports-frozendict-… · home › topics › developer-tools › article
[ARTICLE · art-148617] src=byteiota.com ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

Python 3.15: Lazy Imports, frozendict, and a Faster JIT

Python 3.15 shipped on October 9 with explicit lazy imports, a built-in frozendict type, and JIT improvements, per the release's PEP 810 and PEP 814 documentation. Meta's codebase saw a 70% reduction in initialization time after adopting lazy imports, which defer module loading until first use. The JIT compiler now shows 7–8% geometric mean improvement on x86-64 Linux and 11–12% on AArch64 macOS, up from roughly 2% in 3.13 and 4–5% in 3.14.

read5 min views1 publishedOct 10, 2026
Python 3.15: Lazy Imports, frozendict, and a Faster JIT
Image: Byteiota (auto-discovered)

Python 3.15 shipped on October 9. The headline feature is explicit lazy imports — a syntax change that defers module until first use. Meta’s codebase saw a 70% reduction in initialization time after adopting the pattern. The release also ships frozendict as a built-in type, a proper sentinel, unpacking in comprehensions, and a JIT compiler that is finally showing numbers worth quoting. Here is what matters and what to watch.

Lazy Imports: The Startup Fix Python Needed #

For years, heavy Python apps had a startup problem. A web server importing Django, SQLAlchemy, and a handful of ML libraries could spend 400–800ms doing nothing but running import statements before accepting a single request. The standard fix was manual workaround: move imports inside functions, use importlib tricks, or fork CPython like Meta did. Python 3.15 makes this a first-class feature.

The new lazy soft keyword defers module until the imported name is first accessed:

lazy import json
lazy from pathlib import Path

data = json.loads('{"key": "value"}')

For projects that need to stay compatible with older Python versions, there is a backwards-compatible approach using the __lazy_modules__ list. On Python 3.15+, those imports become lazy. On older versions, the list is ignored and imports proceed normally.

__lazy_modules__ = ['numpy', 'pandas', 'heavy_analytics_lib']
import numpy
import pandas

The practical wins are real. CLI tools are the clearest example — when a user runs --help, there is no reason to import a plotting library or a database driver. Meta’s 70% initialization reduction was not a lab benchmark; it came from converting production libraries with deep dependency graphs.

Two risks worth naming. First: late error detection. An ImportError that used to surface at startup will now surface when you first access the lazy import, potentially during request handling or a background job. Second: thread safety. Startup was previously single-threaded; now any thread that first touches a lazy import triggers the load. Neither is a dealbreaker, but both require awareness when adopting this pattern in concurrent systems.

frozendict: A Built-in That Took 20 Years #

Python developers have needed an immutable, hashable dictionary for a long time. The standard library offered types.MappingProxyType as a partial answer, but it was a view over a mutable dict — not genuinely hashable, not usable as a dict key. Third-party packages filled the gap. Python 3.15 ships frozendict as a proper built-in via PEP 814.

import functools

config = frozendict({"model": "gpt-4o", "temperature": 0.7})

@functools.lru_cache
def run_query(cfg: frozendict) -> str:
    ...

seen_configs = {frozendict(user="alice"), frozendict(user="bob")}
lookup = {frozendict(scope="read"): handler_fn}

A few things to know before adopting it. frozendict is not a dict subclass — isinstance(fd, dict) returns False. That is intentional: it avoids inheriting mutation methods that would need to raise errors. The immutability is also shallow: a nested list inside a frozendict is still mutable, and a frozendict containing a list cannot be hashed. These are the same constraints that apply to frozenset, so the behavior is at least consistent.

The JIT Keeps Compounding #

Python’s experimental JIT has been technically available since 3.13. It has not been worth enabling until now. Python 3.15 shows 7–8% geometric mean improvement on x86-64 Linux and 11–12% on AArch64 macOS, with upgrades to LLVM 21, a new tracing frontend, basic register allocation, and lower memory usage for generated machine code.

The trajectory matters more than any single number: roughly 2% in 3.13, 4–5% in 3.14, 7–8% in 3.15. The JIT is still experimental and opt-in — it will not activate automatically. It is also not PyPy. But 8% on a distributed workload has real infrastructure cost implications, and the trend line is clearly heading somewhere.

Smaller Wins Worth Knowing #

Python 3.15 also ships sentinel as a built-in. The old _MISSING = object() pattern works fine but produces ugly reprs and does not pickle cleanly. sentinel("MISSING") gives you a named, picklable, identity-preserving sentinel that works properly with type annotations.

PEP 798 adds unpacking to comprehensions:

flat = [x for sublist in lists for x in sublist]

flat = [*sublist for sublist in lists]

merged = {**d for d in dict_list}

What Actually Breaks #

UTF-8 is now the default encoding on all platforms. Code that calls open() without an explicit encoding= argument and relies on locale defaults — especially on Windows — may produce different output. The fix is to pass encoding="utf-8" explicitly.

Several long-deprecated APIs are now removed: datetime.utcnow() (use datetime.now(datetime.UTC)), importlib.resources.read_text(), and the internal sre_compile, sre_constants, sre_parse modules. The regex internals are the most likely surprise — some packages accessed them directly. Check your dependencies before upgrading. The official What’s New page has the full list.

Should You Upgrade? #

For greenfield projects: yes. The new built-ins are cleaner than their alternatives, and lazy imports are worth adopting for anything with non-trivial startup cost. For existing projects: check your dependencies first. The UTF-8 default and removed APIs are the likeliest sources of breakage, and most projects will need small fixes rather than rewrites.

Python 3.15 is not a headline release — there is no walrus operator moment, no match statement. What it is: a release that fixes chronic annoyances that Python developers have been patching around for years. That is often more valuable than a flashy syntax addition. The official download is available now.

── more in #developer-tools 4 stories · sorted by recency
── more on @python 3.15 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/python-3-15-lazy-imp…] indexed:0 read:5min 2026-10-10 · —