Patrick Loeber
Patrick Loeber

Patrick Loeber

Python 3.11 is out - All important features

Python 3.11 is out - All important features

Learn what's new in Python 3.11. It's can be up to 60% faster and includes several other changes.

Patrick Loeber's photo
Patrick Loeber
·Oct 25, 2022·

4 min read

Table of contents

  • Faster CPython
  • Better Error Messages
  • add_note() for Exceptions
  • Exception Groups and except*
  • Type Hints features
  • New tomllib module
  • New asyncio TaskGroup
  • New math functions
  • Conclusion

Python 3.11 is out! Learn about all important changes in this article.

You can also watch the video here:

Faster CPython

It got faster! Python 3.11 is on average 25% faster than 3.10. Depending on your workload, the speedup could be up to 10-60% faster. Learn more about the speed improvements here.

Better Error Messages

It got better error messages. The interpreter will now point to the exact expression that caused the error, instead of just the line.

Traceback (most recent call last):
  File "distance.py", line 11, in <module>
    print(manhattan_distance(p1, p2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "distance.py", line 6, in manhattan_distance
    return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
                           ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'x'

add_note() for Exceptions

The add_note() method is added to BaseException. It lets you add additional information which then appears in the traceback.

try:
    raise TypeError
except Exception as e:
    e.add_note("This is a note")
    raise

# ---
Traceback (most recent call last):
  File "/main.py", line 2, in <module>
    raise TypeError
TypeError
This is a note

Exception Groups and except*

ExceptionGroup and except* were added. They make it possible to group exceptions and raise them together, so you can raise and handle multiple unrelated exceptions simultaneously.

eg = ExceptionGroup(
    "one",
    [
        TypeError(1),
        ExceptionGroup(
            "two",
            [TypeError(2), ValueError(3)]
        ),
        ExceptionGroup(
            "three",
            [OSError(4)]
        )
    ]
)

try:
    raise eg
except* ValueError as e:
    print(f"Handling ValueError: {e.exceptions}")
except* TypeError as e:
    print(f"Handling TypeError: {e.exceptions}")
except* OSError as e:
    print(f"Handling OSError: {e.exceptions}")

Type Hints features

New features related to Type Hints and the typing module were added. This includes the LiteralString, the Required and NotRequired types, and the Self type with a capital S.

LiteralString

The new LiteralString annotation may be used to indicate that a function parameter can be of any literal string type. Type checkers can then enforce that sensitive functions, such as those that execute SQL statements are called only with static arguments, providing protection against injection attacks.

from typing import LiteralString

def run_query(sql: LiteralString) -> None:
    ...

Required, NotRequired

Required and NotRequired provide a straightforward way to mark whether individual items in a TypedDict must be present. Those two definitions are equivalent, so in this case, title has to be defined.

from typing import TypedDict, Required, NotRequired

class Movie(TypedDict):
   title: str
   year: NotRequired[int]

m1: Movie = {"title": "Black Panther", "year": 2018}  # OK
m2: Movie = {"title": "Star Wars"}  # OK (year is not required)
m3: Movie = {"year": 2022}  # ERROR (missing required field title)

# The following definition is equivalent:

class Movie(TypedDict, total=False):
   title: Required[str]
   year: int

Self

And the new Self annotation provides a simple and intuitive way to annotate methods that return an instance of their class. Common use cases include alternative constructors provided as classmethods, and enter methods that return self:

from typing import Self

class MyLock:
    def __enter__(self) -> Self:
        self.lock()
        return self

class MyInt:
    @classmethod
    def fromhex(cls, s: str) -> Self:
        return cls(int(s, 16))

New tomllib module

And a whole new module was added, the tomllib module, which adds support for parsing TOML files.

import tomllib

with open("pyproject.toml", "rb") as f:
    data = tomllib.load(f)

# Or from a string:
toml_str = """
python-version = "3.11.0"
python-implementation = "CPython"
"""

data = tomllib.loads(toml_str)

New asyncio TaskGroup

The asyncio TaskGroup class was added, which is an asynchronous context manager holding a group of tasks that are awaited when the context manager exits. For new code this is recommended over using create_task() and gather() directly.

async def main():
    async with asyncio.TaskGroup() as tg:
        task1 = tg.create_task(some_coro(...))
        task2 = tg.create_task(another_coro(...))
    print("Both tasks have completed now.")

New math functions

The math module got 2 new cool functions:

  • math.exp2 which returns 2 raised to the power of x, and
  • math.cbrt which returns the the cube root of x.
import math

print(math.exp2(4))
# 16.0

print(math.cbrt(8))
# 2.0

Conclusion

These are the most important changes. To read about all changes check out this link:

 
Share this