Python 3.12+ - Modern Python Features Explained
Python 3.12 and later introduced powerful features that make code more readable, performant, and maintainable while preserving backward compatibility.
From structural pattern matching to enhanced type hints and faster runtime performance, modern Python enables cleaner, more expressive code.
This tutorial covers essential Python 3.12+ features with practical examples to help you write production-ready Python confidently.
Advanced Type Hints
Type hints have evolved with literal types, TypedDict, and better generic support for more precise static analysis.
from typing import Literal, TypedDict, Any, Optional
from dataclasses import dataclass
# Literal types
Status = Literal['pending', 'approved', 'rejected']
def set_status(status: Status) -> None:
pass
# TypedDict for structured data
class UserDict(TypedDict):
id: int
name: str
email: str
# Generic type aliases
type UserId = int | str
@dataclass
class User:
id: UserId
name: str
role: Literal['admin', 'user'] = 'user'
Use mypy or pyright for static type checking in your IDE for immediate feedback.
Structural Pattern Matching (match/case)
Introduced in Python 3.10, enhanced in 3.12, pattern matching provides powerful data destructuring and control flow.
def process_event(event: dict) -> str:
match event:
case {'type': 'click', 'target': target, 'x': x, 'y': y}:
return f"Click at ({x}, {y}) on {target}"
case {'type': 'key', 'key': 'Enter'}:
return "Enter pressed"
case {'type': 'key', 'key': k}:
return f"Key {k} pressed"
case _:
return "Unknown event"
# Class pattern matching
class Point:
def __init__(self, x: int, y: int):
self.x, self.y = x, y
match point := Point(3, 4):
case Point(x, 0):
print(f"Point on x-axis: {x}")
case Point(0, y):
print(f"Point on y-axis: {y}")
case _:
print(f"Point at ({point.x}, {point.y})")
Walrus Operator and F-Strings
The walrus operator (:=) assigns and tests in one expression. F-strings gained self-documenting expressions and nested formatting.
# Walrus operator
while (user_input := input('Enter text (or q to quit): ')) != 'q':
print(f'You entered: {user_input}')
# Self-documenting f-strings (3.12+)
def format_price(price: float, currency: str = 'USD') -> str:
return f'{price=:,.2f} {currency}'
print(format_price(1234.567)) # $1,234.57 USD
# Nested f-strings
name = 'Alice'
age = 25
f'{f"User {{name={name}, age={age}}}"}'
Dataclasses and Enhanced Defaults
Dataclasses reduce boilerplate for data classes. Python 3.12+ improves field defaults and validation.
from dataclasses import dataclass, field, asdict
from typing import ClassVar
@dataclass(frozen=True)
class Product:
name: str
price: float
stock: int = 0
# Computed field
total_value: float = field(init=False)
def __post_init__(self):
self.total_value = self.price * self.stock
@dataclass
class Order:
items: list[Product] = field(default_factory=list)
customer_id: int
def add_item(self, product: Product) -> None:
self.items.append(product)
# Usage
product = Product('Laptop', 999.99, 5)
print(asdict(product))
Async/Await Improvements
Python 3.12 brings faster async performance and better exception handling in async code.
import asyncio
import aiohttp
from typing import List
async def fetch_user(session: aiohttp.ClientSession, user_id: int) -> dict:
async with session.get(f'/api/users/{user_id}') as response:
return await response.json()
async def fetch_all_users(user_ids: List[int]) -> List[dict]:
async with aiohttp.ClientSession() as session:
tasks = [fetch_user(session, uid) for uid in user_ids]
return await asyncio.gather(*tasks, return_exceptions=True)
# Usage
asyncio.run(fetch_all_users([1, 2, 3, 4]))
Comprehensions and Generators
Python's comprehensions and generators remain powerful. Modern patterns leverage type hints and walrus operator.
# Dictionary comprehension with walrus
files = ['data1.json', 'data2.json']
file_sizes = {
f: (size := len(open(f, 'rb').read()))
for f in files
}
# Nested comprehensions
matrix = [[1, 2, 3], [4, 5, 6]]
flattened = [item for row in matrix for item in row]
# Generator with type hints
def read_large_file(path: str):
with open(path, 'r') as f:
for line_num, line in enumerate(f, 1):
yield line_num, line.strip()
Other Essential Features
- Improved error messages with suggestion hints
- Better f-string debugging (= specifier)
- Flexible function annotations
- Buffer Protocol optimizations for 10-60% speed gains
- Per-interpreter GIL for better multiprocessing
- Experimental free-threaded build (no GIL)
def divide(a: float, b: float) -> float:
if b == 0:
raise ValueError('Cannot divide by zero')
return a / b
# Debug f-string
price: float = 19.99
print(f'{price=:.2f}') # price=19.99
# Python 3.12+ error messages are much clearer
Conclusion
Python 3.12+ combines decades of refinement with cutting-edge features for maximum productivity and performance.
Master type hints, pattern matching, dataclasses, and async patterns to write maintainable, scalable applications.
Upgrade to Python 3.12+ and leverage these features in your next project for cleaner, faster code.
Codecrown