What’s New In Python 3.12 (original) (raw)

Editor:

Adam Turner

This article explains the new features in Python 3.12, compared to 3.11. Python 3.12 was released on October 2, 2023. For full details, see the changelog.

See also

PEP 693 – Python 3.12 Release Schedule

Summary – Release highlights

Python 3.12 is a stable release of the Python programming language, with a mix of changes to the language and the standard library. The library changes focus on cleaning up deprecated APIs, usability, and correctness. Of note, the distutils package has been removed from the standard library. Filesystem support in os and pathlib has seen a number of improvements, and several modules have better performance.

The language changes focus on usability, as f-strings have had many limitations removed and ‘Did you mean …’ suggestions continue to improve. The new type parameter syntaxand type statement improve ergonomics for using generic types and type aliases with static type checkers.

This article doesn’t attempt to provide a complete specification of all new features, but instead gives a convenient overview. For full details, you should refer to the documentation, such as the Library Referenceand Language Reference. If you want to understand the complete implementation and design rationale for a change, refer to the PEP for a particular new feature; but note that PEPs usually are not kept up-to-date once a feature has been fully implemented.


New syntax features:

New grammar features:

Interpreter improvements:

Python data model improvements:

Significant improvements in the standard library:

Security improvements:

C API improvements:

CPython implementation improvements:

New typing features:

Important deprecations, removals or restrictions:

New Features

PEP 695: Type Parameter Syntax

Generic classes and functions under PEP 484 were declared using a verbose syntax that left the scope of type parameters unclear and required explicit declarations of variance.

PEP 695 introduces a new, more compact and explicit way to creategeneric classes and functions:

def max[T](args: Iterable[T]) -> T: ...

class list[T]: def getitem(self, index: int, /) -> T: ...

def append(self, element: T) -> None:
    ...

In addition, the PEP introduces a new way to declare type aliasesusing the type statement, which creates an instance ofTypeAliasType:

type Point = tuple[float, float]

Type aliases can also be generic:

type Point[T] = tuple[T, T]

The new syntax allows declaring TypeVarTupleand ParamSpec parameters, as well as TypeVarparameters with bounds or constraints:

type IntFunc[**P] = Callable[P, int] # ParamSpec type LabeledTuple[*Ts] = tuple[str, *Ts] # TypeVarTuple type HashableSequence[T: Hashable] = Sequence[T] # TypeVar with bound type IntOrStrSequence[T: (int, str)] = Sequence[T] # TypeVar with constraints

The value of type aliases and the bound and constraints of type variables created through this syntax are evaluated only on demand (seelazy evaluation). This means type aliases are able to refer to other types defined later in the file.

Type parameters declared through a type parameter list are visible within the scope of the declaration and any nested scopes, but not in the outer scope. For example, they can be used in the type annotations for the methods of a generic class or in the class body. However, they cannot be used in the module scope after the class is defined. See Type parameter lists for a detailed description of the runtime semantics of type parameters.

In order to support these scoping semantics, a new kind of scope is introduced, the annotation scope. Annotation scopes behave for the most part like function scopes, but interact differently with enclosing class scopes. In Python 3.13, annotations will also be evaluated in annotation scopes.

See PEP 695 for more details.

(PEP written by Eric Traut. Implementation by Jelle Zijlstra, Eric Traut, and others in gh-103764.)

PEP 701: Syntactic formalization of f-strings

PEP 701 lifts some restrictions on the usage of f-strings. Expression components inside f-strings can now be any valid Python expression, including strings reusing the same quote as the containing f-string, multi-line expressions, comments, backslashes, and unicode escape sequences. Let’s cover these in detail:

See PEP 701 for more details.

As a positive side-effect of how this feature has been implemented (by parsing f-strings with the PEG parser), now error messages for f-strings are more precise and include the exact location of the error. For example, in Python 3.11, the following f-string raises a SyntaxError:

my_string = f"{x z y}" + f"{1 + 1}" File "", line 1 (x z y) ^^^ SyntaxError: f-string: invalid syntax. Perhaps you forgot a comma?

but the error message doesn’t include the exact location of the error within the line and also has the expression artificially surrounded by parentheses. In Python 3.12, as f-strings are parsed with the PEG parser, error messages can be more precise and show the entire line:

my_string = f"{x z y}" + f"{1 + 1}" File "", line 1 my_string = f"{x z y}" + f"{1 + 1}" ^^^ SyntaxError: invalid syntax. Perhaps you forgot a comma?

(Contributed by Pablo Galindo, Batuhan Taskaya, Lysandros Nikolaou, Cristián Maureira-Fredes and Marta Gómez in gh-102856. PEP written by Pablo Galindo, Batuhan Taskaya, Lysandros Nikolaou and Marta Gómez).

PEP 684: A Per-Interpreter GIL

PEP 684 introduces a per-interpreter GIL, so that sub-interpreters may now be created with a unique GIL per interpreter. This allows Python programs to take full advantage of multiple CPU cores. This is currently only available through the C-API, though a Python API is anticipated for 3.13.

Use the new Py_NewInterpreterFromConfig() function to create an interpreter with its own GIL:

PyInterpreterConfig config = { .check_multi_interp_extensions = 1, .gil = PyInterpreterConfig_OWN_GIL, }; PyThreadState tstate = NULL; PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config); if (PyStatus_Exception(status)) { return -1; } / The new interpreter is now active in the current thread. */

For further examples how to use the C-API for sub-interpreters with a per-interpreter GIL, see Modules/_xxsubinterpretersmodule.c.

(Contributed by Eric Snow in gh-104210, etc.)

PEP 669: Low impact monitoring for CPython

PEP 669 defines a new API for profilers, debuggers, and other tools to monitor events in CPython. It covers a wide range of events, including calls, returns, lines, exceptions, jumps, and more. This means that you only pay for what you use, providing support for near-zero overhead debuggers and coverage tools. See sys.monitoring for details.

(Contributed by Mark Shannon in gh-103082.)

PEP 688: Making the buffer protocol accessible in Python

PEP 688 introduces a way to use the buffer protocolfrom Python code. Classes that implement the __buffer__() method are now usable as buffer types.

The new collections.abc.Buffer ABC provides a standard way to represent buffer objects, for example in type annotations. The new inspect.BufferFlags enum represents the flags that can be used to customize buffer creation. (Contributed by Jelle Zijlstra in gh-102500.)

PEP 709: Comprehension inlining

Dictionary, list, and set comprehensions are now inlined, rather than creating a new single-use function object for each execution of the comprehension. This speeds up execution of a comprehension by up to two times. See PEP 709 for further details.

Comprehension iteration variables remain isolated and don’t overwrite a variable of the same name in the outer scope, nor are they visible after the comprehension. Inlining does result in a few visible behavior changes:

(Contributed by Carl Meyer and Vladimir Matveev in PEP 709.)

Improved Error Messages

NameError: name 'blech' is not defined. Did you mean: 'self.blech'?

Other Language Changes

New Modules

Improved Modules

array

asyncio

calendar

csv

dis

fractions

importlib.resources

inspect

itertools

math

os

os.path

pathlib

platform

pdb

random

shutil

sqlite3

statistics

sys

tempfile

threading

tkinter

tokenize

types

typing

unicodedata

unittest

Add a --durations command line option, showing the N slowest test cases:

python3 -m unittest --durations=3 lib.tests.test_threading ..... Slowest test durations

1.210s test_timeout (Lib.test.test_threading.BarrierTests) 1.003s test_default_timeout (Lib.test.test_threading.BarrierTests) 0.518s test_timeout (Lib.test.test_threading.EventTests)

(0.000 durations hidden. Use -v to show these durations.)

Ran 158 tests in 9.869s

OK (skipped=3)

(Contributed by Giampaolo Rodola in gh-48330)

uuid

Optimizations

CPython bytecode changes

Demos and Tools

Deprecated

Pending Removal in Python 3.13

Modules (see PEP 594):

Other modules:

APIs:

Pending Removal in Python 3.14

Pending Removal in Python 3.15

Pending removal in Python 3.16

Pending Removal in Future Versions

The following APIs will be removed in the future, although there is currently no date scheduled for their removal.

Removed

asynchat and asyncore

configparser

distutils

ensurepip

enum

ftplib

gzip

hashlib

importlib

imp

io

locale

smtpd

sqlite3

ssl

unittest

webbrowser

xml.etree.ElementTree

zipimport

Others

Porting to Python 3.12

This section lists previously described changes and other bugfixes that may require changes to your code.

Changes in the Python API

Build Changes

C API Changes

New Features

Porting to Python 3.12

Deprecated

Pending Removal in Python 3.14

Pending Removal in Python 3.15

Pending Removal in Future Versions

The following APIs are deprecated and will be removed, although there is currently no date scheduled for their removal.

Removed