What's new in Python 3.15

Python 3.15 introduces several new features and optimizations that enhance language flexibility, performance, and developer ergonomics. Below is a deeper dive into the key changes with code snippets to demonstrate their usage.

1. Pattern Matching Enhancements

Python 3.15 introduces more expressive and flexible patterns in the match statement, enabling concise matching of complex data structures.

New match Syntax Example:

def process_data(data):
    match data:
        case {"type": "success", "value": val}:
            print(f"Success with value: {val}")
        case {"type": "error", "message": msg}:
            print(f"Error occurred: {msg}")
        case _:
            print("Unknown type")

In 3.15, patterns can be even more nuanced by allowing easier nested destructuring or using new pattern matching syntax enhancements, such as explicit type annotations inside patterns.

def process(data):
    match data:
        case int(val):
            print(f"Got integer: {val}")
        case list([_, *rest]):
            print(f"List with remaining elements: {rest}")
        case _:
            print("Unhandled type")

2. Buffer Protocol Enhancements

Python 3.15 refines the buffer protocol which improves the way objects expose memory buffers. This allows direct memory access without copying, crucial for performance-sensitive applications.

# Example of using buffer protocol with memoryview
import array

arr = array.array('I', [1, 2, 3, 4])
buf = memoryview(arr)

print(buf.format)  # Outputs 'I', the format of the data
print(buf[1])      # Direct access to array element without a copy

Libraries like NumPy and PIL benefit from these improvements by avoiding unnecessary memory copies when working with large datasets or images.

3. Performance Improvements

Python 3.15 includes a range of performance improvements, notably in function calls and attribute access. Internal optimizations reduce overhead, yielding significant speedups in everyday code.

Example: Faster Function Calls

def foo(x):
    return x + 1

%timeit foo(10)  # Optimized for faster calls

A notable optimization includes better handling of function calls where less internal bookkeeping is necessary, making standard function calls (especially within tight loops) faster.

4. New Syntax for Decorators

Python 3.15 introduces a more flexible syntax for decorators, allowing a cleaner and more concise declaration.

# Before
@outer_decorator(inner_decorator(arg))
def my_function():
    pass

# Python 3.15 allows you to:
@outer_decorator
@inner_decorator(arg)
def my_function():
    pass

This separation of decorators improves readability in cases with multiple nested decorators.

5. Frozen (Immutable) Dictionaries

Python 3.15 introduces frozen dictionaries, allowing the creation of immutable dictionaries. This can be used when you need hashable dictionaries for sets or as dictionary keys.

from types import MappingProxyType

mutable_dict = {'a': 1, 'b': 2}
frozen_dict = MappingProxyType(mutable_dict)

# This will raise an exception
# frozen_dict['a'] = 3

These frozen dictionaries ensure immutability at runtime, making them safe to use in cases where you want guarantees that your dictionary data will not be modified.

6. Typed **kwargs

Type hinting for **kwargs has been enhanced in Python 3.15, allowing for more specific type annotations of keyword arguments.

def foo(**kwargs: int) -> None:
    print(kwargs)

foo(a=1, b=2)  # OK
foo(a="str")   # Type checker will flag this as incorrect

The new type hinting syntax for **kwargs helps ensure that only arguments of a specified type can be passed as keyword arguments, improving code clarity and reducing runtime errors.

7. Async Comprehensions with async for

Python 3.15 improves async for comprehension support, allowing you to write asynchronous comprehensions in a more natural syntax.

# Example of async comprehensions
async def get_values():
    return [x async for x in some_async_iterator() if x > 10]

This feature simplifies working with asynchronous iterators in comprehensions, providing a cleaner, more Pythonic approach to async operations.

8. Improved concurrent.futures

Python 3.15 optimizes concurrent.futures with better handling of asynchronous tasks and thread pools, ensuring that futures are more efficiently managed.

from concurrent.futures import ThreadPoolExecutor

def task(n):
    return n * 2

with ThreadPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(task, range(10)))
print(results)

9. Enhanced Error Messages

Error messages are more descriptive in Python 3.15, providing additional context to help diagnose issues. For example, a TypeError involving argument mismatches will show clearer details about where the mismatch occurs.

Example: Improved TypeError

def foo(x: int, y: str) -> None:
    pass

foo(10, 20)  # Raises a more informative error: TypeError: expected 'str' for 'y', but got 'int'

10. Improved SSL/TLS and Cryptography

The ssl and secrets modules in Python 3.15 have been improved to support more robust security standards and cryptographic algorithms. This is crucial for applications dealing with sensitive information.

import ssl

context = ssl.create_default_context()
context.minimum_version = ssl.TLSVersion.TLSv1_3  # Enforce modern TLS standards

11. Cross-Interpreter Communication (Subinterpreters)

Python 3.15 improves support for subinterpreters, an experimental feature that allows multiple Python interpreters to run in parallel and communicate. This lays the groundwork for better concurrency without the limitations of the GIL.

import _xxsubinterpreters as interpreters

interp = interpreters.create()  # Creates a new interpreter
interpreters.run_string(interp, 'print("Hello from subinterpreter")')

12. Deprecations and Removals

Some legacy features are deprecated in Python 3.15:

  • Legacy string module methods like string.uppercase and string.lowercase are officially deprecated.
  • Older C API components are being phased out in favor of newer, more efficient mechanisms.

Python 3.15 emphasizes performance, safety, and new language constructs to further optimize both everyday coding patterns and more advanced concurrency models. If you're migrating or upgrading, it's important to take advantage of these new features to write faster, more robust Python code.