Jorge Turbica / blog · Blog ← All articles ES · Leer en español
Languages

Python 3.15 is final: lazy imports, frozendict and UTF-8 by default

Python 3.15.0 ships lazy imports, frozendict, UTF-8 by default and a new profiler. What to check before upgrading your services.

Python 3.15.0 is now final (announced on 9 October 2026). It is a release with plenty of pieces that touch daily life for anyone running services in production: lazy imports for faster startup, a built-in sampling profiler, frame pointers enabled by default, and a change of default encoding that deserves careful testing.

What changes

According to the official announcement, the main additions are:

  • Interpreter: a sentinel built-in type (PEP 661), UTF-8 as the default encoding (PEP 686), unpacking in comprehensions (PEP 798), explicit lazy imports (PEP 810), the frozendict built-in (PEP 814), package startup configuration files (PEP 829) and better error messages.
  • Standard library: a dedicated profiling package and the Tachyon high-frequency sampling profiler (PEP 799), plus more colour output.
  • Typing: TypedDict with typed extra items (PEP 728), TypeForm (PEP 747) and disjoint bases (PEP 800).
  • C API: PyBytesWriter (PEP 782), protection against finalization (PEP 788), and a stable ABI for free-threaded builds (PEPs 803, 820 and 793).
  • Build: frame pointers enabled by default for system-level observability (PEP 831).

The experimental JIT gets a significant upgrade: a 7–8% geometric mean improvement over the standard interpreter on x86-64 Linux and 11–12% over the tail-calling interpreter on AArch64 macOS. Official macOS binaries now install free-threading support by default, and official 64-bit Windows binaries use the tail-calling interpreter.

Why it matters in production

As an SRE, the JIT is not what interests me most; three other things are. First, lazy imports (PEP 810): in CLIs, serverless functions and workers that start often, import time tends to dominate cold starts. Second, default frame pointers (PEP 831) and the Tachyon profiler: they make it easier to profile a Python process with system-level tools without rebuilding anything. Third, UTF-8 by default (PEP 686): this is the change most likely to surprise you, because code that opens files without an explicit encoding and relies on the locale may now behave differently. The announcement lists it as a feature and does not describe the compatibility impact, so read the "What's New" documentation before assuming anything.

There is also one concrete warning: on macOS 27.0, IDLE and other tkinter apps may hang when opening dialogs because of an OS behaviour change, and the project suggests waiting for a workaround (issue #158053). It does not affect Linux servers, but it does affect developer laptops.

What I would do

  1. Read the full "What's New in Python 3.15", especially the deprecation and removal sections the announcement does not enumerate.
  2. Add 3.15 to the CI matrix as a non-blocking job and run the suite with warnings as errors:
bash
python3.15 -W error -m pytest -q
  1. Grep for open( without encoding= and read_text() without an explicit encoding, and pin encoding="utf-8" wherever behaviour must stay stable.
  2. Measure startup before and after with python3.15 -X importtime -c "import my_app" and find which imports are worth making lazy.
  3. Try the JIT and free-threading only in an isolated environment with your own benchmarks: the published gain is an average and may not reflect your workload.
  4. Do not upgrade production until your dependencies publish wheels for 3.15.

Sources

Jorge Turbica

Software Engineer and SRE. I write about the real challenges I run into in production.

See portfolio ↗