Python 3.9.0 stable release

The stable version of Python 3.9.0 is expected to be released today , 10/05/2020. The new version will receive patched updates approximately every 2 months for approximately 18 months. Some time after the release of the final version 3.10.0, the ninth and last update will be released with bug fixes 3.9.



“This is the first version of Python to default to the 64-bit installer on Windows. The installer now also actively disallows installation on Windows 7. "

“This is the first version of Python to use the 64-bit installer on Windows by default. The installer now also prevents installation on Windows 7. "



I have read the Python 3.9 release notes and related discussions. Based on the information, I wanted to write a comprehensive guide so that everyone can get an idea of ​​the functions along with their detailed work.



UPD :

Transition to stable annual release cycles, see PEP 602

alec_kalinin

“Every new version of Python will now come out in October. Python 3.10 will be released in October 2021, Python 3.11 in October 2022. Buckfix will be released every two months. This is great news for me, now we can clearly plan to upgrade the python environment. "



PEP 584



This PEP suggests adding the merge ( | ) and update ( | = ) operators to the built-in dict class.



To merge: |



>>> a = {'milk': 'prostokvashino', 'heese': 'cheddar'} 
>>> b = {'milk': 1, 'heese': 2, 'bread': 3} 
>> >  | b 
{'milk': 1, 'heese': 2, 'bread': 3}
>>> b | a 
{'milk': 'prostokvashino', 'heese': 'cheddar', 'bread': 3}


To update: | =



>>> a | = b 
>>> a 
{'milk': 1, 'heese': 2, 'bread': 3}


The key rule to remember is that if there are any key conflicts, then the rightmost value will be preserved.



Of course, many pythonists will have a question, why is this necessary, if there is already an option familiar to everyone



{**d1, **d2}


This question was answered in the PEP itself:



Unpacking dictionaries looks ugly and is not easy to detect. Few will be able to guess what this means when they first see it.


As Guido said :

I'm sorry about PEP 448 , but even if you know about ** d in a simpler context, if you were asking a typical Python user how to combine two dict into a new one, I doubt many people would think of {** d1, ** d2}. I know I forgot about it myself when this thread started!


Also {** d1, ** d2} doesn't work for dict subclasses like defaultdict




PEP 585



Generics type hints in standard collections.



Generic is a type that can be parameterized, a kind of container. Also known as parametric type or generic type.



This release includes universal syntax support for all standard collections currently available in the Typing module. We can use list or dict types as generic types instead of using typing.List or typing.Dict .



It was:



from typing import List

a: List[str] = list()

def read_files(files: List[str]) -> None:
    pass


Became:



a: list[str] = list()

def read_files(files: list[str]) -> None:
    pass


Complete list of types
tuple

list

dict

set

frozenset

type

collections.deque

collections.defaultdict

collections.OrderedDict

collections.Counter

collections.ChainMap

collections.abc.Awaitable

collections.abc.Coroutine

collections.abc.AsyncIterable

collections.abc.AsyncIterator

collections.abc.AsyncGenerator

collections.abc.Iterable

collections.abc.Iterator

collections.abc.Generator

collections.abc.Reversible

collections.abc.Container

collections.abc.Collection

collections.abc.Callable

collections.abc.Set # typing.AbstractSet

collections.abc.MutableSet

collections.abc.Mapping

collections.abc.MutableMapping

collections.abc.Sequence

collections.abc.MutableSequence

collections.abc.ByteString

collections.abc.MappingView

collections.abc.KeysView

collections.abc.ItemsView

collections.abc.ValuesView

contextlib.AbstractContextManager # typing.ContextManager

contextlib.AbstractAsyncContextManager # typing.AsyncContextManager

re.Pattern # typing.Pattern, typing.re.Pattern

re.Match # typing.Match, typing.re.Match



PEP 615



IANA time zone database support in the standard library.



IANA time zones are often referred to as tz or zone info. There are a large number of IANA time zones with different search paths for specifying the IANA time zone for a date and time object. For example, we can pass the name of the search path as Continent / City to a datetime object to set its tzinfo.



dt: datetime = datetime(2000, 01, 25, 01, tzinfo=ZoneInfo("Europe/London"))


If we pass in the wrong key, an exception will be thrown

zoneinfo.ZoneInfoNotFoundError

PEP 616



New string functions to remove prefix and suffix. Two new functions have been added



to the str object.



  • The first function removes the prefix.
    str.removeprefix(prefix)
  • The second function removes the suffix.
    str.removesuffix(suffix)


>>> 'hello_world'.removeprefix ('hello_') 
world
>>> 'hello_world'.removesuffix ('_world') 
hello


PEP 617



Python 3.9 proposes to replace the current LL (1) -based Python parser with a new PEG-based parser that is high performance and stable.



The current CPython parser is based on LL (1). Subsequently, the grammar is based on LL (1), which allows it to be parsed with an LL (1) parser. The LL (1) parser works from top to bottom. In addition, it parses the input data from left to right. The current grammar is context free grammar, so the context of the tokens is not taken into account.

Python 3.9 proposes to replace it with a new PEG based parser, which means it will remove the current limitations of Python's LL grammar (1). In addition, fixes have been made to the current parser, adding a number of hacks that will be removed. As a result, this will reduce the cost of maintenance in the long run.



For example, while LL (1) parsers and grammars are easy to implement, constraints prevent them from expressing common constructs in a natural way for the language designer and reader. The parser only looks one token forward to distinguish between possibilities.



issue30966



Ability to cancel simultaneous futures .



A new parameter cancel_futures has been added to concurrent.futures.Executor.shutdown () .



This parameter contains all pending futures that have not yet started. Prior to version 3.9, the process waited for them to complete before exiting the executor.



A new parameter cancel_futures has been added to ThreadPoolExecutor and ProcessPoolExecutor . It works when the parameter value is True, then all pending futures will be canceled when the shutdown () function is called .



When shutdown ()is executed, the interpreter checks to see if the executor is garbage collected. If it is still in memory, it gets any pending items and then cancels the futures.



issue30966



A number of improvements have been made to the asyncio and multiprocessing library in this release.



For instance,



  1. The reuse_address parameter asyncio.loop.create_datagram_endpoint () is no longer supported due to significant security issues.
  2. Added new coroutines, shutdown_default_executor (), and asyncio.to_thread () coroutines . A new call to asyncio.to_thread () is used to run I / O-related functions on a separate thread to avoid blocking the event loop.


As for the enhancements to the multiprocessing library, a new close () method has been added to the multiprocessing.SimpleQueue class . This method explicitly closes the queue. This ensures that the queue is closed and does not stay longer than expected. It is important to remember that the get (), put (), empty () methods cannot be called after the queue is closed.







issue37444



Fixed bug with importing packages.



The main problem with importing Python libraries prior to the 3.9 release was inconsistent import behavior in Python when relative imports passed by its top-level package.



builtins .__ import __ () raised a ValueError while importlib .__ import __ () raised an ImportError.



Now it is corrected . __Import __ () now raises ImportError instead of ValueError.



issue40286



Generation of random bytes.



Another feature that was added in version 3.9 is random.Random.randbytes () . It can be used to generate random bytes.



We can generate random numbers, but what if we needed to generate random bytes? Prior to version 3.9, developers had to be creative to generate random bytes. Although we can use os.getrandom () , os.urandom (), or secrets.token_bytes (), we cannot generate pseudo-random patterns.



For example, to ensure that random numbers are generated with expected behavior and the process reproduces, we usually use seed with the random.Random module.



As a result, the random.Random.randbytes () method was introduced . It generates random bytes.



issue28029



Correction of the string replacement function.



The principle of the replace function is that for a given maximum argument to replace an occurrence, it replaces the character set from the string with the new character set.



To further explain the problem, prior to version 3.9 the replace function had inconsistent behavior:



One would expect to see blog



"" .replace ("", "blog", 1) 
>>> '' 




One would expect to see |



"" .replace ("", "|", 1) 
>>> '' 




"" .replace ("", "prefix") 
>>> 'prefix'




issue39648, issue39479, issue39288, issue39310



Changes in the "math" module.



Returns the least common multiple of integer arguments:



>>> import  math 
>>> math.lcm(48,72,108) 
432




Returns the greatest common divisor of integer arguments. The earlier version only supported two arguments. Added support for an arbitrary number of arguments:



>>> import  math 
>>> math.gcd(9,12,21) 
3




Calculates the floating-point number closest to " x " in the direction of " y ".



>>> math.nextafter(2, -1)
1.9999999999999998




This method returns the value of the least significant bit of the floating point number x.



>>> 1 - math.ulp(1)
0.9999999999999998
>>> math.nextafter(1, -1) + math.ulp(1)
1.0




issue38870



The unparse method was added to the ast module.

The new method can be used to create a line of code and then execute it.



>>> import ast
>>> parsed = ast.parse('from sys import platform; print(platform)')
>>> unparsed_str = ast.unparse(parsed)
>>> print(unparsed_str)
from sys import platform
print(platform)
>>> exec(unparsed_str)
win32




issue39507, issue39509



Adding new codes to http.HTTPStatus.



" Save 418! "

418 IM_A_TEAPOT
103 EARLY_HINTS
425 TOO_EARLY




UPD :

PEP 614



Relaxing grammatical restrictions for decorators.



It was:



buttons = [QPushButton(f'Button {i}') for i in range(10)]

button_0 = buttons[0]

@button_0.clicked.connect
def spam():
    ...

button_1 = buttons[1]

@button_1.clicked.connect
def eggs():
    ...


Now you can remove unnecessary assignments and call directly:



buttons = [QPushButton(f'Button {i}') for i in range(10)]

@buttons[0].clicked.connect
def spam():
    ...

@buttons[1].clicked.connect
def eggs():
    ...




"The tuple must be enclosed in parentheses."



This is based on Guido's vision in the same letter. Quote:



But I will not allow commas. I cannot agree with this



@f, g
def pooh(): ...


This can lead inexperienced programmers to the conclusion that multiple decorators can be called in a row this way. The parentheses are needed to clarify things without additional restrictions or complex syntax.




issue17005



The new graphlib module provides functionality for topological sorting of a graph of hashed nodes.

More details can be found in the documentation .



UPD :ifinik

image



>>> from graphlib import TopologicalSorter 
>>> graph = {'E': {'C', 'F'}, 'D': {'B', 'C'}, 'B': {'A'}, 'A': {'F'}} 
>>> ts = TopologicalSorter(graph) 
>>> tuple(ts.static_order()) 
('C', 'F', 'E', 'A', 'B', 'D')
>>> tuple(ts.static_order())
('F', 'C', 'A', 'E', 'B', 'D')


The graph can be transferred not immediately, but fill in the TopologicalSorter using the add method . In addition, the class is adapted to parallel computing and can be used, for example, to create a task queue.



issue37630, issue40479



Updating hashlib.

Hashlib can now use SHA3 and SHAKE XOF hashes from OpenSSL.

Built-in hash modules can now be disabled or selectively enabled, for example to enforce an OpenSSL-based implementation.



Optimization



A summary of the performance improvements from Python 3.4 to Python 3.9:



Python version                       3.4     3.5     3.6     3.7     3.8    3.9
--------------                       ---     ---     ---     ---     ---    ---

Variable and attribute read access:
    read_local                       7.1     7.1     5.4     5.1     3.9    4.0
    read_nonlocal                    7.1     8.1     5.8     5.4     4.4    4.8
    read_global                     15.5    19.0    14.3    13.6     7.6    7.7
    read_builtin                    21.1    21.6    18.5    19.0     7.5    7.7
    read_classvar_from_class        25.6    26.5    20.7    19.5    18.4   18.6
    read_classvar_from_instance     22.8    23.5    18.8    17.1    16.4   20.1
    read_instancevar                32.4    33.1    28.0    26.3    25.4   27.7
    read_instancevar_slots          27.8    31.3    20.8    20.8    20.2   24.5
    read_namedtuple                 73.8    57.5    45.0    46.8    18.4   23.2
    read_boundmethod                37.6    37.9    29.6    26.9    27.7   45.9

Variable and attribute write access:
    write_local                      8.7     9.3     5.5     5.3     4.3    4.2
    write_nonlocal                  10.5    11.1     5.6     5.5     4.7    4.9
    write_global                    19.7    21.2    18.0    18.0    15.8   17.2
    write_classvar                  92.9    96.0   104.6   102.1    39.2   43.2
    write_instancevar               44.6    45.8    40.0    38.9    35.5   40.7
    write_instancevar_slots         35.6    36.1    27.3    26.6    25.7   27.7

Data structure read access:
    read_list                       24.2    24.5    20.8    20.8    19.0   21.1
    read_deque                      24.7    25.5    20.2    20.6    19.8   21.6
    read_dict                       24.3    25.7    22.3    23.0    21.0   22.5
    read_strdict                    22.6    24.3    19.5    21.2    18.9   21.6

Data structure write access:
    write_list                      27.1    28.5    22.5    21.6    20.0   21.6
    write_deque                     28.7    30.1    22.7    21.8    23.5   23.2
    write_dict                      31.4    33.3    29.3    29.2    24.7   27.8
    write_strdict                   28.4    29.9    27.5    25.2    23.1   29.8

Stack (or queue) operations:
    list_append_pop                 93.4   112.7    75.4    74.2    50.8   53.9
    deque_append_pop                43.5    57.0    49.4    49.2    42.5   45.5
    deque_append_popleft            43.7    57.3    49.7    49.7    42.8   45.5

Timing loop:
    loop_overhead                    0.5     0.6     0.4     0.3     0.3    0.3


The test script displays the time in nanoseconds. Tests were performed on an Intel Core i7-4960HQ processor . The test code can be found in the repository at " Tools / scripts / var_access_benchmark.py " .



Thank you for attention.



Link to the official Python 3.9 manual .

Unsubscribe in the comments if you missed something.



All Articles