What's New in Python 3.15: Lazy Imports, frozendict, and a Fresh Profiling Story

By VersionLog Team
April 09, 2026
12 min read

Introduction

Python 3.15 delivers several changes that directly affect how you write, run, and debug Python code.

This release focuses on startup performance with explicit lazy imports, immutable data handling via a new built-in type, and better profiling tools.

Most teams will notice improvements in application startup times and easier performance analysis without heavy overhead.

What's New in Python 3.15: Lazy Imports, frozendict, and a Fresh Profiling Story

How Do Explicit Lazy Imports Work in Python 3.15?

Python 3.15 introduces the lazy soft keyword to defer module loading until the imported name is first used.

Write lazy import json or lazy from pathlib import Path at module level. The actual import happens transparently on first access.

This keeps imports tidy at the top of files while avoiding the cost of unused dependencies. In practice, large applications with deep import trees see measurable startup wins.

lazy import json
lazy from pathlib import Path

print("Starting up...")  # no loading yet

data = json.loads('{"key": "value"}')  # loads here
p = Path(".")  # loads here

The feature supports both regular and from-import styles. Exceptions surface at first use, with tracebacks that point to both the access site and the original lazy statement.

Can You Control Lazy Imports Globally or Selectively?

Use the -X lazy_imports command-line option or PYTHON_LAZY_IMPORTS environment variable to set behavior to all, none, or normal.

At runtime, call sys.set_lazy_imports(mode) and sys.get_lazy_imports(). For finer control, supply a filter function via sys.set_lazy_imports_filter().

Most teams will keep the default and add lazy only where it helps. The filter lets you make your own modules lazy while keeping third-party packages eager.

import sys

def myapp_filter(importing, imported, fromlist):
    return imported.startswith("myapp.")

sys.set_lazy_imports("all")
sys.set_lazy_imports_filter(myapp_filter)

Lazy imports are restricted to module scope. You cannot use them inside functions, classes, or try blocks. Star imports and future imports also stay forbidden.

What Is the New frozendict Built-in and Why Use It?

Python 3.15 adds frozendict to builtins as an immutable mapping type.

It inherits directly from object, not from dict. A frozendict is hashable when its keys and values are hashable, and it preserves insertion order for iteration while ignoring order in comparisons and hashing.

This matters because many teams already reach for third-party frozen dicts or tuples of pairs. Now the language provides a clean, built-in option that integrates with copy, json, pickle, and other modules.

a = frozendict(x=1, y=2)
b = frozendict(y=2, x=1)
print(a == b)          # True
print(hash(a) == hash(b))  # True
# a['z'] = 3 raises TypeError

Several standard library modules now accept frozendict where they previously expected mappings.

How Does the New Profiling Package Change Performance Work?

Python 3.15 introduces a dedicated profiling module that organizes profiling tools.

cProfile moves to profiling.tracing (with the old name kept as an alias), and the profile module is deprecated.

The headline addition is Tachyon, a high-frequency statistical sampling profiler in profiling.sampling. It runs with near-zero overhead and supports sampling rates up to one million hertz.

What Can You Do with the Tachyon Sampling Profiler?

Tachyon lets you attach to a running process by PID, profile scripts or modules, and choose wall-clock, CPU, GIL-holding, or exception modes.

It understands threads and async code, and outputs in multiple formats including pstats, collapsed stacks, flamegraphs, and heatmaps. You can also run a live TUI.

In practice, this makes production profiling far more practical than before. Teams can now gather data with minimal impact instead of relying solely on tracing profilers that slow code down.

How Has the JIT Compiler Improved in Python 3.15?

The experimental JIT received a significant upgrade, including LLVM 21, a new tracing frontend, basic register allocation, and more optimizations.

It now handles more bytecode instructions, object creation, overloaded operations, and generators. Reported speedups reach 6-7% on x86-64 Linux and 12-13% on AArch64 macOS in some workloads.

Most teams will not enable the JIT in production yet, but the direction is clear: better runtime performance is coming.

What Changed with Default Encoding and Error Messages?

open() and many I/O operations now default to UTF-8. You can opt out with PYTHONUTF8=0 or -X utf8=0. The encoding='locale' option remains for system locale behavior.

Error messages received small but useful polish. AttributeError suggestions now consider attributes accessed via members, and delattr() offers closer matches on failure. Unraisable exceptions appear highlighted by default.

These changes reduce friction in daily work and make tracebacks easier to read.

What Other Library and Core Improvements Stand Out?

Several modules received updates. The math module gained integer submodule plus functions like isnormal(), issubnormal(), fmax(), fmin(), and signbit().

bytearray adds take_bytes() for zero-copy extraction. Unpacking with * and ** now works inside comprehensions and generator expressions.

The slice type supports subscription and becomes generic. memoryview handles more complex float and double types.

Summary Table

Area Key Change Benefit
Imports lazy keyword (PEP 810) Faster startup for large apps
Data Types Built-in frozendict (PEP 814) Native immutable mappings
Profiling profiling module + Tachyon sampler (PEP 799) Low-overhead performance insights
Performance Upgraded JIT compiler Better runtime speed in supported cases
Encoding UTF-8 default for I/O Consistent modern behavior
Error Handling Improved AttributeError suggestions Faster debugging
Comprehensions * and ** unpacking support (PEP 798) Cleaner flattening of iterables

Conclusion

Python 3.15 refines the language in areas that affect real development work: startup time, data immutability, profiling, and everyday usability.

Start experimenting with lazy imports and the new profiling tools on non-critical code. The changes are stable enough for testing, and many will become part of standard workflows over time.

Tags: #python #python-3.15 #features #performance #profiling
VersionLog Team

VersionLog Team

Editorial Team

Curating the latest software releases, changelogs, and framework comparisons for developers.