Python 3.13 betas are out (Edit: 3.13.0 is out!), which means the features are locked in. For the first time in thirty years, Python has a new, more colorful REPL! There’s also a no-GIL compile-time option (free-threaded), an optional JIT, some new typing features, and better error messages (again).
Interpreter improvements
PyPy’s REPL was brought over to CPython. The old REPL was deeply linked to the
internals of the interpreter, while the new one is written in Python and finally
makes some long requested features possible! The new interpreter has colorized
prompts, multiline editing, three new keyboard shortcuts (F1: help, F2: history,
F3: paste mode), and repl-specific commands no longer need trailing parentheses
(like help
, exit
, and quit
)!
Tracebacks are now colorized by default, as is doctest output.
FORCE_COLOR
/NO_COLOR
are respected.
New error message updates include:
- Trying to access an attribute from a local module overlapping a global/installed one will now mention this as a possible problem.
- Mistyped keyword args now suggest possible matches.
And breakpoint()
now enters the debugger on the line it it given, rather than
the line after, meaning it works at the end of a function now.
Free-threading
Python can now be built in free-threading mode, and wheels can be built for free-threading Python (requires pip 24.1b1 or newer, or uv to install).
When built in this mode, CPython no longer has a GIL, and supports true multithreading. This will likely require some updates from compiled libraries (supporting free-threading wheels) and some code that happened to work because it was relying on the GIL might require proper multithreading constructs like locks and such. This does slow down single thread performance some, though part of it is due to some other optimizations being turned off for now (meaning it will likely be better in the future).
If you use a free-threaded build, you can manually enable the GIL with
PYTHON_GIL
or -X gil
. You can check with sys._is_gil_enabled()
and check
for free-threaded Python with sysconfig.get_config_var("Py_GIL_DISABLED")
.
Python will enable the GIL if an extension module doesn’t declare free-threaded
support.
Progress in the ecosystem supporting free-threading is tracked here. An example in both pure Python and with an extension module is at scikit-build-sample-projects.
JIT compiler
CPython 3.13 comes with a JIT compiler (disabled by default for now). It doesn’t make things much faster yet, but the infrastructure is there. Just like the Specializing Adaptive Interpreter, it will slowly gain support for more Python and in theory make a future version faster.
It works using a copy-and-patch approach. When building Python, you have to have LLVM available (even if you are not compiling with LLVM - LLVM has a tail call attribute that is required for this to work that is missing from GCC), and it will generate machine code for a set of Tier 2 IR (a new construct a level higher than the current Tier 1 IR introduced in CPython 3.11). At run time, if a code path is hot enough, it will use these machine codes instead of running the interpreter.
Static Typing
As always for non-syntax improvements, typing updates are available for older
(3.8+) Python’s in typing-extensions
.
TypeIs
A new typing.TypeIs
augments typing.TypeGuard
. For example:
def is_string(x: int | str) -> TypeIs[str]:
return isinstance(x, str)
if not is_string(value):
typing.reveal_type(value)
# Revealed type is 'int'
def is_string(x: int | str) -> TypeGuard[str]:
return isinstance(x, str)
if not is_string(value):
typing.reveal_type(value)
# Revealed type is 'int | str'
This prints int
, but if we used the older TypeGuard instead, it would have
printed int | str
, because a TypeGuard
doesn’t infer anything if the
function is False
. With TypeIs
, you can model the common case of a function
returning true if it’s a type, and also if it’s not that type.
See more.
Generic defaults
Another static addition is Generics can finally have defaults. This can be
done using the new default=
keyword for TypeVar
and friends for backward
compatibility, or as an added syntax to Python 3.12’s generics syntax (requires
3.13). For example:
@dataclass
class Box[T = int]:
value: T | None = None
T = TypeVar("T", default=int)
@dataclass
class Box(Generic[T]):
value: T | None = None
If you make a new Box()
without explicitly setting the template parameter or
passing a value
, then the type will be int
. The most notable use standard
library use case is for Generator
; most of the time, the second and third
arguments are None
, but currently you had to specify them anyway. Now they can
have defaults.
def simple_generator() -> Generator[int]:
yield from range(5)
def simple_generator() -> Generator[int, None, None]:
yield from range(5)
(Note that Generator
is a more correct type annotation for a generator
function than Iterator
, which is slightly different.)
Deprecated
Added to the warnings module, @warnings.deprecated("msg")
is a type-checker
supported way to add deprecation warnings to a function or class. It’s backport
is @typing_extensions.deprecated()
. You can also set the category
(PendingDeprecationWarning
, DeprecationWarning
, and FutureWarning
are the
three levels) and stacklevel
as well.
Along with this, deprecated=
parameters were added to argparser
’s methods to
indicate deprecated parameters and subcommands.
Other typing features
A few other features:
typing.get_protocol_members()
gets the members of a Protocol.typing.is_protocol()
checks to see if a class is a Protocol.typing.ReadOnly
can be used to mark items of aTypedDict
as read only.
Other features
There’s a new copy.replace()
function, which is a generalized version of
dataclasses.replace
that supports many built-in types and you can add support
for your classes with __replace__
.
Other features include:
process_cpu_count()
added to places wherecpu_count()
is provided.- Warning if bool passed instead of file handle.
configparser
can be configured to handle items without a section..name
and.mode
attributes added for compressed files.glob.translate()
produces a regex from a shell-style glob.itertools.batched()
now has astrict=
parameter.math.fma()
added for fused multiply adds, avoiding intermediate precision loss.pathlib.Path.from_uri()
constructor for file URIs.pathlib.PurePath.full_match()
supports shell style wildcards including**
.pathlib.Path.glob()
andrglob()
return files too, instead of just directories, if a pattern ends in**
.python -m random
is a new CLI for random numbers.statistics
now haskde()
andkde_random()
functions.dbm
has asqlite3
backend now.- Properties now have a
.__name__
attribute. - New
PythonFinalizationError
- Faster import time for modules like
typing
,enum
,functools
,importlib.metadata
, and `threading.
Removals and deprecations
The remaining “dead batteries” have been removed; 19 modules that were very
rarely used. These are: aifc
, audioop
, cgi
, cgitb
, chunk
, crypt
,
imghdr
, mailcap
, msilib
, nis
, nntplib
, ossaudiodev
, pipes
,
sndhdr
, spwd
, sunau
, telnetlib
, uu
and xdrlib
. tkinter.tix
and
lib2to3
were also removed. The “porting from Python 2” page was removed as
well; Python 2 is officially history.
optparse
and getopt
are soft deprecated; meaning they should not be used in
new code, but do not have a removal scheduled. Other deprecations include a few
items in typing
like AnyStr
, no_type_check_decorator()
, io
, re
, and
keyword arguments to NamedTuple
. Also forgetting or using None for the value
in the functional syntax for NamedTuple
or TypedDict
is deprecated. 2to3
has been removed. EntryPoint
’s __getitem__
access has been removed.
Undocumented Logger.warn()
has been removed (deprecated since Python 3.3); you
should be using .warning()
instead. Path’s can’t be used as context managers
(was a no-op since 3.9).
Quite a few previously deprecated things are going to be removed in 3.14 (Python
π?), so make sure you are enabling all warnings as errors in your test suites!
Things like ast.Num
and friends (use ast.Constant
),
importlib.abc.Traversable
(was moved), shutil.rmtree()
’s onerror=
(use
onexc=
instead)
Other Developer changes
One key new feature is a new 2 year “full-support” window; previous versions of Python have a 1.5 year full support window. This means bugfixes and new binaries can be produced for a larger portion of the 5 year support window.
Other features include:
The garbage collector is incremental now.(Update: reverted in 3.13.0rc2 due to performance regressions in Sphinx. Targeting 3.14 now.locals()
optimized and made consistent- iOS and Android are supported platforms now (tier 3).
- Indents are now stripped from docstrings. Saves space.
- Some deprecated
importlib.resources
functions were undeprecated. python -m venv <PATH>
now adds a.gitignore
to the created venv.- Classes have new
__firstlineno__
and__static_attributes__
attributes populated by the compiler. - Some changes to spawning processes, using
os.posix_spawn
more often, should speed up FreeBSD and Solaris. - Default time resolution is better on Windows.
PYTHON_PERF_JIT_SUPPORT
allows integration with Perf without frame pointers (3.12 addedPYTHON_PERF_SUPPORT
using frame pointers)
Not a specific feature, but WASI is now the official flavor of WebAssembly actively supported (and now tier 2!), with Emscripten relegated to Pyodide.
Final Words
If you are using GitHub Actions, the new and best way to add 3.13 is to use this:
- uses: actions/setup-python@v4
with:
python-version: "3.13"
allow-prereleases: true
This works in a matrix, etc. too. If you want to try out free-threaded Python, it was shipped in manylinux on May 14, 2024 and you can use it with:
jobs:
manylinux:
name: Manylinux on 🐍 3.13 • Free-threaded
runs-on: ubuntu-latest
timeout-minutes: 40
container: quay.io/pypa/manylinux_2_28_x86_64:latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare venv
run: python3.13t -m venv .venv
# etc
We are working on preparing support for tools. The new free-threading variant will pose some challenges that we’ll be working through. Be sure to use the pip 24.1 beta or newer for the free-threading variant, or use uv. cibuildwheel now supports free-threading with an opt-in option. pybind11 supports 3.13 and 3.13t, as does NumPy.