V 3.4
- enum: реализация классов IntEnum и Enum для работы со списками перечислимых констант. [Ссылка](https://docs.python.org/3/library/enum.html)
- tracemalloc: трассировка распределения памяти. https://peps.python.org/pep-0454/
- В functools добавлены generic-функции одиночной диспетчеризации (Single-dispatch generic functions). https://peps.python.org/pep-0443/
V 3.5
- Расширено применение операторов распаковки "\*" и "\*\*", которые теперь можно использовать для произвольного числа распаковок при вызове функции или при манипуляциях с множествами, кортежами, списками и словарями. (ранее допускалась только одна распаковка). Например, для функции
```
def fn(a, b, c, d):
print(a, b, c, d)
```
можно выполнить
```
fn(**{'a': 1, 'c': 3}, **{'b': 2, 'd': 4})")
```
а для кортежа
```
{*range(4), 4, *(5, 6, 7)}
```
- memoryview теперь поддерживает индексацию кортежей (включая многомерные). https://docs.python.org/dev/library/stdtypes.html#memoryview
V 3.6
- поддержка форматируемых строковых литералов. https://docs.python.org/dev/whatsnew/3.6.html#whatsnew36-pep498
```
> name = "Fred"
> f"He said his name is {name}."
"He said his name is Fred."
> width = 10
> precision = 4
> value = decimal.Decimal("12.34567")
> f"result: {value:{width}.{precision}}" # nested fields
"result: 12.35"
```
- Читаемость чисел можно улучшать при помощи символов подчеркивания. https://docs.python.org/dev/whatsnew/3.6.html#whatsnew36-pep515
```
> 1_000_000_000_000_000
1000000000000000
> 0x_FF_FF_FF_FF
4294967295
```
- определен синтаксис аннотаций для переменных. https://docs.python.org/dev/whatsnew/3.6.html#whatsnew36-pep526
```
primes: List[int] = []
captain: str # Note: no initial value!
class Starship:
stats: Dict[str, int] = {}
```
- Добавлена возможность определения асинхронных генераторов.https://docs.python.org/dev/whatsnew/3.6.html#whatsnew36-pep525
```
async def ticker(delay, to):
"""Yield numbers from 0 to *to* every *delay* seconds."""
for i in range(to):
yield i
await asyncio.sleep(delay)
```
- возможность асинхронной обработки. добавляет поддержку использования async for в выражениях list, set, dict comprehensions и генераторах https://docs.python.org/dev/whatsnew/3.6.html#whatsnew36-pep530
```
result = [i async for i in aiter() if i % 2]
```
- Настройка создания класса в Python. https://docs.python.org/dev/whatsnew/3.6.html#whatsnew36-pep487
Теперь можно настраивать создание подклассов без использования метакласса. Метод класса new __init_subclass__ будет вызываться в базовом классе всякий раз, когда создается новый подкласс:
```
class PluginBase:
subclasses = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.subclasses.append(cls)
class Plugin1(PluginBase):
pass
class Plugin2(PluginBase):
pass
```
- Файл ._pth может быть добавлен, чтобы включить изолированный режим и полностью указать все пути поиска, чтобы избежать поиска в реестре и окружении. Дополнительные сведения см. в разделе https://docs.python.org/dev/using/windows.html#windows-finding-modules
- PEP 487: Усовершенствования протокола дескрипторов. PEP 487 расширяет протокол дескрипторов, включая новый необязательный метод __set_name__(). Каждый раз, когда определяется новый класс, новый метод будет вызываться для всех дескрипторов, включенных в определение, предоставляя им ссылку на определяемый класс и имя, присвоенное дескриптору в пространстве имен класса. Другими словами, экземпляры дескрипторов теперь могут знать имя атрибута дескриптора в классе-владельце:
```
class IntField:
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError(f"expecting integer in {self.name}")
instance.__dict__[self.name] = value
# this is the new initializer:
def __set_name__(self, owner, name):
self.name = name
class Model:
int_field = IntField()
```
- PEP 495 добавляет новый атрибут fold к экземплярам классов datetime.datetime и datetime.time для различения двух моментов времени, для которых местное время одинаково:
```
>>> u0 = datetime(2016, 11, 6, 4, tzinfo=timezone.utc)
>>> for i in range(4):
... u = u0 + i*HOUR
... t = u.astimezone(Eastern)
... print(u.time(), 'UTC =', t.time(), t.tzname(), t.fold)
...
04:00:00 UTC = 00:00:00 EDT 0
05:00:00 UTC = 01:00:00 EDT 0
06:00:00 UTC = 01:00:00 EST 1
07:00:00 UTC = 02:00:00 EST 0
```
V 3.7
- Python 3.7 включает новую встроенную функцию breakpoint() как простой и последовательный способ входа в отладчик Python. https://docs.python.org/dev/whatsnew/3.7.html#whatsnew37-pep553
- PEP 562: Настройка доступа к атрибутам модуля. Python 3.7 позволяет определять __getattr__() на модулях и будет вызывать его всякий раз, когда атрибут модуля не найден. Определение __dir__() на модулях теперь также разрешено. Типичным примером того, где это может быть полезно, является обесценивание атрибутов модуля и ленивая загрузка.
- PEP 552: Файлы .pyc на основе хэша. Python традиционно проверяет актуальность файлов кэша байткода (т.е. файлов .pyc), сравнивая исходные метаданные (временную метку последнего изменения и размер) с исходными метаданными, сохраненными в заголовке файла кэша при его генерации. Несмотря на свою эффективность, этот метод аннулирования имеет свои недостатки. Если временные метки файловой системы слишком грубые, Python может пропустить обновления источника, что приведет к путанице пользователей. Кроме того, наличие временной метки в файле кэша проблематично для build reproducibility и систем сборки на основе содержимого. PEP 552 расширяет формат pyc, позволяя использовать хэш исходного файла для проверки недействительности вместо временной метки источника. Такие .pyc файлы называются «основанными на хэше». По умолчанию Python по-прежнему использует проверку недействительности на основе временной метки и не генерирует файлы .pyc на основе хэша во время выполнения. Файлы .pyc на основе хэша могут быть сгенерированы с помощью py_compile или compileall.
- dataclasses. Новый декоратор dataclass() предоставляет возможность объявлять классы данных. Класс данных описывает свои атрибуты с помощью аннотаций переменных класса. Его конструктор и другие магические методы, такие как __repr__(), __eq__() и __hash__() генерируются автоматически.
```
@dataclass
class Point:
x: float
y: float
z: float = 0.0
p = Point(1.5, 2.5)
print(p) # produces "Point(x=1.5, y=2.5, z=0.0)"
```
- Новая функция asyncio.create_task() была добавлена в качестве сокращения для asyncio.get_event_loop().create_task().
V 3.8
- Выражения заданий. Существует новый синтаксис :=, который присваивает значения переменным как части большего выражения.
В этом примере выражение присваивания помогает избежать двойного вызова len():
```
if (n := len(a)) > 10:
print(f"List is too long ({n} elements, expected <= 10)")
```
- Только позиционные параметры. Существует новый синтаксис параметров функций / для указания того, что некоторые параметры функций должны быть указаны позиционно и не могут быть использованы в качестве аргументов ключевых слов. Это та же нотация, что и help() для функций языка Си
Параметры a и b должны быть только позиционными, в то время как c или d могут быть как позиционными, так и именованными, а 'e' или 'f' должны быть именованными:
```
def f(a, b, /, c, d, *, e, f):
print(f'a={a}, b={b}, c={c}, d={d}, e={e}, f={f}')
> f(10, 20, 30, d=40, e=50, f=60)
a=10, b=20, c=30, d=40, e=50, f=60
```
- f-строки поддерживают = для самодокументирования выражений и отладки
```
> user = 'eric_idle'
> member_since = date(1975, 7, 31)
> f'{user=} {member_since=}'
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"
```
Обычные f-string format specifiers позволяют больше контролировать отображение результата выражения:
```
> print(f'{theta=} {cos(radians(theta))=:.3f}')
theta=30 cos(radians(theta))=0.866
```
- Dict comprehensions были синхронизированы с dict literals так, что ключ вычисляется первым, а значение вторым:
```
>>> # Dict comprehension
>>> cast = {input('role? '): input('actor? ') for i in range(2)}
role? King Arthur
actor? Chapman
role? Black Knight
actor? Cleese
>>> # Dict literal
>>> cast = {input('role? '): input('actor? ')}
role? Sir Robin
actor? Eric Idle
```
Гарантированный порядок выполнения полезен в выражениях присваивания, поскольку переменные, назначенные в ключевом выражении, будут доступны в выражении значения:
```
>>> names = ['Martin von Löwis', 'Łukasz Langa', 'Walter Dörwald']
>>> {(n := normalize('NFC', name)).casefold() : n for name in names}
{'martin von löwis': 'Martin von Löwis',
'łukasz langa': 'Łukasz Langa',
'walter dörwald': 'Walter Dörwald'}
```
V 3.9
- Операторы слияния и обновления словаря
```
>>> x = {"key1": "value1 from x", "key2": "value2 from x"}
>>> y = {"key2": "value2 from y", "key3": "value3 from y"}
>>> x | y
{'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'}
```
- Новые строковые методы для удаления префиксов и суффиксов. Добавлены методы str.removeprefix(prefix) и str.removesuffix(suffix), позволяющие легко удалить ненужный префикс или суффикс из строки.
- Добавлен новый coroutine asyncio.to_thread(). Он в основном используется для запуска функций, связанных с IO, в отдельном потоке, чтобы избежать блокирования цикла событий, и по сути работает как высокоуровневая версия run_in_executor(), которая может напрямую принимать аргументы ключевых слов.
V 3.10
- PEP 634: Структурное сопоставление шаблонов
Идиома `if ... elif ... elif ... else` часто используется для определения типа или формы объекта специальным способом, используя одну или несколько проверок, таких как
`isinstance(x, cls), hasattr(x, "attr"), len(x) == n` или `key" in x` в качестве защиты выбора пременения блокировки.
```
if isinstance(x, tuple) and len(x) == 2:
host, port = x
mode = "http"
elif isinstance(x, tuple) and len(x) == 3:
host, port, mode = x
# Etc.
```
Лучше так
```
match x:
case host, port:
mode = "http"
case host, port, mode:
pass
# Etc.
```
Было
```
if (isinstance(node, BinOp) and node.op == "+"
and isinstance(node.right, BinOp) and node.right.op == "*"):
a, b, c = node.left, node.right.left, node.right.right
# Handle a + b*c
```
Стало
```
match node:
case BinOp("+", a, BinOp("*", b, c)):
# Handle a + b*c
```
- PEP 604: Оператор союза нового типа. Был введен новый оператор объединения типов, который позволяет использовать синтаксис X | Y.
```
def square(number: int | float) -> int | float:
return number ** 2
```
- В типе int появился новый метод int.bit_count(), возвращающий количество единиц в двоичном расширении данного целого числа.
```
> i = 123
> i.bit_count()
6
> bin(i)
'0b1111011'
```