NewsDeveloper ToolsProgramming LanguagesPython

Python 3.15: Lazy Imports, Faster JIT, and What to Do Now

Python 3.15 release showing lazy imports and JIT compiler improvements

Python 3.15 landed on October 9 — slightly late, because a third release candidate dropped on October 2 to fix a lazy-import edge case. Worth it. The headline is lazy imports: CLI tools that used to take 44ms to start now take 11ms. The JIT compiler, experimental since 3.13, is finally posting numbers worth talking about. frozendict is now a built-in. UTF-8 is the new default, and it will quietly break some code you forgot about. Here is what changes for you today.

Lazy Imports: 4x Startup, No Rewrite Required

PEP 810 adds a lazy soft keyword to the import statement:

lazy import json
lazy from pathlib import Path
lazy from json import dumps

When you mark an import lazy, Python binds the name to a proxy object instead of loading the module immediately. The first time you access the name, the module loads for real. A script importing 13 standard library modules drops from 44ms to 11ms.

A few rules: lazy only works at module level — not inside functions, class bodies, or try blocks. from __future__ import cannot be lazy. This will not speed up a script that uses every import on startup. If your cold start is already fast, lazy imports will not move the needle. If you are shipping a CLI tool or a Lambda that imports a wide dependency tree before doing anything, profile first, then reach for lazy.

The Steering Council accepted PEP 810 unanimously after a 450-comment discussion thread. The demand was real. This is the most impactful addition in Python 3.15 for most developers.

UTF-8 Is Now the Default — Audit Your Code

open("file.txt") without an encoding= argument now uses UTF-8 everywhere, regardless of system locale. On Linux and macOS this was usually already the case. On Windows, the system locale was the default — typically cp1252 on Western installs.

That is the most likely source of silent regressions. Audit every open(), read_text(), and write_text() that does not specify an encoding. To restore the old behavior, pass encoding="locale".

Three things that are gone in Python 3.15:

  • datetime.utcnow() — use datetime.now(timezone.utc)
  • importlib.resources.read_text() — use importlib.resources.files()
  • Deprecated items from ast, ctypes, and typing

Run your test suite against Python 3.15 before upgrading production. The deprecation warnings were there in 3.13 and 3.14. Now the warnings are removals. See the official what’s new guide for the complete list.

The Python 3.15 JIT Is Finally Doing Something

The experimental JIT compiler ships enabled-but-off by default. You opt in:

PYTHON_JIT=1 python script.py
# or
python -X jit script.py

The pyperformance benchmark suite reports a 7–8% geometric mean improvement on x86-64 Linux and 11–12% on AArch64 (M1/M2 Macs). The range is wide — some microbenchmarks clock 20% slower, others exceed 100% faster. For CPU-bound work the gains are real. For I/O-bound code, you will not notice.

The JIT is not the default, and it should not be your default until you benchmark your specific workload. PyPy still wins on raw throughput. But after two release cycles of “promising but not yet,” 3.15 is the first version where turning it on might actually pay off.

frozendict Is Now a Built-In

The frozendict type ships in Python 3.15 with no import required. It is an immutable mapping — hashable when all keys and values are hashable, which makes it usable as a dictionary key or set member.

config = frozendict(debug=False, region="us-east-1")
cache_key = frozendict(model="gpt-6", temperature=0.7)

# Raises TypeError
config["debug"] = True

One caveat: frozendict does not inherit from dict, so isinstance(fd, dict) returns False. Update any type checks that expect a plain dict. The PyPI frozendict package — over two million downloads per month — is now a dependency you can drop.

Tachyon: The Profiler You Will Actually Use in Production

Python 3.15 adds profiling.sampling to the standard library — a sampling profiler that attaches to a running process with near-zero overhead. Unlike cProfile, which slows your program 2–3x by tracing every function call, Tachyon reads the call stack from a separate process at a fixed frequency. You can attach it to a live production app by PID.

python -m profiling.sampling myscript.py
python -m profiling.sampling --pid 12345

Flame graphs, async-aware sampling, and live top-style views are included. Tachyon is getting less coverage than lazy imports, but for anyone who has needed to debug a performance regression in production without reproducing it locally first, this is the more immediately useful addition.

How to Install Python 3.15 Now

# uv — now defaults to 3.15
uv python install 3.15
uv venv --python 3.15

# pyenv
pyenv install 3.15.0
pyenv global 3.15.0

# Docker
FROM python:3.15-slim

Python 3.10 reached end-of-life with this release. If your production environment is still on 3.10, you are now without security patches. Plan the migration now — Real Python’s lazy imports guide is the best starting point for understanding what changes, and the Astral blog covers uv 0.13.0, which ships Python 3.15 as its new default.

Python 3.15 is what the community is calling an “operations release”: lazy imports for faster starts, Tachyon for production observability, UTF-8 defaults for cross-platform consistency. Less a single headline feature, more a stack of improvements that make everyday Python development better. The lazy imports alone are reason enough to plan the upgrade.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:News