Python: Modern Python Features

Python has evolved steadily since 3.6, adding features that make code more expressive, safer, and faster. Each release has introduced at least one idea worth learning. This tutorial walks through the most significant additions version by version, explaining not just what each feature does but why it was introduced and when you should reach for it.

Python 3.6: f-strings, Annotations, Numeric Underscores

Python 3.6 shipped three features that changed everyday coding habits. The first two are now considered standard style in any modern Python codebase.

f-strings: Readable String Interpolation

Python

f-strings replaced .format() as the preferred way to embed values into strings.

Variable Annotations and Numeric Underscores

Python

Annotating variables at the module and class level, and making large literals readable.

Python 3.7: dataclasses, breakpoint(), Guaranteed Dict Order

Python 3.7 formalised two things that had been informally true or partially available. Dictionaries had maintained insertion order in CPython 3.6 as an implementation detail; 3.7 made it part of the language specification. The @dataclass decorator arrived as a standard way to eliminate class boilerplate. And breakpoint() gave developers a built-in, configurable hook into any debugger.

@dataclass: Auto-generated Boilerplate

Python

Python 3.7 introduced @dataclass in the standard library. See the Advanced Concepts tutorial for the full reference; here is a brief reminder of its core value.

Guaranteed Dict Order and breakpoint()

Python

Insertion order is now part of the spec, and breakpoint() replaces the pdb import idiom.

Python 3.8: Walrus Operator, Positional-only Parameters, f-string =

Python 3.8 is notable for three additions that all reduce unnecessary repetition in different contexts. The walrus operator eliminates a read-then-assign pattern that was previously unavoidable. Positional-only parameters give library authors more freedom in designing stable APIs. The = specifier inside f-strings cuts the most common debugging print statement down to a single line.

Walrus Operator :=

Python

Assigning and testing a value in a single expression, most useful in while loops and comprehensions.

Positional-only Parameters

Python

Using / in a function signature to prevent callers from passing arguments by keyword.

f-string = Specifier

Python

Printing both the expression and its value in a single f-string for quick debugging.

Python 3.9: Dict Merge Operator and Built-in Generics

Python 3.9 brought two changes that directly reduce the amount of boilerplate in everyday code. The dict merge and update operators give you a cleaner way to combine mappings. The built-in generic types change means you no longer need to importList, Dict, Tuple, and Set from typing just to write type annotations.

Dict Merge | and Update |= Operators

Python

Combining dictionaries without dict() or {**a, **b} unpacking.

Built-in Generic Types in Annotations

Python

Using list, dict, tuple, set, and frozenset directly as generics without importing from typing.

Python 3.10: match-case, Better Error Messages, X | Y Union

Python 3.10 is one of the more significant releases in recent years. Structural pattern matching adds an expressive dispatch mechanism that goes well beyond what a chain ofif/elif can do. The improved error messages are a quality-of-life improvement that makes Python more approachable, especially for beginners. And the X | Yunion syntax at runtime brings annotation syntax into line with how developers actually think about optional values.

match-case: Structural Pattern Matching

Python

Matching on values, types, sequences, mappings, and class structures in a single statement.

Class Pattern Matching and Guards

Python

Matching on class instances and adding conditional guards to cases.

X | Y Union Syntax and Better Error Messages

Python

Using | for union types at runtime and what improved error messages look like.

Python 3.11: ExceptionGroup, tomllib, Faster CPython

Python 3.11 made a substantial investment in performance. The CPython team reported 10 to 60 percent speed improvements on the standard benchmark suite compared to 3.10, achieved through specialised adaptive bytecode interpretation. Beyond performance, 3.11 formalised two things that lacked standard solutions: parsing TOML configuration files, and handling multiple concurrent exceptions cleanly.

ExceptionGroup and except*

Python

Raising and handling multiple exceptions simultaneously, the pattern asyncio.TaskGroup uses.

tomllib: Reading TOML Configuration

Python

Python 3.11 added a built-in TOML reader so you no longer need a third-party package for config files.

Python 3.11 Performance Improvements

The 3.11 release was the result of the Faster CPython project, a dedicated effort to systematically improve interpreter performance.

  • Specialised adaptive interpreter: bytecode is instrumented during execution and specialised for the actual types being used, reducing per-operation overhead.
  • Faster Python call overhead: calling Python functions is significantly cheaper due to a redesigned frame structure.
  • Zero-cost exceptions: try blocks with no exception have virtually no overhead when no exception is raised.
  • Fine-grained error locations: tracebacks pinpoint the exact sub-expression that failed, not just the line.

Python 3.12: Type Parameter Syntax, f-string Improvements, @override

Python 3.12 focused on cleaning up two rough edges: the verbosity of generic type declarations and the limitations of f-strings. It also added an @overridedecorator that makes class hierarchies safer to refactor.

Type Parameter Syntax: Inline Generic Declarations

Python

Declaring type variables directly in the def and class statement, without importing TypeVar.

f-string Improvements in Python 3.12

Python

Nesting quotes freely and using backslashes inside f-string expressions.

@override Decorator

Python

Marking intentional overrides so type checkers warn when the base method changes.

Python 3.13: Free-threaded Mode and Experimental JIT

Python 3.13 is arguably the most architecturally significant release since Python 3.0. It ships two experimental features that address the two longest-standing criticisms of CPython: the GIL and interpreter speed. Both are opt-in and explicitly labelled experimental, meaning the API can change and production use requires careful evaluation. But they represent a credible path to a fundamentally more capable CPython.

Free-threaded Mode: Python Without the GIL

Python

How to use the no-GIL build and what it enables for CPU-bound multithreading.

Experimental JIT Compiler

Python

How the JIT works conceptually and how to enable it in Python 3.13.

Python 3.13 Other Notable Changes

Beyond free-threading and the JIT, Python 3.13 shipped several quality-of-life improvements.

  • Improved interactive interpreter (REPL): multi-line editing, colour output, and paste mode via F3.
  • Better error messages continued: even more precise suggestions for common mistakes like misspelled attribute names.
  • Removed deprecated modules: aifc, audioop, cgi, cgitb, chunk, crypt, imghdr, mailcap, msilib, nis, nntplib, ossaudiodev, pipes, sndhdr, spwd, sunau, telnetlib, uu, and xdrlib were removed after years of deprecation warnings.
  • PEP 667: locals() now returns a proper mapping that reflects changes to local variables, fixing a long-standing inconsistency.

Quick Reference: Feature by Version

When working on a project, the Python version specified in pyproject.toml or your CI configuration determines which features you can use. This summary helps you quickly identify the minimum version a feature requires.

Feature Availability by Python Version

Each line lists the minimum Python version and the feature it introduced.

  • 3.6: f-strings, variable annotations, underscores in numeric literals, secrets module.
  • 3.7: @dataclass, breakpoint(), guaranteed dict insertion order, asyncio.run().
  • 3.8: walrus operator :=, positional-only parameters (/), f-string = specifier, TypedDict.
  • 3.9: dict | merge operator, list[int] and dict[str, int] as generic annotations, zoneinfo module.
  • 3.10: match-case structural pattern matching, X | Y union at runtime, parenthesised context managers, better error messages.
  • 3.11: ExceptionGroup, except*, tomllib, asyncio.TaskGroup, fine-grained tracebacks, 10-60% speed improvement.
  • 3.12: type parameter syntax def f[T](), type alias statement, @override, improved f-strings, pathlib improvements.
  • 3.13: free-threaded (no-GIL) build, experimental JIT, improved REPL, PEP 667 locals().

Quiz - Test Your Knowledge

Ten questions spanning Python 3.6 through 3.13, covering f-string specifiers, the walrus operator, positional-only parameters, the dict merge operator, built-in generics, structural pattern matching, ExceptionGroup, the @override decorator, free-threaded mode, and the 3.9 annotation changes. Each question tests understanding of a specific feature, not just recognition of the syntax.

Knowledge Check

1. What is the f-string debugging specifier introduced in Python 3.8?

2. What does the walrus operator := do in Python 3.8?

3. What is a positional-only parameter in Python 3.8, and how is it declared?

4. What does the | operator do when applied to two dicts in Python 3.9?

5. What does a match-case statement in Python 3.10 do that a chain of if/elif cannot?

6. What is an ExceptionGroup in Python 3.11, and when does one arise?

7. What is the new type parameter syntax introduced in Python 3.12?

8. What does the @override decorator introduced in Python 3.12 do?

9. What is the free-threaded mode introduced experimentally in Python 3.13?

10. In Python 3.9+, which of the following is a valid type hint that was NOT valid before 3.9?