Novedades esperadas en Python 3.9

La nueva versión se espera solo en octubre, pero ya puede leer lo que nos espera y probar el lanzamiento preliminar.
En este artículo, lo más interesante, en mi opinión, cambia.

En primer lugar, se nos recuerda que las capas que admiten la compatibilidad con versiones anteriores con la versión 2.7 se eliminan lentamente y se les pide que presten atención a DeprecationWarning y las eliminen. Algunas advertencias seguirán en 3.9, pero es mejor deshacerse de ellas.

Operador de
combinación de diccionarios ( PEP-584 ) Hasta ahora, había varias formas de combinar diccionarios, pero cada uno de ellos tenía pequeños defectos o matices.
Varias formas de combinar diccionarios
1. update
d1 = {'one': 1}
d2 = {'two': 2}
#     ,..
d1.update(d2)
# ...  . 
united_dict = d1.copy()
united_dict.update(d2)

2.
united_dict = {**d1, **d2}

, , , .
3. dict(d1, **d2), . , d2 .
4. collections.ChainMap
.
, , .
from collections import ChainMap
d1 = {'one': 1}
d2 = {'two': 2}
united_dict = ChainMap(d1, d2)

, , , . , - .

Ahora puedes escribir simplemente
united_dict = d1 | d2
# ,        ,    update():
d1 |= d2

Por lo tanto, creo que una nueva posibilidad de combinar diccionarios con un operador atraerá a muchos.

Simplificación de anotaciones para contenedores y otros tipos que se pueden parametrizar ( PEP-0585 )
La siguiente innovación es muy útil para quienes usan anotaciones de tipo.
Ahora simplifica la anotación de colecciones, como list y dict, y tipos generalmente parametrizados.

Para estos tipos, se introduce el término Genérico: este es un tipo que se puede parametrizar, generalmente un contenedor. Por ejemplo, dict. Y la pregunta es cómo traducirlo correctamente para que no rompa los dientes. Realmente no quiero usar la palabra "genérico". Así que en los comentarios realmente espero otras sugerencias. ¿Quizás en algún lugar de las traducciones había un nombre mejor?
Genérico parametrizado: dict [str, int].

Entonces, para estos tipos, ahora no necesita importar las anotaciones correspondientes de la escritura, pero solo puede usar los nombres de los tipos.
por ejemplo
# 
from typing import List
List[str]
# 
list[int]

.

:
# 
from typing import OrderedDict
OrderedDict[str, int]
# 
from collections import OrderedDict
OrderedDict[str, int]

tuple # typing.Tuple
list # typing.List
dict # typing.Dict
set # typing.Set
frozenset # typing.FrozenSet
type # typing.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


Para las cadenas, aparecieron los métodos removeprefix () y removevesuffix () ( PEP 616 )
. Aquí todo es simple. Si la línea comienza con un prefijo, se devolverá la línea sin este prefijo. Si el prefijo se repite varias veces, se eliminará solo una vez. De manera similar con el sufijo:
some_str = 'prefix of some string and here suffix'
some_str.removeprefix('prefix')
>> ' of some string and here suffix'
some_str.removesuffix('suffix')
>> 'prefix of some string and here '

Alternativas actuales
1. , , — removeprefix.
def removeprefix(self: str, prefix: str, /) -> str:
    if self.startswith(prefix):
        return self[len(prefix):]
    else:
        return self[:]

2. lstrip, rstrip:
	'foobar'.lstrip(('foo',))

, , .

Algunos cambios en el módulo matemático
La función math.gcd () para encontrar el divisor común más grande ahora acepta una lista de enteros, por lo que puede encontrar un divisor común con más de un número con una función.
Hay una función para determinar el múltiplo común más pequeño de math.lcm () , que también acepta un número ilimitado de enteros.
Las siguientes dos funciones están interconectadas.
math.nextafter (x, y) : calcula el número de coma flotante más cercano a x si se mueve en la dirección y.
math.ulp (x)- significa "Unidad en el último lugar" y depende de la precisión de los cálculos de su computadora. Para números positivos, se devolverá el valor más bajo del número, de modo que cuando se agregue x + ulp (x), se obtendrá el número de punto flotante más cercano.
import math

math.gcd(24, 36)
>> 12
math.lcm(12, 18)
>> 36
math.nextafter(3, -1)
>> 2.9999999999999996
3 - math.ulp(3)
>> 2.9999999999999996
math.nextafter(3, -1) + math.ulp(3)
>> 3.0 

Ahora cualquier expresión válida puede ser un decorador ( PEP-0614 )
La restricción se elimina de los decoradores, según la cual solo un nombre puede actuar como decorador y su sintaxis solo permite la separación por puntos.

No creo que muchas personas hayan pensado en la existencia de tal restricción, pero la descripción de pep da un ejemplo cuando una innovación hace que el código sea más delgado. Por analogía, podemos citar
Ejemplo simplificado y artificial:
def a(func):
	def wrapper():
		print('a')
		func()
	return wrapper
	
def b(func):
	def wrapper():
		print('b')
		func()
	return wrapper
	
decorators = [a, b]

@decorators[0] #   3.8        
def some_func():
	print('original')
	
some_func()
>> a
>> original

El método no analizado ( bpo-38870 ) se agregó al módulo ast.
Como su nombre lo indica, puede compilar la cadena fuente usando el objeto ast.AST. Una vez, incluso quise usar esto y fue sorprendente que no hubiera tal método.
Ejemplo:
import ast
parsed = ast.parse('import pprint; pprint.pprint({"one":1, "two":2})')
unparsed_str = ast.unparse(parsed)
print(unparsed_str)
>> import pprint
>> pprint.pprint({'one': 1, 'two': 2})
exec(unparsed_str)
>> {'one': 1, 'two': 2}

La nueva clase functools.TopologicalSorter para la clasificación topológica de gráficos acíclicos dirigidos ( bpo-17005 ) El
gráfico que se pasa al clasificador debe ser un diccionario en el que las claves son los vértices del gráfico, y el valor es un objeto iterable con predecesores (vértices cuyos arcos apuntan a la clave). Como clave, como de costumbre, cualquier tipo de hash es adecuado.
Ejemplo:
:

from functools import TopologicalSorter
graph = graph = {8: [3, 7], 11: [5, 7], 2: [11], 9: [8, 11], 10: [3, 11]}
t_sorter = TopologicalSorter(graph)
t_sorted_list = list(t_sorted_list.static_order()) #  ,    ,     static_order.
>> [3, 7, 5, 8, 11, 2, 9, 10]


, TopologicalSorter add. , , .

Nuevos estados que hemos estado esperando durante tanto tiempo se han
agregado a http.HTTPStatus : 103 EARLY_HINTS
418 IM_A_TEAPOT
425 TOO_EARLY

Y algunos cambios más:
  • Los tipos incorporados (rango, tupla, conjunto, conjunto congelado, lista) se aceleran ( PEP-590 )
  • "" .replace ("", s, n) ahora devuelve s, no una cadena vacía, para todos los n distintos de cero. Esto es cierto tanto para bytes como para bytearray.
  • ipaddress ahora admite el análisis de direcciones IPv6 con destinos.

Dado que la versión 3.9 todavía está en desarrollo, y tal vez se agregarán más cambios, planeo complementar este artículo según sea necesario.

Puede leer con más detalle:
docs.python.org/3.9/whatsnew/3.9.html
www.python.org/downloads/release/python-390a6
En general, no quiere decir que los cambios futuros son lo que todos han estado esperando durante mucho tiempo y sin los cuales es imposible sobrevivir, aunque hay algunos puntos interesantes. ¿Y qué te pareció más interesante en la nueva versión?

UPD:
enlace actualizado a la última versión;
PEP-0585 agregado sobre la anotación de tipo

All Articles