Latest Python Features

Latest Python Features

This article explains the latest features of Python.

We will explain the notable features of the Python 3.12 to 3.13 generations step by step from a practical standpoint of 'immediately usable' applications.

YouTube Video

Latest Python Features

In recent years, Python has evolved with an emphasis not only on 'ease of writing' but also on 'robustness, speed, and readability'. Below, we introduce the notable features from Python 3.12 to 3.13 generations.

Dramatic Improvements in Error Messages (Python 3.12)

In Python 3.12, errors are now displayed in a more concrete and visual manner. You can instantly identify where mistakes are made and significantly reduce debugging time.

1def calc_total(price, tax):
2    return price + price * tax
3
4result = calc_total(100, )
  • Missing arguments are shown with the relevant line and location, so you won't get confused when identifying the cause.

Practical Use of 'match' Statement (Structural Pattern Matching)

The 'match' statement allows you to describe complex condition branches and data structure discrimination declaratively. Handling dictionaries and nested structures becomes especially more readable.

1user = {"status": "active", "name": "Alice"}
2
3match user:
4    case {"status": "active", "name": name}:
5        print(f"Welcome back, {name}!")
6    case {"status": "inactive"}:
7        print("Please activate your account.")
8    case _:
9        print("Unknown user status.")
  • Because you can perform condition branching and data extraction simultaneously, nesting if statements becomes unnecessary.

Intuitive pattern matching for handling nested data

The 'match' statement is also effective for structured data such as JSON or API responses.

1data = {"user": {"name": "Bob", "age": 25}}
2
3match data:
4    case {"user": {"name": name, "age": age}}:
5        print(f"{name} is {age} years old.")
  • You can extract only the necessary elements safely, reducing the need for defensive code.

Enhanced f-string Debug Output (=` notation / Python 3.8 and later, improved usability)

With f-strings, you can now add = to display both the expression itself and its evaluation result at the same time. This feature is specialized for debugging and is extremely useful when you want to quickly check the contents of a variable.

1x = 10
2y = 20
3print(f"{x=}, {y=}, {x+y=}")
  • Because variable names and values are displayed together, temporary debugging with print() statements becomes easier to read.
  • You can write log outputs and verification code more concisely and in a more expressive way.

Simplified Type Hints and 'type' Alias (Python 3.12: New Type Alias Syntax)

In Python 3.12, a dedicated syntax for defining type aliases— the type statement—was introduced. This allows type hints to function not merely as supplementary information but also as a language element to clearly express design intent.

1type UserId = int
2type UserName = str
3
4def greet(user_id: UserId, name: UserName) -> str:
5    return f"Hello, {name} (id={user_id})"
  • By giving meaning to UserId or UserName, the differences in roles can be clarified even if both use the same int or str type.
  • Type definitions become more concise, reducing the cost of understanding during code review and maintenance.
  • Previously, type aliases such as UserId = int were created by assignment, but using the type statement makes it explicit that 'this is a type definition'. This is especially effective for improving design readability in medium-sized and larger code bases.

Natural Type Annotations Using Built-in Types (Simplified Generics from Python 3.9+)

Since Python 3.9, you can use built-in types like list or dict directly as generics.

This allows you to write intuitive and readable type hints without importing types from the typing module.

1def sum_numbers(numbers: list[int]) -> int:
2    return sum(numbers)
3
4print(sum_numbers([1, 2, 3, 4]))
  • Type hints function not as 'constraints', but as 'documentation that explains processing contents'.

Safe Method Chaining with the Self Type (Python 3.11 and later)

Since Python 3.11, you can specify Self as the return type for methods that return the class itself.

This allows you to safely write method chaining code without losing type information.

 1from typing import Self
 2
 3class Counter:
 4    def __init__(self, value: int = 0) -> None:
 5        self.value = value
 6
 7    def increment(self) -> Self:
 8        self.value += 1
 9        return self
10
11counter = Counter()
12counter.increment().increment()
13print(counter.value)
  • Even for methods returning self, the correct return type is preserved.
  • IDEs and type checkers can accurately understand method chaining.

Clearer String Manipulation (removeprefix / removesuffix | Python 3.9 and later)

From Python 3.9, specialized methods str.removeprefix() and str.removesuffix() have been added to safely remove prefixes and suffixes from strings. With these, you can accurately express the intent of 'removing only the beginning or end' in your code.

1filename = "report_2026.txt"
2
3clean_name = filename.removeprefix("report_")
4name_without_ext = clean_name.removesuffix(".txt")
5
6print(name_without_ext)
  • The specified string is removed only if it exists at the beginning or the end, preventing unintended replacements.
  • This approach provides better readability and safety than using replace() or slicing.
  • Especially for handling 'strings with a defined format', such as file names or URL preprocessing, using these methods can greatly reduce the risk of bugs.

Robust String Comparison for Internationalization (str.casefold() | Unicode Support)

str.casefold() in Python is a method for case-insensitive comparison that considers Unicode. Unlike simple lower() or upper(), it normalizes strings, including language-specific character conversion.

1text1 = "Stra\u00dfe"
2text2 = "strasse"
3
4print(text1)
5print(text2)
6
7print(f"Comparison Result: {text1.casefold() == text2.casefold()}")
  • It can properly handle language-dependent differences such as German ß and ss.
  • This is an essential technique for applications based on multilingual support or internationalization.

Standard TOML Support (tomllib | Python 3.11 and later)

From Python 3.11 onward, the tomllib module for reading TOML configuration files has been added to the standard library. Configuration management can now be completed solely in Python, without depending on external libraries.

 1import tomllib
 2
 3with open("config.toml", "rb") as f:
 4    config = tomllib.load(f)
 5
 6print(config["database"]["host"])
 7
 8# config.toml
 9# title = "TOML Example"
10# [database]
11# host = "192.168.1.1"
12# ports = [ 8001, 8001, 8002 ]
  • External packages like toml are no longer needed, simplifying your dependencies.
  • Configuration file loading is standardized, making distribution, operation, and CI environments easier to handle.

Exception Handling for the Age of Parallel Processing (ExceptionGroup / except* | Python 3.11 and later)

Python 3.11 introduced ExceptionGroup to handle multiple exceptions together and the except* syntax to handle them safely in branches. This is a new feature to handle 'simultaneous errors' appearing in asynchronous or parallel processing.

 1def process(values):
 2    errors = []
 3    for v in values:
 4        if v < 0:
 5            errors.append(ValueError(f"Negative value: {v}"))
 6    if errors:
 7        raise ExceptionGroup("Invalid values", errors)
 8
 9try:
10    process([1, -2, -3])
11except* ValueError as e:
12    print("Handled:", e)
  • Multiple exceptions can now be raised and classified in a single operation.
  • It addresses the problem in asynchronous processing where only the first error could be seen.
  • In operations like asyncio.gather() or parallel batch processing, multiple failure factors can occur simultaneously. Using ExceptionGroup makes it easier to organize error collection, logging, and retry strategies.

Performance Improves Simply by Updating to the Latest Version

From Python 3.11 onward, many processes have been made faster through internal optimizations.

1def count_up(n):
2    total = 0
3    for i in range(n):
4        total += i
5    return total
6
7print(count_up(1_000_000))
  • A major advantage is that speed improvements can be achieved without rewriting your code.

Controlling Garbage Collection (Explicit Management via gc Module)

In Python, using the standard gc module lets you temporarily disable or manually execute garbage collection. This is an effective optimization technique in scenarios such as batch processing of large data sets or performance-critical operations.

1import gc
2
3gc.disable()
4# heavy batch processing
5gc.enable()
6gc.collect()
  • Suppressing unnecessary garbage collection triggers can reduce fluctuations in processing time.
  • You can explicitly collect at process intervals, making memory usage easier to track.
  • However, this technique should not be used as a default optimization but only considered if profiling shows GC is a bottleneck. For most applications, it is safest to rely on Python's automatic garbage collection.

Summary

With improvements in error messages and the evolution of type hints in the Python 3.12 to 3.13 generation, understanding and maintaining code has become easier than ever before. Additionally, enhancements such as better debugging experiences and performance improvements through internal optimization are steadily making direct contributions to productivity in practice. You don't need to use all these new features at once; it's practical to start with the latest Python version and gradually incorporate features as needed. This gradual adoption leads to more readable and robust Python code.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video