What is new in Python 3.11?

Python 3.11 is a significant release of the programming language, bringing with it a number of new features and improvements. It’s faster overall than Python 3.10 on most benchmarks, uses less memory, and starts up faster. It also has a number of new and refined features that improve the developer experience, such as exception groups, exception notes, and fine-grained error locations in tracebacks.

New features

Here’s a list of features that are introduced in Python 3.11:

  • Exception groups

  • Exception notes

  • The tomllib library

  • Variadic generics

  • Marking TypedDict options

  • Self type

  • Arbitrary literal string type

  • Data class transforms

Exception groups

Exception groups are a new feature in Python 3.11 that allows us to group multiple exceptions and handle them collectively. This can be useful for a variety of reasons, such as:

  • To simplify error handling in complex code

  • To provide more context to users when errors occur

  • To handle multiple errors in a single handler

Exception notes

Exception notes are a way to document the different types of exceptions that a piece of code can raise. Other developers can use this information to understand the potential risks of using the code and write code that handles exceptions gracefully. Exception notes should be clear, concise, and informative. They should include the following information:

  • The name of the exception type

  • A description of the conditions under which the exception is raised

  • The recommended way to handle the exception

Some benefits of writing exception notes can be:

  • Helping other developers understand the potential risks of using our code

  • Helping developers write code that gracefully handles exceptions

  • Helping us debug our code

  • Helping make our code more robust and reliable

The tomllib library

In Python 3.10, there’s no built-in library to parse TOML files, and we need third-party libraries, such as tomli, to handle TOML files. However, we don’t need to do that anymore because Python 3.11 introduced the tomllib library that aids in parsing TOML files. We can load and read TOML data through the library but not write it. It’s based on the third-party tomli library.

Note: TOML, which stands for Tom’s Obvious, Minimal Language, is an easily readable configuration file format because of its simple syntax. It was created to address some shortcomings of other configuration file formats.

The two main functions of the tomllib library are:

  • load(): It loads data from .toml files.

  • loads(): It loads data from str.

Here’s an example of parsing TOML files in Python 3.11:

main.py
t.toml
import tomllib
with open('t.toml') as Sample:
toml_data = tomllib.loads(Sample.read())
print(toml_data)

In the code above:

  • Line 1: We import the tomllib library.

  • Lines 3–4: Using with open(), the code reads t.toml, loads the content using the tomllib library, and assigns parsed data to the variable toml_data.

  • Line 6: The print(toml_data) statement prints the parsed data.

Variadic generics

Python 3.11 introduces a new feature called variadic generics. Variadic generics allow us to pass a variable number of type arguments to a generic function or class.

For example, the following generic function takes a variable number of type arguments:

def my_function(*args: Type[Any]) -> None:
for arg in args:
print(arg)
my_function(int, str, float)

Here’s the explanation:

  • Line 1: This line defines a function called my_function() with a parameter *args that tells Python that the function can take a variable number of arguments. The Type[Any] type hint tells Python that the arguments to the function must be of type Any. This means that the function can be called with any type of argument and the my_function() function doesn’t return a value.

  • Lines 2–3: This line starts a for loop that iterates over the args parameter. For each argument, the function prints the argument to the console.

  • Line 5: This line calls the my_function() function with three arguments: int, str, and float.

Variadic generics can be very useful for writing generic code that can handle a variety of different types.

Marking TypedDict options

This feature allows us to mark certain options in a TypedDict as required or optional.

For example, the following TypeDict has two options: name and age:

my_type_dict: TypedDict = {
"name": str,
"age": Optional[int]
}
print(my_type_dict)

Here’s the explanation:

  • Line 1: This line declares a variable called my_type_dict and assigns it to a TypedDict object.

  • Lines 2–3: The TypedDict object has two keys: name and age. The name key has the type str and the age key has the type Optional[int]. This means that the name key must contain a string value and the age key can contain an integer value or be None.

  • Line 5: This line prints the my_type_dict to the console.

The Self type

The Self type in Python 3.11 is a new type annotation that allows us to specify the return type of a method as the same type as the class in which the method is defined. This can be useful for improving the type safety of our code and making it more readable.

Here’s an example:

class Person:
def __init__(self, name: str) -> None:
self.name = name
def greet(self: Self) -> Self:
print(f"My name is {self.name}")
return self
person = Person("Alice")

Here’s the explanation:

  • Line 1: This line defines a class called Person.

  • Line 2: This line defines a constructor for the Person class. The constructor takes a name parameter of type str.

  • Line 3: This line assigns the value of the name parameter to the self.name attribute.

  • Line 5: This line defines a method called greet(). The greet() method takes no parameters and returns an instance of the Person class by using the Self type hint.

  • Line 6: This line prints the message “My name is name” to the console. The name is replaced by the value given in the method parameter.

  • Line 7: This line returns an instance of the Person class.

  • Line 9: This line creates a new instance of the Person class and assigns it to the person variable and adds the value of name as the parameter.

Arbitrary literal string type

Arbitrary literal string type is a new feature in Python 3.11 that allows us to specify the type of a variable as any literal string value. This can be useful for ensuring that variables only contain valid string values, and for making our code more readable.

To use the arbitrary literal string type, we can use the LiteralString type hint. For example, the following code is valid:

my_variable: LiteralString = "Hello, world!"
print(my_variable)

In the code above, the LiteralString type hint is used, which indicates that my_variable should have the exact value, "Hello, world!".

Data class transforms

In Python 3.11, we can use the dataclasses module to create data classes, which can simplify the creation of classes that primarily store data. These classes automatically generate special methods like __init__, __eq__, __ne__, and __repr__ based on the class attributes. The dataclass_transform decorator is used to mark a function, class, or metaclass as performing runtime “magic” that transforms a class, endowing it with dataclass-like behaviors.

Here’s an example of how to use dataclass–tranform in Python 3.11:

import typing
from typing import Type, TypeVar, Any
import dataclasses
_T = TypeVar("_T")
@typing.dataclass_transform()
def create_model(cls: Type[_T]) -> Type[_T]:
cls = dataclasses.dataclass(cls) # Automatically create __init__, __eq__, and __ne__ methods
return cls
# The create_model decorator can now be used to create new model classes:
@create_model
class CustomerModel:
id: int
name: str
c = CustomerModel(327, "Eric Idle")
print(c)

Here’s the explanation:

  • Line 1–3: Import all the necessary modules.

  • Line 5: Define the type variable named _T. This is used to represent any type.

  • Line 7: Decorate the upcoming method with typing.dataclass_transform(), which tells the type checker that the create_model() method performs dataclass-like transformations.

  • Lines 8–10: Define the create_model() method which takes a type object as input and returns a transformed object. It uses dataclasses.dataclass() decorator to automatically create the __init____eq__, and __ne__ methods for the type object.

  • Line 13: Decorate the CustomerModel class with the create_model() decorator.

  • Lines 14–16: Define the CustomerModel class which has two variables: id and name.

  • Line 18: Create an instance of the CustomerModel class named c and assign values to the variable fields.

  • Line 19: Print the values stored in c.

Improved features

A lot of features and functions were improved and modified in Python 3.11. Some of them are as follows:

  • Faster CPython

  • Improvements in the hashlib module

  • Fine-grained error location in tracebacks

  • The -P command-line option

Faster CPython

Python 3.11 includes a number of optimizations that make the CPython interpreter faster. These optimizations include:

  • The new bytecode optimizer in Python 3.11 can generate more efficient code by performing a number of optimizations, including constant foldingReplaces constant expressions with their evaluated values, dead code eliminationRemoves the code that’s never executed, common subexpression eliminationReplaces multiple occurrences of the same subexpression with a single occurrence, and loop optimizationMoves invariant code out of loops and optimizes loop control structures.

  • The new garbage collector in Python 3.11 is more efficient and uses less memory by using a number of techniques, including generational garbage collectionDivides objects into generations based on age and collects garbage from older generations more frequently, reference countingTracks the number of references to each object and garbage-collecting objects without any references, and tricolor markingTracks the reachability of objects and garbage-collecting objects that aren’t reachable from the root set of objects.

  • The new memory allocator in Python 3.11 is more efficient and reduces fragmentation by using a number of techniques, including bump pointer allocationAllocates memory from a contiguous memory region and moves the pointer to the next available memory block after each allocation, free list allocationMaintains a list of free memory blocks and allocates new blocks from the list, and slab allocationAllocates memory in slabs of a fixed size.

Improvements in the hashlib module

The following improvements have been made to hashlib modules in Python 3.11:

  • The hashlib.blake2b() and hashlib.blake2s() functions now prefer the libb2 library over the vendored copy. It improves performance significantly, especially on systems with a recent version of OpenSSL installed.

  • The hashlib module now prefers optimized SHA-3 and SHAKE implementations from OpenSSL. This can also improve performance on systems with OpenSSL installed.

  • A new hashlib.file_digest() function has been added. This function allows us to efficiently compute the hash of a file or file-like object. Here‘s an example of how to use the method:

main.py
myfile.txt
import hashlib
def get_file_hash(filename, digest="sha256"):
with open(filename, "rb") as f:
return hashlib.file_digest(f, digest).hexdigest()
file_hash = get_file_hash("myfile.txt")
print(file_hash)

Here’s the explanation of the code:

  • Line 1: Import the hashlib module.

  • Lines 3–5: Define a method get_file_hash() with arguments: filename and digest. The default digest algorithm is set to SHA256.

  • Line 7: Compute the hash of myfile.txt using the get_file_hash() method and save the results in the file_hash variable.

  • Line 8: Print the hash of the file

Fine-grained error location in tracebacks

Python 3.11 introduced a new feature called fine-grained error location in tracebacks. This feature provides more detailed information about the location of errors in Python code.

For an example, run the following code:

def my_function(x):
return x / 0
my_function(1)

This output section shows the traceback that tells us that the error occurred on line 2 of the my_function() function in the main.py file.

The -P command-line option

The new -P command-line option and PYTHONSAFEPATH environment variable in Python 3.11 allow us to disable the automatic prepending of potentially unsafe paths to sys.path. This can be useful for improving security and reducing the risk of arbitrary code execution.

Deprecated features

Deprecated features and APIs are those that are no longer recommended for use and will be removed in future versions of Python. This can be done for a variety of reasons, such as security vulnerabilities, performance problems, or because the feature is no longer needed. Here’s a list of features/APIs that are deprecated in Python 3.11 and will be removed in later versions:

  • Py_UNICODE encoder APIs have been converted to static inline functions, which are more efficient and easier to use.

  • A variety of Python APIs that have been deprecated for various reasons. For example, the pickle.Unpickler class is deprecated because it’s vulnerable to security attacks.

It’s important to note that deprecated features and APIs are still functional in Python 3.11. However, it’s recommended to avoid using them if possible because they may be removed in future versions of Python.

Conclusion

Python 3.11 is a major release of the Python programming language, with a number of new features and improvements that make it faster, more reliable, and more user-friendly. Some of the most notable changes include faster performance, improved type safety, new language features, and an improved standard library.

It’s recommended to upgrade to Python 3.11. The upgrade process is relatively straightforward, and the benefits of using Python 3.11 are well worth it.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved