Python 3.15 lands: UTF-8 by default, frozendict built in, a slightly faster JIT
Python 3.15.0 shipped on October 9 with 5,643 commits from 1,012 contributors. What UTF-8 defaults, lazy imports, frozendict and the JIT change for you.
Python 3.15.0 was released on October 9: 5,643 commits from 1,012 contributors, per the official page. As I write this it has already been superseded by 3.15.1 — which is itself the reminder not to put a brand-new major on production immediately.
The change most likely to bite: UTF-8 by default
PEP 686 makes UTF-8 the default encoding. On Linux and macOS that is “finally”; on Windows scripts that relied on the system code page (GBK, cp1252) it is a behaviour change: the default for open() without encoding, the paths around locale.getpreferredencoding(), and how subprocess and filenames are handled all shift.
The useful pre-upgrade action isn’t reading the PEP, it’s grepping your project for every open(), subprocess call and Path.read_text() that omits an encoding and pinning it explicitly. This change never raises — it quietly corrupts the one input with a Chinese character or an accent in it.
Language level: lazy imports and two built-in types
- PEP 810, explicit lazy imports: defers imports until first use, which buys startup time. The cost is that module side effects happen later, so plugin-style code that relies on “import means registered” needs review.
- PEP 814,
frozendict: an immutable dict finally in builtins. Before, you either usedMappingProxyType(unhashable) or wrapped one yourself; now it is a real type you can use as a cache key. - PEP 661,
sentinel: a proper sentinel type for “no value provided”, replacing theobject()idiom that only worked by identity. - PEP 798, unpacking in comprehensions and PEP 829, package startup configuration files: the former makes unpacking inside comprehensions natural; the latter moves “things a package does at startup” into declarative configuration.
JIT: small numbers, right direction
The official figures are geometric means: 7–8% faster than the standard interpreter on x86-64 Linux, and 11–12% faster than the tail-calling interpreter on AArch64 macOS. Note the baselines differ — the second is against the tail-calling interpreter, not against 3.14’s default configuration. Don’t mix them when quoting.
Profiling and typing
PEP 799 brings Tachyon, a high-frequency statistical sampling profiler, plus a dedicated package for organising Python profiling tools. For “sample production traffic cheaply”, that is a step up from what cProfile realistically offers.
On typing: PEP 728 lets TypedDict declare extra allowed keys (previously you flattened everything with total=False), and PEP 747 introduces TypeForm for annotating type expressions themselves.
The judgement
3.15 has no “match statement” moment, but it pays off three long-standing debts: the encoding default, an immutable dict, and a credible sampling profiler. Upgrade order: run your test suite on 3.15 in CI first (watch encoding-sensitive assertions), then talk about production — and go straight to 3.15.1 there.
Source: the official Python release page, “Python 3.15.0” (2026-10-09).

Comments
…