What are the new features in Python 3.11?

Discover the benefits of Python 3.11 for application development

Discover the benefits of Python 3.11 for application development
Posted :

Every version of Python has developments and variations, and 3.11 is no exception. Python releases a new version every year. A feature-locked beta release is done in the first half of the year and the final release is done in the second half of the year.

The release of Python 3.11 occurred on October 24, 2022. Python’s latest version is faster and easier to use. It has been in development for 17 months and is now ready for widespread use.

The developers are invited to test it out on non-production code to see if it works with their systems and if the performance improvements would benefit their code.

A new Python release is always a reason to celebrate and appreciate the tireless work that volunteers from across the world have put into the language.

Python 3.11 will fundamentally alter programming for both novice and expert users. However, it is advisable to take help from a Python development services provider to ensure smooth migration. And if you’re still new to the world of programming, employing some of the new features of Python 3.11 in real-time projects is the easiest way to comprehend and learn them.

There are a lot of new features in Python 3.11, let’s explore them in detail:

Better error messages

Python is considered to be an easy programming language for beginners due to its readable syntax and robust data structures. However, interpreting the traceback that it displays when an error occurs is a bit difficult.

Python’s error messages were considerably enhanced in version 3.10. Python has now added decorative annotations to tracebacks that help you interpret error messages quickly.

To check this, add the following code to a file and name it inverse.py:



#inverse.py

def inverse(number):
    return 1 / number


print(inverse(0))

Use inverse () if you want to calculate the multiplicative inverse of a number. In the above code, we have written 0 and since there is no multiplicative inverse of 0, you will get an error when you run it:

error messages

The symbols ^ and ~ are embedded in the traceback. You can see the code responsible for the error. You should always begin at the bottom and work your way up with tracebacks. In this case, the division 1/number results in a ZeroDivisionError. It is because of inverse (0), since 0 has no inverse.

Having this extra assistance in identifying errors is beneficial. If your code is more complicated, the annotated tracebacks are more effective. They can provide details that the traceback alone couldn’t provide you before.

Faster code execution

Python is known for being a slow language. A normal loop, for instance, runs orders of magnitude slower in Python than it would in C. There are numerous strategies to overcome this disadvantage. Code execution speed is frequently less significant than programmer productivity.

Additionally, Python is excellent at encasing libraries created in faster languages. For instance, NumPy calculations are substantially faster than equivalent plain Python calculations. Python is a strong contender in the data science field due to its ease of use in writing code.

The fundamental Python language is still being worked on to make it faster. Mark Shannon proposed several performance enhancements for Python in the fall of 2020. The Shannon Plan is a very ambitious plan that aims to make Python five times faster throughout multiple releases.

Based on the Faster CPython project, Python 3.11 has a lot of enhancements. You will discover more about other improvements in later sections.

Python code is assembled to bytecode before execution. Each line of Python code is split up into many bytecode statements because bytecode contains more fundamental instructions than conventional Python code.

You can use dis to view the bytecode for Python. For example, consider a function that can convert between feet and meters as an illustration:



# feet_to_meters.py
def feet_to_meters(feet):
    return 0.3048 * feet

import dis
dis.dis(feet_to_meters)

By calling dis.dis(), you can deconstruct this method into bytecode:

Faster code execution

One bytecode instruction is detailed on each line. The five columns are the line number, byte address, operation code name, operation parameters, and a description of the parameters.

To write Python, you typically don’t need to be familiar with bytecode. However, it can assist you in comprehending the inner workings of Python.

Speed improvement

The usual benchmark suite runs about 25% faster than in 3.10, which is the first prominent change that will delight data scientists. According to the Python documentation, 3.11 can occasionally be up to 60% quicker. You must install Docker before you can run the benchmark test and assess speed improvements on your computer. This will help you to compare the speeds of Python 3.10 and 3.11. Run these two commands in the terminal to download two images for the two versions of Python after making sure Docker Desktop is running.

speed improvement

Exception Notes

The ability to add arbitrary notes is an addition to standard exceptions. The usage of these notes to annotate an exception in a piece of code other than the one that first raised it is covered by PEP 678. A testing library like Hypothesis, for instance, can give details about which tests failed. Any exception can have a remark added to it using:

Use .add_note() to add a code to any exception and inspect the.__notes__ attribute to see the current notes:

Exception Notes

Any relevant annotations are written at the bottom of the traceback if an error is raised.

asyncio Task Groups

Asynchronous programming frequently requires that you start a lot of activities running simultaneously and then take some action once they are finished. For instance, downloading several photos concurrently and then compiling them into a zip file.

You must gather tasks and pass them to asyncio.gather to accomplish this. Here’s a simple example of how to use the gather function to run multiple jobs at the same time:



# asd.py
import asyncio


async def simulate_flight(city, departure_time, duration):
         await asyncio.sleep(departure_time)
         print(f"Flight for {city} departing at {departure_time}PM")

         await asyncio.sleep(duration)
         print(f"Flight for {city} arrived.")


flight_schedule = {'Boston': [3, 2], 'Detroit': [7, 4], 'New York': [1, 9],}


async def main():
         tasks = [ ]
         for city, (departure_time, duration) in flight_schedule.items():
               tasks.append(simulate_flight(city, departure_time, duration))
         await asyncio.gather (*tasks)
         print("Simulations done.")

asyncio.run(main())

asyncio Task Groups

However, it is a little obstinate to have to keep a list of the duties to anticipate them. As a result, Task Groups, a new API, has been added to asyncio:



#asd.py
import asyncio


async def simulate_flight(city, departure_time, duration):
        await asyncio.sleep(departure_time)
        print(f"Flight for {city} departing at {departure_time}PM")

        await asyncio.sleep(duration)
        print (f"Flight for {city} arrived.")

flight_schedule = {'Boston': [3, 2], 'Detroit': [7, 4], 'New York': [1, 9], }


async def main():
         async with asyncio. TaskGroup() as tg:
                  for city, (departure_time, duration) in flight_schedule.items():                               
                      tg.create_task(simulate_flight(city, departure_time, duration))
      
          print("Simulations done.")

asyncio.run(main())

The asyncio.TaskGroup() context manager makes sure that all tasks launched inside of it have finished running before quitting.

Improvements to the Standard Libraries

The quality of standard libraries is enhanced. First, the math module now includes two functions that were eagerly anticipated.

Improvements to the Standard Libraries

You may now build fractions from strings using a new functionality that was added to the fractions module:

build fractions from strings

As you can see, the fractions module has some useful applications in arithmetic. Specifically, you can determine which fraction is the most similar to the provided float. This can be advanced by defining a denominator limit:

fractions module

A new module called tomllib is also available for parsing TOML documents. The TOML (Tom’s Obvious Minimal Language) file format is a well-known format for creating configuration files that can be read by humans.



import tomllib

toml_str = " " "
python-version = "3.11.0"
release_date = "2022-10-22"
" " "

data = tomllib.loads(toml_str)
print(data) # {'python-version': '3.11.0', 'release_date': '2022-10-22'}
print(data['python-version']) # 3.11.0
print(data['release_date']) # 2022-10-22

New typing feature: Self

Statically typed programming languages make your code more readable and easier to debug. Defining the precise types of variables, function inputs, and outputs will help others understand your code more easily and save you hours of troubleshooting effort. When you add typing annotations to your functions, modern IDEs will display function definitions as you type their names, making your functions easier for others to understand.

The robust Python typing module has classes for almost every data type until this point, with the exception of classes that return instances of themselves. The example given below is not possible in the previous versions of Python:



from typing import Self


class Language:

        def __init__(self, name, version, release_date):
                self.name = name
                self.version = version
                self.release_date = release_date

        def change_version(self, version) -> Self:
               self.version = version

               return Language(self.name, self.version, self.release_date)

Python 3.11, however, introduces the Self class, which you can include in the definition of a function if its return value is self or a new instance of the class.

Other benefits of Python 3.11:

  • Namespace dictionaries for Python objects are now built lazily and their dictionaries share keys, so less memory is needed to store them now.
  • Hashes are no longer needed to be stored with all keys being Unicode, which minimizes the dictionary size and improves cache performance.
  • Now there is experimental support for compiling to WebAssembly in the CPython runtime, the standard Python interpreter. This could help with the future development of initiatives like PyScript, which enables the use of a Wasm-compiled Python runtime to function in the browser.

It’s time to upgrade!

According to the official announcement, the new release is 10–60% faster than Python 3.10, depending on your workload. Additionally, error and exception handling in the programming language has been improved.

It brings better efficiency, more exception handling options, a new module for reading TOML files, interpreter enhancements, more types, annotations, and type features, as well as the deprecation and removal of some outdated language baggage. If you’re planning to migrate to the latest version of Python, it is always better to take help from experienced professionals. Talk to our Python experts to make a move now.

Need Help?
We are here for you

Step into a new land of opportunities and unearth the benefits of digital transformation.