What's New in Python 3.13: Every Major Feature Explained
Python 3.13, released on October 7, 2024, is one of the most ambitious Python releases in years. It brings a completely redesigned interactive shell, an experimental mode that removes the Global Interpreter Lock, the beginnings of a JIT compiler, and a batch of quality-of-life improvements that make everyday Python noticeably better.
I've spent time digging through the changelog, testing the new features, and separating the genuinely useful from the merely interesting. Here's what you actually need to know about Python 3.13 and its new features.
1. The New Interactive REPL
If you spend any time in Python's interactive interpreter, this one matters. Python 3.13 replaces the old REPL with a completely redesigned version based on code from the PyPy project. The difference is immediately noticeable.
The new REPL supports multiline editing with history preservation. You can arrow up to a previous multi-line function definition, edit it, and re-run it — something that was frustratingly impossible before. You'd either retype the whole thing or reach for an external tool like IPython.
Other improvements worth knowing about:
- Color-coded prompts and tracebacks are on by default. Error messages are visually distinct from regular output, which sounds minor until you're scanning through a long debugging session.
- Direct commands like
exit,quit, andhelpwork without parentheses. No more seeingUse quit() or Ctrl-D to exitwhen you typequit. - F1 opens interactive help with its own separate command history. F2 browses history while skipping output lines. F3 enters "paste mode" for dumping in multi-line code blocks without the REPL trying to execute each line as you go.
You can disable the new REPL by setting the PYTHON_BASIC_REPL environment variable if you need the old behavior, but I'd give the new one a fair shot first. It eliminates most of the reasons people reach for IPython during quick interactive sessions.
2. Free-Threaded Mode (No GIL)
This is the headline feature — and the one that will have the most long-term impact on the Python ecosystem. Python 3.13 ships with experimental support for running without the Global Interpreter Lock (GIL), the mechanism that has prevented true multi-threaded parallelism in CPython for over three decades.
What the GIL actually does
The GIL is a mutex that allows only one thread to execute Python bytecode at a time. Even on a 16-core machine, a multi-threaded Python program effectively uses one core for Python code. You can work around this with multiprocessing, but that carries the overhead of separate processes, inter-process communication, and duplicated memory.
How to use free-threaded Python
Free-threaded mode is available via a separate build — python3.13t — or through the --disable-gil build option. On Windows and macOS, the official installers include the free-threaded build as an optional component.
# Check if your build supports free-threading
python3.13t -VV
# Output includes "experimental free-threading build"
# At runtime, check GIL status
import sys
print(sys._is_gil_enabled()) # False in free-threaded mode
# You can also control it via environment variable
# PYTHON_GIL=0 python3.13t my_script.py
A few important caveats. This is explicitly experimental. Single-threaded performance takes a measurable hit in free-threaded mode because the interpreter needs to use finer-grained locking instead of the single coarse GIL. C extensions need to be rebuilt and updated to be thread-safe — most popular packages aren't there yet. And some internal APIs behave differently without the GIL's implicit synchronization.
The practical upshot: don't use free-threaded Python in production today. But do test your code against it. The Python core team is committed to this direction, and PEP 703 lays out a multi-release roadmap. By Python 3.15 or 3.16, the no-GIL mode will likely be stable enough for production workloads. Preparing now means you won't be scrambling later.
3. The Experimental JIT Compiler
Python 3.13 introduces a basic just-in-time compiler under PEP 744. It uses a technique called "copy-and-patch" — instead of generating machine code from scratch at runtime, it copies pre-compiled templates and patches in the specific values needed.
The JIT works by compiling the Tier 2 intermediate representation (micro-ops) into native machine code. The Tier 2 optimizer was introduced in Python 3.12, and the JIT extends that work by turning the optimized IR into actual executable code rather than interpreting it.
To use it, you need a build compiled with --enable-experimental-jit. At runtime, you can toggle it with the PYTHON_JIT environment variable. The official installers don't include JIT by default.
Performance improvements right now are modest — the Python team is upfront about this. The JIT infrastructure is the foundation being laid for more aggressive optimizations in future releases. Think of Python 3.13's JIT the way you'd think of the first version of any compiler optimization: the architecture matters more than the immediate speedup.
4. Improved Error Messages
Python has been steadily improving its error messages since 3.10, and 3.13 continues the trend with several genuinely useful additions.
Color-coded tracebacks
Tracebacks are now displayed with color by default. The filename, line number, and error type are visually distinct, making it faster to scan a stack trace and find the relevant frame. You can control this with the PYTHON_COLORS environment variable, or disable it entirely with NO_COLOR.
Smart keyword argument suggestions
Misspell a keyword argument? Python 3.13 tells you what you probably meant.
>>> "hello world".split(max_split=1)
TypeError: split() got an unexpected keyword argument 'max_split'
>>> "hello world".split(max_split=1)
TypeError: split() got an unexpected keyword argument 'max_split'.
Did you mean 'maxsplit'?
Script name collision warnings
One of the most common beginner mistakes is naming a script the same as a standard library module — creating random.py and then wondering why import random doesn't work. Python 3.13 now detects this and tells you exactly what's wrong:
$ python random.py
AttributeError: module 'random' has no attribute 'randint'
(consider renaming '/home/user/random.py' since it has the same
name as the standard library module named 'random' and prevents
importing that standard library module)
This one error message will save thousands of Stack Overflow searches per year. It's exactly the kind of improvement that makes a language more accessible without dumbing anything down.
5. Typing Improvements
Python's type system continues to mature with four significant additions in 3.13.
Type parameter defaults (PEP 696)
Type variables can now have default types, reducing boilerplate in generic code:
from typing import TypeVar
T = TypeVar('T', default=int)
class Container[T]:
def __init__(self, value: T) -> None:
self.value = value
# Container() now defaults T to int without explicit annotation
TypeIs for type narrowing (PEP 742)
TypeIs replaces the more limited TypeGuard for type narrowing functions. The key difference: TypeIs narrows in both the if and else branches, while TypeGuard only narrows in the if branch.
from typing import TypeIs
def is_str_list(val: list[int | str]) -> TypeIs[list[str]]:
return all(isinstance(x, str) for x in val)
def process(items: list[int | str]) -> None:
if is_str_list(items):
# Type checker knows items is list[str] here
print(items[0].upper())
else:
# Type checker knows items is list[int | str] here
pass
ReadOnly TypedDict items (PEP 705)
Individual fields in a TypedDict can now be marked as read-only, useful for representing data structures where some fields shouldn't be modified after creation:
from typing import TypedDict, ReadOnly
class User(TypedDict):
id: ReadOnly[int] # Cannot be modified
name: str # Can be modified
email: str # Can be modified
Deprecation in the type system (PEP 702)
The new @warnings.deprecated() decorator lets you mark functions, classes, and overloads as deprecated in a way that type checkers can understand and flag. This is cleaner than the previous approach of deprecation warnings that only appeared at runtime.
6. Standard Library Changes
Beyond the headline features, Python 3.13 brings several practical improvements to the standard library.
New dbm.sqlite3 backend: The dbm module now uses SQLite as its default backend when creating new files, replacing the aging dbm.ndbm and dbm.gnu backends. This means better reliability and cross-platform compatibility for simple key-value storage.
Defined locals() semantics (PEP 667): The behavior of locals() in optimized scopes (functions, generators, comprehensions) is now explicitly defined. It returns independent snapshots — calling locals() twice gives you two separate dictionaries. This matters for debuggers and tools that modify local variables, and it eliminates a class of subtle bugs around mutating the locals() return value.
Performance improvements: The typing module imports roughly 33% faster. textwrap.indent() is about 30% faster for large inputs. subprocess uses posix_spawn() more broadly for faster process creation. Docstrings now have leading indentation stripped automatically, reducing memory use and .pyc file sizes.
Mobile and web platform support: iOS (PEP 730) and Android (PEP 738) are now officially supported as Tier 3 platforms. WASI (WebAssembly System Interface) moves up to Tier 2. Python is quietly becoming a viable choice for cross-platform development scenarios it never targeted before.
7. What Got Removed
Python 3.13 completes the "dead batteries" removal under PEP 594. Nineteen modules that were deprecated in Python 3.11 are now gone entirely: aifc, audioop, cgi, cgitb, chunk, crypt, imghdr, mailcap, msilib, nis, nntplib, ossaudiodev, pipes, sndhdr, spwd, sunau, telnetlib, uu, and xdrlib.
The 2to3 tool and lib2to3 module are also gone. If you're still using these, the migration path is to run them under Python 3.12 first and then upgrade.
If your codebase imports any of these modules, you'll need to find replacements before upgrading. For cgi, use urllib.parse or a web framework's built-in parsing. For imghdr, the filetype package on PyPI is a solid drop-in. Most of the others have PyPI alternatives or were so niche that very few projects used them.
8. Should You Upgrade?
For most developers, yes — but with the usual caution around major version bumps.
Upgrade now if: You want the improved REPL and error messages immediately. You want to start testing your code against the free-threaded build. Your project doesn't import any of the removed standard library modules.
Wait if: You rely on C extensions that haven't been updated for 3.13 compatibility. You use any of the removed modules and haven't found replacements yet. You're running a production system that can't tolerate any risk of compatibility issues.
Start testing against free-threaded mode now. Even if you're not ready to deploy it, identifying thread-safety issues in your code today will pay off when no-GIL becomes the default in a future release. Run your test suite under python3.13t and see what breaks.
Python 3.13 is the release where the language's long-term direction becomes clear: faster execution through the JIT pipeline, true parallelism through free-threading, and a continued focus on developer experience through better tooling and error messages. The experimental features aren't production-ready yet, but the foundation is solid and the trajectory is encouraging.
Want to test Python code or explore new 3.13 features? Try the AI Code Tester to run Python snippets with structural scoring, or ask the Andy AI Chat any Python questions — it handles code generation, debugging, and technical explanations across 16 different modes.
— Andy