Python был разработан около тридцати лет назад, первая его официальная версия вышла в 1991 году и имела номер 0.9. После этого довольно долгое время язык развивался, и популярность он получил в 2000-х годах, во время мажорной второй версии. Однако уже тогда было понятно, что в языке необходимы изменения, которые будут обратно несовместимы с текущими версиями, такие как например, изменения в поведении юникодных строк. Однако вторая версия Python была уже очень популярна к этому моменту, поэтому третья работа над третьей версией велась одновременно с работой над 2.7. Довольно долго у core-разработчиков Python не было определенной стратегии, поэтому до версии 3.4 изменения были довольно хаотичны.
С 2019 года Python адаптирует годичные релизные циклы. Это изменение было представлено в PEP-602 Что это значит для пользоватеоей Python?
- новая минорная (3.X.0) версия выходит каждый год
- фаза активной разработки версии 3.X+1.0 начинается в тот момент, когда в релих отправляется 3.X.beta и продолжается 12 месяцев
- каждая минорная версия активно поддерживается в течении полутора лет
- каждая минорная версия получает обновления безопасности в течении трех с половиной лет Пример расписания релизов для версии 3.9 можно посмотреть на рисунке:
What’s new in Python 3.9?
Релиз Python 3.9 произошел 2020-10-05. Рассмотрим что есть нового в этой версии.
Работа со словарями
Допустим, есть два словаря, которые мы зотим объединить.
В версиях до 3.9 можно было бы сделать таким образом:
In [9]:
pycon = {2017: "Portland", 2018: "Cleveland", 2019: "Cleveland", 2020: "online"}
europython = {2017: "Rimini", 2018: "Edinburgh", 2019: "Basel"}
{**pycon, **europython}
Out[9]:
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}
Синтаксис ** разворачивает словарь, и когда они объединяются, более позднее значение затирается более новым. Аналогичные дейтсвия можно совершить, если использовать следующий синтаксис:
In [7]:
merged_dict = pycon.copy()
for key, value
in europython.items():
merged_dict[key] = value
merged_dict
Out[7]:
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}
Или таким образом:
In [8]:
pycon.update(europython)
pycon
Out[8]:
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}
Этот способ пойдойдет в случае если нужно изменить первоначальный словарь.
In [14]:
merged_dict = pycon.copy().update(europython)
Out[14]:
{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}
In [ ]:
Однако если нужно сохранить эти данные в новом словаре, этим способом воспользоваться нельзя, в последнем примере
In [17]:
merged_dict
is None
Out[17]:
True
В библиотеке collections есть объект ChainMap, который тоже обхединяет словари, но его результатом будет объект ChainMap, а не словарь. Он состоит из нескольких словарей, следующих друг за другом. Если взять значение по ключу, то вернется то значение, которое встречается раньше. То есть, в этом примере для ключа 2019, вернется значение Cleveland
In [28]:
from collections import ChainMap
merged_dict = ChainMap(pycon, europython)
merged_dict
Out[28]:
ChainMap({2017: 'Amsterdam', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}, {2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel'})
В Python 3.8 был представлен walrus-оператор. С его помощью можно решить проблему примера с update и скопировать словарь в новую переменную:In [11]:
(merged_dict := pycon.copy()).update(europython)
merged_dict
Out[11]:
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}
В Python 3.9 в PEP-0614 добавлен синтаксис | (читается как pipe), который объединяет словари аналогично первому примеру:
In [13]:
pycon | europython
Out[13]:
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}
При этом первоначальный словарь не меняется:
In [14]:
pycon
Out[14]:
{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}
Если все-таки нужно обновить первоначальный словарь, можно воспользоваться синтаксисом |= (работает по аналогии с +=): a |= b a = a|bIn [16]:
pycon |= europython
pycon
Out[16]:
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}
Важно помнить, что поскольку более поздние значения перезаписывают более ранние значения, эта операция может быть не коммуникативна.
In [23]:
print(europython | pycon)
print(pycon | europython)
{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}
Синтаксис | работает только непосредственно со словарями, тогда как синтаксис ** работает и с orderedict и с другими подобными словарям объектами.
Изменения в работе с декораторами
До версии 3.9 в качестве декораторов могли выступать функции или классы, но не такие объекты как списки или словари. Рассмотрим пример, в котором это будет удобно использовать. Допустим есть UI-приложение с кнопками, и нужно добавить какое-то сообщение по нажатию на каждую кнопку. Было бы удобно это сделать с помощью декоратора, но что делать, если для каждой кнопки нужно печатать различные сообщения. Это можно сделать следующим образом:In [ ]:
buttons = [QPushButton(f'Button
{i
}')
for i
in range(10)]
button_0 = buttons[0]
button_1 = buttons[1]
@button_0.clicked.connect
def say_hello():
message.setText("Hello, World!")
@button_1.clicked.connect
def say_goodbye():
message.setText("Goodbye, World!")
Создаем list comprehension из функций, явно присваем объектам значения элементов списка, и их можно использовать в качестве декораторов. Это будет работать, однако не будет эффективно, если объектов из которых будут созданы декораторы, будет достаточно много.
Это не единственный способ, но другие будут довольно неоднозначными. Рассмотрим два из них. В первом случае создадим функцию, которая будет возвращать необходимую для декоратора функцию:In [ ]:
def _(x):
return x
@_(buttons[0].clicked.connect)
def say_hello():
...
Использование eval:In [ ]:
@eval("buttons[1].clicked.connect")
def say_bye():
...
В Python 3.9 стало возможно создавать декораторы из любых объектов, например из элементов списков и словарей. Можно рассмотреть синтаксис, который реализует тот же самый пример:
In [ ]:
@buttons[0].clicked.connect
def say_hello():
message.setText("Hello, World!")
@buttons[1].clicked.connect
def say_goodbye():
message.setText("Goodbye, World!")
Похожим образом будет выглядеть синтаксис для значений словаря:
In [ ]:
buttons = {'hello': QPushButton('Hello!'), 'goodbye': QPushButton('Goodbye!')}
@buttons['hello'].clicked.connect
def say_hello():
message.setText("Hello, World!")
@buttons['goodbye'].clicked.connect
def say_goodbye():
message.setText("Goodbye, World!")
Этот функционал, несмотря на то, что не приносит новых возможностей, позволяет писать более чистый код и избегать рискованных решений вроде использования eval.
Изменения в синтаксисе типирования
Дженерики
Дженерики это типы, которые могут быть параметризованы, обычно являются контейнерами, например dict. Параметризованные дженерики это типы, для которых указан внутренний тип, например dict[str, int]
Начиная с Python 3.7 стало можно указывать тип объекта, конкре��изируя тип внутренних элементов контейнеры. Но для этого нужно было импортировать таки типы как List из модуля typing:
In [ ]:
from typing import List, Dict
def find(haystack: Dict[str, List[int]]) -> int:
#def find(haystack: dict) -> int:
...
Можно было не конкретизировать тип внутренних значений, для этого не нужно было импортировать дополинтельные типы и можно было использовать стандартные типы dict и list. Благодаря этому нововведению, внешние библиотеки такие как Mypy стали распознавать дженерики.
Также, в версии 3.9 стало можно пользоваться аннотациями без явного их импорта из модуля __future__
Расширение возможностей аннотаций
Аннотации были доступны для использования и в более ранних версиях Python, однако их функция была скорее информационной, использовались они в первую очередь для документации. Синтаксис использования аннотаций до Python 3.9 выглядел таким образом:
In [24]:
def speed(distance: "feet", time: "seconds") -> "miles per hour":
fps2mph = 3600 / 5280
return distance / time * fps2mph
В Python 3.9 появился новый объект типа Annotated, который принимает на вход два аргумента, первый это реальный тип, которым должен обладать аннотриуемый объект, а второй это название для целей документации:
In [ ]:
from typing import Annotated
def speed(
distance: Annotated[float, "feet"], time: Annotated[float, "seconds"]) -> Annotated[float, "miles per hour"]:
fps2mph = 3600 / 5280
return distance / time * fps2mph
Когда происходит проверка аннотаций, проверяется только первый аргумент, в котором находится «реальный» тип объекта, а второй использовуется как и в предыдущих версиях:
In [25]:
speed.__annotations__
Out[25]:
{'distance': 'feet', 'time': 'seconds', 'return': 'miles per hour'}
Изменения связанные с часовыми поясами
В предыдущих версиях Python, модуль datetime не содержал информации о часовых поясах, и рекомендованным способом работы с ними была библиотека python-dateutil.
Однако начиная с Python 3.9 появился модуль zoneinfo, который содержит информацию о часовых поясах и позволяет создавать объекты им соответствующие:
In [31]:
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
local_tz = ZoneInfo('Europe/Amsterdam')
datetime.now(tz=timezone.utc), datetime.now()
Out[31]:
(datetime.datetime(2021, 5, 4, 15, 58, 36, 295472, tzinfo=datetime.timezone.utc),
datetime.datetime(2021, 5, 4, 17, 58, 36, 295477))
В стандартной библиотеке не было информации ни о каких часовых поясах, кроме utc, и необходимо было использовать pytz чтобы создать объект, содержащий информацию о часовом поясе. Теперь это можно сделать без установки дополнительных библиотек:In [32]:
from zoneinfo import ZoneInfo
local_tz = ZoneInfo('Europe/Amsterdam')
datetime.now(tz=local_tz)
Out[32]:
(datetime.datetime(2021, 5, 4, 17, 58, 37, 765947, tzinfo=zoneinfo.ZoneInfo(key='Europe/Amsterdam')),)
In [ ]:
Всего часовых поясов больше чем можно было бы предположить, и многие из них представлены в модуле `zoneinfo`
In [33]:
import zoneinfo
tzs = zoneinfo.available_timezones()
len(tzs)
Out[33]:
594
Новые методы работы со строкам
Иногда нужно убрать первые или последние несколько символов из строки. Есть метод strip, который обладает казалось бы похожим функционалом, но он может иногда давать неожиданные результаты Например в таком случае:
In [34]:
"ababbbbbbaaccc".lstrip("ab")
Out[34]:
'ccc'
В Python 3.9 были добавлены функции removeprefix, removesuffix, которые выполняют то, что от них ожидается: удаляют первые или последние несколько символов строки.In [35]:
"ababbbbbbaaccc".removeprefix("ab")
Out[35]:
'abbbbbbaaccc'
In [36]:
"ababbbbbbaaccc".removesuffix("c")
Out[36]:
'ababbbbbbaacc'
In [36]:
Если строка не содержит суффикс или префикс, строка не меняется, никаких исключений не появляется.
In [37]:
"ababbbbbbaaccc".removesuffix("something else")
Out[37]:
'ababbbbbbaaccc'
Ссылки:
Python 3.10
Последняя версия Python 3.10 это 0b3, которая вышла 17 июня 2021 года. Согласно расписанию релизов, полноценный релиз появится примерно в октябре 2021. Пока официального релиза нет, версия не доступна в пакетных менеджерах (таких как brew). Соответственно, чтобы ее установить, билд нужно скачать вручную с www.python.org и уствноваить на своей машине. Рассмотрим изменения, доступные в этой Python 3.9.
Pattern Matching
В более ранних версиях Python если нужно описать различное поведение, в зависимости от того, какой объект используется, скорее всего будет использоваться условный оператор:In [ ]:
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
Однако в Python 3.10 вместе с PEP-0635 будет добавлен новый оператор match, который может использоваться с case:In [ ]:
match x:
case host, port:
mode = "http"
case host, port, mode:
pass
cass Class1:
...
case host == 'localhost'
...
Также с его помощью будет удобно реализовывать, например, обработку ошибок:In [ ]:
def http_error(status):
match status:
case 400:
return "Bad request"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something's wrong with the Internet"
Это одно из самых «громких» нововведений в последних версиях Python и возможно самое ожидаемое коммьюнити.
Более удобное использование Union для типирования:
Если раньше чтобы указать, что аргумент функции может быть одним из нескольких типов, необходимо было использовать Union, импортируемый из пакета typing:In [ ]:
from typing import Union
def square(number: Union[int, float]) -> Union[int, float]:
return number ** 2
То начиная с Python 3.10 можно будет заменить его оператором pipe | и, соответственно, избавиться от импорта:In [ ]:
def square(number: int | float) -> int | float:
return number ** 2
Контекстные менеджеры
Синтаксис работы с контекстными менеджерами упростится, теперь несколько контекстных менеджеров можно объединять в одном with, а так же не обязательно присваивать им локальные имена:In [ ]:
with (
CtxManager1(),
CtxManager2()
):
...
with (CtxManager1()
as example,
CtxManager2()):
...
with (
CtxManager1()
as example1,
CtxManager2()
as example2
):
...
Более информативные сообщения об ошибках
Наверняка многие из читателей сталкивались с тем, что сообщение об ошибке слишком общее и само по себе не говорит о том, что нужно сделать чтобы ошибку исправить. В новой версиеи Python core-разработчики улучшили самые распространенные из них и теперь сообщения об ошибках будут намного более читабельными:In [ ]:
expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
^
SyntaxError: '{' was never closed
In [ ]:
>>>
if rocket.position > event_horizon
File "<stdin>", line 1
if rocket.position > event_horizon
^
SyntaxError: expected ':'
In [ ]:
>>> {x,y
for x,y
in range(100)}
File "<stdin>", line 1
{x,y
for x,y
in range(100)}
^
SyntaxError: did you forget parentheses around the comprehension target?
In [ ]:
if rocket.position = event_horizon:
File "<stdin>", line 1
if rocket.position = event_horizon:
^
SyntaxError: cannot assign to attribute here. Maybe you meant '==' instead
In [ ]:
def foo():
...
if lel:
... x = 2
File "<stdin>", line 3
x = 2
^
IndentationError: expected an indented block after 'if' statement
in line 2
Остальное
- Модуль distutils постепенно выыводится из употребления, чтобы быть полностью удаленным в Python 3.12. Это связано с тем, что его функции были полностью заменены такими модулями как setuptools и packaging.
- Улучшение читабельности сообщений в модуле debugging
Это не все изменения которые попадут в Python 3.10, с полным списком можно ознакомиться посмотрев список изменений.
Прокачать Python можно на курсах:
<!DOCTYPE html>
<html dir="ltr" lang="ru-RU">
<head>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="profile" href="http://gmpg.org/xfn/11" />
<title>Что нового появилось в Python в 2021 году? OTUS</title>
<!-- All in One SEO 4.5.2.1 - aioseo.com -->
<meta name="description" content="Краткая история Python Python был разработан около тридцати лет назад, первая его официальная версия вышла в 1991 году и имела номер 0.9. После этого довольно долгое время язык развивался, и популярность он получил в 2000-х годах, во время мажорной второй версии. Однако уже тогда было понятно, что в языке необходимы изменения, которые будут обратно несовместимы" />
<meta name="robots" content="max-image-preview:large" />
<link rel="canonical" href="https://otus.ru/journal/chto-novogo-poyavilos-v-python-v-2021-godu/" />
<meta name="generator" content="All in One SEO (AIOSEO) 4.5.2.1" />
<script type="application/ld+json" class="aioseo-schema">
{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#article","name":"\u0427\u0442\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0432 Python \u0432 2021 \u0433\u043e\u0434\u0443? OTUS","headline":"\u0427\u0442\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0432 Python \u0432 2021 \u0433\u043e\u0434\u0443?","author":{"@id":"https:\/\/otus.ru\/journal\/author\/d-golovin\/#author"},"publisher":{"@id":"https:\/\/otus.ru\/journal\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/otus.ru\/journal\/wp-content\/uploads\/2021\/06\/oj-1080x720-kopiya-3.png","width":1080,"height":720},"datePublished":"2021-06-28T15:21:00+00:00","dateModified":"2021-06-28T15:21:01+00:00","inLanguage":"ru-RU","mainEntityOfPage":{"@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#webpage"},"isPartOf":{"@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#webpage"},"articleSection":"\u041f\u043e\u043b\u0435\u0437\u043d\u043e\u0435, \u041f\u0440\u043e IT"},{"@type":"BreadcrumbList","@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/otus.ru\/journal\/#listItem","position":1,"name":"\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430","item":"https:\/\/otus.ru\/journal\/","nextItem":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#listItem"},{"@type":"ListItem","@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#listItem","position":2,"name":"\u0427\u0442\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0432 Python \u0432 2021 \u0433\u043e\u0434\u0443?","previousItem":"https:\/\/otus.ru\/journal\/#listItem"}]},{"@type":"Organization","@id":"https:\/\/otus.ru\/journal\/#organization","name":"\u041e\u0442\u0443\u0441 \u043e\u043d\u043b\u0430\u0439\u043d-\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435","url":"https:\/\/otus.ru\/journal\/","sameAs":["https:\/\/www.youtube.com\/channel\/UCetgtvy93o3i3CvyGXKFU3g"],"contactPoint":{"@type":"ContactPoint","telephone":"+74999389202","contactType":"Customer Support"}},{"@type":"Person","@id":"https:\/\/otus.ru\/journal\/author\/d-golovin\/#author","url":"https:\/\/otus.ru\/journal\/author\/d-golovin\/","name":"D. Golovin","image":{"@type":"ImageObject","@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/50a23d5429cb764281144301f26baf7e?s=96&d=mm&r=g","width":96,"height":96,"caption":"D. Golovin"}},{"@type":"WebPage","@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#webpage","url":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/","name":"\u0427\u0442\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0432 Python \u0432 2021 \u0433\u043e\u0434\u0443? OTUS","description":"\u041a\u0440\u0430\u0442\u043a\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f Python Python \u0431\u044b\u043b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u043e\u043a\u043e\u043b\u043e \u0442\u0440\u0438\u0434\u0446\u0430\u0442\u0438 \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434, \u043f\u0435\u0440\u0432\u0430\u044f \u0435\u0433\u043e \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0432\u044b\u0448\u043b\u0430 \u0432 1991 \u0433\u043e\u0434\u0443 \u0438 \u0438\u043c\u0435\u043b\u0430 \u043d\u043e\u043c\u0435\u0440 0.9. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0433\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u044f\u0437\u044b\u043a \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u043b\u0441\u044f, \u0438 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0432 2000-\u0445 \u0433\u043e\u0434\u0430\u0445, \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043c\u0430\u0436\u043e\u0440\u043d\u043e\u0439 \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. \u041e\u0434\u043d\u0430\u043a\u043e \u0443\u0436\u0435 \u0442\u043e\u0433\u0434\u0430 \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0432 \u044f\u0437\u044b\u043a\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b","inLanguage":"ru-RU","isPartOf":{"@id":"https:\/\/otus.ru\/journal\/#website"},"breadcrumb":{"@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#breadcrumblist"},"author":{"@id":"https:\/\/otus.ru\/journal\/author\/d-golovin\/#author"},"creator":{"@id":"https:\/\/otus.ru\/journal\/author\/d-golovin\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/otus.ru\/journal\/wp-content\/uploads\/2021\/06\/oj-1080x720-kopiya-3.png","@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#mainImage","width":1080,"height":720},"primaryImageOfPage":{"@id":"https:\/\/otus.ru\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/#mainImage"},"datePublished":"2021-06-28T15:21:00+00:00","dateModified":"2021-06-28T15:21:01+00:00"},{"@type":"WebSite","@id":"https:\/\/otus.ru\/journal\/#website","url":"https:\/\/otus.ru\/journal\/","name":"OTUS JOURNAL","description":"Blog about IT","inLanguage":"ru-RU","publisher":{"@id":"https:\/\/otus.ru\/journal\/#organization"}}]}
</script>
<!-- All in One SEO -->
<link rel='dns-prefetch' href='//otus.ru' />
<link rel='dns-prefetch' href='//fonts.googleapis.com' />
<link rel='stylesheet' id='wp-block-library-css' href='https://otus.ru/journal/wp-includes/css/dist/block-library/style.min.css?ver=6.4.7' type='text/css' media='all' />
<style id='classic-theme-styles-inline-css' type='text/css'>
/*! This file is auto-generated */
.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none}
</style>
<style id='global-styles-inline-css' type='text/css'>
body{--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}
.wp-block-navigation a:where(:not(.wp-element-button)){color: inherit;}
:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}
:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}
.wp-block-pullquote{font-size: 1.5em;line-height: 1.6;}
</style>
<link rel='stylesheet' id='wbcr-comments-plus-url-span-css' href='https://otus.ru/journal/wp-content/plugins/clearfy/components/comments-plus/assets/css/url-span.css?ver=2.2.0' type='text/css' media='all' />
<link rel='stylesheet' id='wpel-style-css' href='https://otus.ru/journal/wp-content/plugins/wp-external-links/public/css/wpel.css?ver=2.59' type='text/css' media='all' />
<link rel='stylesheet' id='ez-toc-css' href='https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/css/screen.min.css?ver=2.0.61' type='text/css' media='all' />
<style id='ez-toc-inline-css' type='text/css'>
div#ez-toc-container .ez-toc-title {font-size: 120%;}div#ez-toc-container .ez-toc-title {font-weight: 500;}div#ez-toc-container ul li {font-size: 95%;}div#ez-toc-container nav ul ul li {font-size: 90%;}
.ez-toc-container-direction {direction: ltr;}.ez-toc-counter ul{counter-reset: item ;}.ez-toc-counter nav ul li a::before {content: counters(item, ".", decimal) ". ";display: inline-block;counter-increment: item;flex-grow: 0;flex-shrink: 0;margin-right: .2em; float: left; }.ez-toc-widget-direction {direction: ltr;}.ez-toc-widget-container ul{counter-reset: item ;}.ez-toc-widget-container nav ul li a::before {content: counters(item, ".", decimal) ". ";display: inline-block;counter-increment: item;flex-grow: 0;flex-shrink: 0;margin-right: .2em; float: left; }
</style>
<link rel='stylesheet' id='contentberg-fonts-css' href='https://fonts.googleapis.com/css?family=Roboto%3A400%2C500%2C700%7CPT+Serif%3A400%2C400i%2C600%7CIBM+Plex+Serif%3A500' type='text/css' media='all' />
<link rel='stylesheet' id='contentberg-core-css' href='https://otus.ru/journal/wp-content/themes/contentberg/style.css?ver=1.8.3' type='text/css' media='all' />
<link rel='stylesheet' id='contentberg-lightbox-css' href='https://otus.ru/journal/wp-content/themes/contentberg/css/lightbox.css?ver=1.8.3' type='text/css' media='all' />
<link rel='stylesheet' id='font-awesome-css' href='https://otus.ru/journal/wp-content/themes/contentberg/css/fontawesome/css/font-awesome.min.css?ver=1.8.3' type='text/css' media='all' />
<script type="text/javascript" id="breeze-prefetch-js-extra">
/* <![CDATA[ */
var breeze_prefetch = {"local_url":"https:\/\/otus.ru\/journal","ignore_remote_prefetch":"1","ignore_list":["\/wp-admin\/"]};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/breeze/assets/js/js-front-end/breeze-prefetch-links.min.js" id="breeze-prefetch-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery.min.js" id="jquery-core-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery-migrate.min.js" id="jquery-migrate-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/lazysizes.js" id="lazysizes-js"></script>
<link rel="https://api.w.org/" href="https://otus.ru/journal/wp-json/" /><link rel="alternate" type="application/json" href="https://otus.ru/journal/wp-json/wp/v2/posts/1502" /><link rel='shortlink' href='https://otus.ru/journal/?p=1502' />
<link rel="alternate" type="application/json+oembed" href="https://otus.ru/journal/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fotus.ru%2Fjournal%2Fchto-novogo-poyavilos-v-python-v-2021-godu%2F" />
<link rel="alternate" type="text/xml+oembed" href="https://otus.ru/journal/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fotus.ru%2Fjournal%2Fchto-novogo-poyavilos-v-python-v-2021-godu%2F&format=xml" />
<script>var Sphere_Plugin = {"ajaxurl":"https:\/\/otus.ru\/journal\/wp-admin\/admin-ajax.php"};</script><link rel="icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-32x32.png" sizes="32x32" />
<link rel="icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-192x192.png" sizes="192x192" />
<link rel="apple-touch-icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-180x180.png" />
<meta name="msapplication-TileImage" content="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-270x270.png" />
<style type="text/css" id="wp-custom-css">
#menu-item-10406 .wpel-icon {
display: none;
}
#menu-item-10407 .wpel-icon {
display: none;
}
.otus-login-site a .wpel-icon {
display: none;
}
.menu-menju-navykov-container a .wpel-icon {
display: none;
}
.otus-login-site a
{
background: #ffd709;
border-radius: 12px;
color: #0f0f10;
font-size: 14px;
font-weight: 700;
line-height: 20px;
display: block;
text-align: center;
padding: 8px 25px;
}
.main-footer.dark {
background: linear-gradient(90deg, #a64fc5, #4f54e6);
border-color: transparent;
}
.main-footer.bold .copyright {
color: #fff;
}
.main-footer.bold .to-top i {
color: #fff;
}
.main-footer.bold .back-to-top {
color: #fff;
}
.nav__scroll {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.scrollable-menu .menu {
display: flex;
}
.nav__scroll
{
background: linear-gradient(90deg, #a64fc5, #4f54e6);
}
.scrollable-menu .menu .menu-item {
flex: 0 0 auto;
padding: 15px 15px;
}
.scrollable-menu .menu .menu-item a {
color: #fff;
}
.nav__scroll::-webkit-scrollbar{background-color:#fff;height:5px;}
.nav__scroll::-webkit-scrollbar-thumb{background-color:#dcdcdc;}
.nav__scroll::-webkit-scrollbar-track{-webkit-border-radius:0;border-radius:0;background-color:#fff;}/
body {
min-width: 320px;
}
.banner-click img {
margin: 0 auto;
display: block;
}
.banner-click {
cursor: pointer;
}
.banner-footer-area {
margin-bottom: 20px;
}
.banner-left-area {
margin-top: 40px;
} </style>
<!--Start VDZ Yandex Metrika Plugin-->
<!-- Yandex.Metrika counter --><script type="text/javascript" >(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");ym(34531570, "init", {clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true, trackHash:true, ecommerce:"dataLayer"});</script>
<noscript><div><img src="https://mc.yandex.ru/watch/34531570" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter --><!--START ADD EVENTS FROM CF7--><script type='text/javascript'>document.addEventListener( 'wpcf7submit', function( event ) {
//event.detail.contactFormId;
if(ym){
//console.log(event.detail);
ym(34531570, 'reachGoal', 'VDZ_SEND_CONTACT_FORM_7');
ym(34531570, 'params', {
page_url: window.location.href,
status: event.detail.status,
locale: event.detail.contactFormLocale,
form_id: event.detail.contactFormId,
});
}
}, false );
</script><!--END ADD EVENTS FROM CF7-->
<!--End VDZ Yandex Metrika Plugin-->
</head>
<body class="post-template-default single single-post postid-1502 single-format-standard right-sidebar lazy-normal has-lb">
<div class="main-wrap">
<header id="main-head" class="main-head head-nav-below has-search-modal simple simple-boxed">
<div class="inner inner-head" data-sticky-bar="0">
<div class="wrap cf wrap-head">
<div class="left-contain">
<span class="mobile-nav"><i class="fa fa-bars"></i></span>
<div class="title">
<a href="https://otus.ru/journal/" title="OTUS JOURNAL" rel="home" data-wpel-link="internal">
<span class="text-logo"><img src="/journal/wp-content/themes/contentberg/img/logo_site.svg" alt="OTUS JOURNAL"></span>
</a>
</div>
</div>
<div class="navigation-wrap inline">
<nav class="navigation inline simple light" data-sticky-bar="0">
<div class="menu-rubriki-container"><ul id="menu-rubriki" class="menu"><li id="menu-item-109" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-cat-1 menu-item-109"><a href="https://otus.ru/journal/category/pro-it/" data-wpel-link="internal"><span>Про IT</span></a></li>
<li id="menu-item-113" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-cat-4 menu-item-113"><a href="https://otus.ru/journal/category/polza/" data-wpel-link="internal"><span>Полезное</span></a></li>
<li id="menu-item-114" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-cat-3 menu-item-114"><a href="https://otus.ru/journal/category/lifestyle/" data-wpel-link="internal"><span>Лайфстайл</span></a></li>
<li id="menu-item-10406" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10406"><a href="https://otus.ru/catalog/courses" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right"><span>Обучение</span><span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10407" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10407"><a href="https://otus.ru/about" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right"><span>Информация</span><span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </nav>
</div>
<div class="actions">
<div class="otus-login-site">
<a href="https://otus.ru/login/" target="_blank" data-wpel-link="external" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Войти<span class="wpel-icon wpel-image wpel-icon-6"></span></a>
</div>
<a href="#" title="Search" class="search-link"><i class="fa fa-search"></i></a>
</div>
</div>
</div>
</header> <!-- .main-head -->
<div class="nav nav_disable nav_colored nav_transparent course-categories__nav nav__scroll ">
<div class="container wrap">
<div class="links inline simple light scrollable-menu">
<div class="menu-menju-navykov-container"><ul id="menu-menju-navykov" class="menu"><li id="menu-item-10413" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10413"><a href="https://otus.ru/categories/programming/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Программирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10414" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10414"><a href="https://otus.ru/categories/architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Архитектура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10415" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10415"><a href="https://otus.ru/categories/operations/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Инфраструктура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10416" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10416"><a href="https://otus.ru/categories/information-security-courses/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Безопасность<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10417" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10417"><a href="https://otus.ru/categories/data-science/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Data Science<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10418" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10418"><a href="https://otus.ru/categories/gamedev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">GameDev<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10419" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10419"><a href="https://otus.ru/categories/marketing-business/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Управление<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10420" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10420"><a href="https://otus.ru/categories/analytics/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Аналитика и анализ<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10421" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10421"><a href="https://otus.ru/categories/testing/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Тестирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </div>
</div>
</div>
<div class="main wrap">
<div class="ts-row cf">
<div class="col-8 main-content cf">
<article id="post-1502" class="the-post post-1502 post type-post status-publish format-standard has-post-thumbnail category-polza category-pro-it">
<header class="post-header the-post-header cf">
<div class="post-meta the-post-meta">
<span class="post-cat">
<a href="https://otus.ru/journal/category/polza/" class="category" data-wpel-link="internal">Полезное</a>
</span>
<h1 class="post-title">
Что нового появилось в Python в 2021 году?
</h1>
<a href="https://otus.ru/journal/chto-novogo-poyavilos-v-python-v-2021-godu/" class="date-link" data-wpel-link="internal"><time class="post-date">28 июня, 2021</time></a>
</div>
<div class="featured">
<a href="https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-kopiya-3.png" class="image-link" data-wpel-link="internal"><img width="770" height="515" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20770%20515%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-contentberg-main size-contentberg-main lazyload wp-post-image" alt="Что нового появилось в Python в 2021 году?" title="Что нового появилось в Python в 2021 году?" decoding="async" fetchpriority="high" data-srcset="https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-kopiya-3-770x515.png 770w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-kopiya-3-300x200.png 300w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-kopiya-3-1024x683.png 1024w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-kopiya-3-150x100.png 150w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-kopiya-3-270x180.png 270w" data-src="https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-kopiya-3-770x515.png" data-sizes="(max-width: 770px) 100vw, 770px" /> </a>
</div>
</header><!-- .post-header -->
<div class="post-content description cf entry-content content-normal">
<div id="ez-toc-container" class="ez-toc-v2_0_61 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction">
<div class="ez-toc-title-container">
<p class="ez-toc-title " >Содержание</p>
<span class="ez-toc-title-toggle"><a href="#" class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" aria-label="Toggle Table of Content"><span class="ez-toc-js-icon-con"><span class=""><span class="eztoc-hide" style="display:none;">Toggle</span><span class="ez-toc-icon-toggle-span"><svg style="fill: #999;color:#999" xmlns="http://www.w3.org/2000/svg" class="list-377408" width="20px" height="20px" viewBox="0 0 24 24" fill="none"><path d="M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z" fill="currentColor"></path></svg><svg style="fill: #999;color:#999" class="arrow-unsorted-368013" xmlns="http://www.w3.org/2000/svg" width="10px" height="10px" viewBox="0 0 24 24" version="1.2" baseProfile="tiny"><path d="M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z"/></svg></span></span></span></a></span></div>
<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class="ez-toc-link ez-toc-heading-1" href="#%D0%9A%D1%80%D0%B0%D1%82%D0%BA%D0%B0%D1%8F_%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D1%8F_Python" title="Краткая история Python">Краткая история Python</a></li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class="ez-toc-link ez-toc-heading-2" href="#Whats_new_in_Python_39" title="What’s new in Python 3.9?">What’s new in Python 3.9?</a><ul class='ez-toc-list-level-2' ><li class='ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-3" href="#%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0_%D1%81%D0%BE_%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8F%D0%BC%D0%B8" title="Работа со словарями">Работа со словарями</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-4" href="#%D0%98%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B5_%D1%81_%D0%B4%D0%B5%D0%BA%D0%BE%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%B0%D0%BC%D0%B8" title="Изменения в работе с декораторами">Изменения в работе с декораторами</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-5" href="#%D0%98%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%81%D0%B5_%D1%82%D0%B8%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F" title="Изменения в синтаксисе типирования">Изменения в синтаксисе типирования</a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-6" href="#%D0%94%D0%B6%D0%B5%D0%BD%D0%B5%D1%80%D0%B8%D0%BA%D0%B8" title="Дженерики">Дженерики</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-7" href="#%D0%A0%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2%D0%BE%D0%B7%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D0%B5%D0%B9_%D0%B0%D0%BD%D0%BD%D0%BE%D1%82%D0%B0%D1%86%D0%B8%D0%B9" title="Расширение возможностей аннотаций">Расширение возможностей аннотаций</a></li></ul></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-8" href="#%D0%98%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D1%8F%D0%B7%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5_%D1%81_%D1%87%D0%B0%D1%81%D0%BE%D0%B2%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BE%D1%8F%D1%81%D0%B0%D0%BC%D0%B8" title="Изменения связанные с часовыми поясами">Изменения связанные с часовыми поясами</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-9" href="#%D0%9D%D0%BE%D0%B2%D1%8B%D0%B5_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B_%D1%81%D0%BE_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B0%D0%BC" title="Новые методы работы со строкам">Новые методы работы со строкам</a></li></ul></li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class="ez-toc-link ez-toc-heading-10" href="#Python_310" title="Python 3.10">Python 3.10</a><ul class='ez-toc-list-level-2' ><li class='ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-11" href="#Pattern_Matching" title="Pattern Matching">Pattern Matching</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-12" href="#%D0%91%D0%BE%D0%BB%D0%B5%D0%B5_%D1%83%D0%B4%D0%BE%D0%B1%D0%BD%D0%BE%D0%B5_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_Union_%D0%B4%D0%BB%D1%8F_%D1%82%D0%B8%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F" title="Более удобное использование Union для типирования:">Более удобное использование Union для типирования:</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-13" href="#%D0%9A%D0%BE%D0%BD%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%BD%D1%8B%D0%B5_%D0%BC%D0%B5%D0%BD%D0%B5%D0%B4%D0%B6%D0%B5%D1%80%D1%8B" title="Контекстные менеджеры">Контекстные менеджеры</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-14" href="#%D0%91%D0%BE%D0%BB%D0%B5%D0%B5_%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B5_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BE%D0%B1_%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0%D1%85" title="Более информативные сообщения об ошибках">Более информативные сообщения об ошибках</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-15" href="#%D0%9E%D1%81%D1%82%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5" title="Остальное">Остальное</a></li></ul></li></ul></nav></div>
<h1 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9A%D1%80%D0%B0%D1%82%D0%BA%D0%B0%D1%8F_%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D1%8F_Python"></span>Краткая история Python<span class="ez-toc-section-end"></span></h1>
<p>Python был разработан около тридцати лет назад, первая его официальная версия вышла в 1991 году и имела номер 0.9. После этого довольно долгое время язык развивался, и популярность он получил в 2000-х годах, во время мажорной второй версии. Однако уже тогда было понятно, что в языке необходимы изменения, которые будут обратно несовместимы с текущими версиями, такие как например, изменения в поведении юникодных строк. Однако вторая версия Python была уже очень популярна к этому моменту, поэтому третья работа над третьей версией велась одновременно с работой над 2.7. Довольно долго у core-разработчиков Python не было определенной стратегии, поэтому до версии 3.4 изменения были довольно хаотичны.</p>
<figure class="wp-block-image"><img decoding="async" src="https://github.com/tomasmor42/new-in-python/raw/45a764a6bc8ffa8c6ed54d1852d0f2775c973bc1/python_versions.png" alt="python_versions"/></figure>
<p>С 2019 года Python адаптирует годичные релизные циклы. Это изменение было представлено в <a href="https://www.python.org/dev/peps/pep-0602/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">PEP-602<span class="wpel-icon wpel-image wpel-icon-6"></span></a> Что это значит для пользоватеоей Python?</p>
<ul><li>новая минорная (3.X.0) версия выходит каждый год</li><li>фаза активной разработки версии 3.X+1.0 начинается в тот момент, когда в релих отправляется 3.X.beta и продолжается 12 месяцев</li><li>каждая минорная версия активно поддерживается в течении полутора лет</li><li>каждая минорная версия получает обновления безопасности в течении трех с половиной лет Пример расписания релизов для версии 3.9 можно посмотреть на рисунке:</li></ul>
<figure class="wp-block-image"><img decoding="async" src="https://github.com/tomasmor42/new-in-python/raw/45a764a6bc8ffa8c6ed54d1852d0f2775c973bc1/pep-0602-example-release-calendar_bpiqwz0.png" alt="release_calendar"/></figure>
<h1 class="wp-block-heading"><span class="ez-toc-section" id="Whats_new_in_Python_39"></span>What’s new in Python 3.9?<span class="ez-toc-section-end"></span></h1>
<p>Релиз Python 3.9 произошел 2020-10-05. Рассмотрим что есть нового в этой версии.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0_%D1%81%D0%BE_%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8F%D0%BC%D0%B8"></span>Работа со словарями<span class="ez-toc-section-end"></span></h2>
<p>Допустим, есть два словаря, которые мы зотим объединить.</p>
<p>В версиях до 3.9 можно было бы сделать таким образом:</p>
<p>In [9]:</p>
<pre class="wp-block-preformatted">pycon = {2017: "Portland", 2018: "Cleveland", 2019: "Cleveland", 2020: "online"}
europython = {2017: "Rimini", 2018: "Edinburgh", 2019: "Basel"}
{**pycon, **europython}
</pre>
<p>Out[9]:</p>
<pre class="wp-block-preformatted">{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}</pre>
<p>Синтаксис <code>**</code> разворачивает словарь, и когда они объединяются, более позднее значение затирается более новым. Аналогичные дейтсвия можно совершить, если использовать следующий синтаксис:</p>
<p>In [7]:</p>
<pre class="wp-block-preformatted">merged_dict = pycon.copy()
<strong>for</strong> key, value <strong>in</strong> europython.items():
merged_dict[key] = value
merged_dict</pre>
<p>Out[7]:</p>
<pre class="wp-block-preformatted">{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}</pre>
<p>Или таким образом:</p>
<p>In [8]:</p>
<pre class="wp-block-preformatted">pycon.update(europython)
pycon</pre>
<p>Out[8]:</p>
<pre class="wp-block-preformatted">{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}</pre>
<p>Этот способ пойдойдет в случае если нужно изменить первоначальный словарь.</p>
<p>In [14]:</p>
<pre class="wp-block-preformatted">merged_dict = pycon.copy().update(europython)</pre>
<p>Out[14]:</p>
<pre class="wp-block-preformatted">{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}</pre>
<p>In [ ]:</p>
<pre class="wp-block-preformatted">Однако если нужно сохранить эти данные в новом словаре, этим способом воспользоваться нельзя, в последнем примере</pre>
<p>In [17]:</p>
<pre class="wp-block-preformatted">merged_dict <strong>is</strong> <strong>None</strong></pre>
<p>Out[17]:</p>
<pre class="wp-block-preformatted">True</pre>
<p>В библиотеке collections есть объект ChainMap, который тоже обхединяет словари, но его результатом будет объект ChainMap, а не словарь. Он состоит из нескольких словарей, следующих друг за другом. Если взять значение по ключу, то вернется то значение, которое встречается раньше. То есть, в этом примере для ключа 2019, вернется значение Cleveland</p>
<p>In [28]:</p>
<pre class="wp-block-preformatted"><strong>from</strong> <strong>collections</strong> <strong>import</strong> ChainMap
merged_dict = ChainMap(pycon, europython)
merged_dict</pre>
<p>Out[28]:</p>
<pre class="wp-block-preformatted">ChainMap({2017: 'Amsterdam', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}, {2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel'})</pre>
<p>В Python 3.8 был представлен walrus-оператор. С его помощью можно решить проблему примера с update и скопировать словарь в новую переменную:In [11]:</p>
<pre class="wp-block-preformatted">(merged_dict := pycon.copy()).update(europython)
merged_dict</pre>
<p>Out[11]:</p>
<pre class="wp-block-preformatted">{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}</pre>
<p>В Python 3.9 в <a href="https://www.python.org/dev/peps/pep-0614/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">PEP-0614<span class="wpel-icon wpel-image wpel-icon-6"></span></a> добавлен синтаксис | (читается как pipe), который объединяет словари аналогично первому примеру:</p>
<p>In [13]:</p>
<pre class="wp-block-preformatted">pycon | europython</pre>
<p>Out[13]:</p>
<pre class="wp-block-preformatted">{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}</pre>
<p>При этом первоначальный словарь не меняется:</p>
<p>In [14]:</p>
<pre class="wp-block-preformatted">pycon</pre>
<p>Out[14]:</p>
<pre class="wp-block-preformatted">{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}</pre>
<p>Если все-таки нужно обновить первоначальный словарь, можно воспользоваться синтаксисом |= (работает по аналогии с +=): a |= b a = a|bIn [16]:</p>
<pre class="wp-block-preformatted">pycon |= europython
pycon</pre>
<p>Out[16]:</p>
<pre class="wp-block-preformatted">{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}</pre>
<p>Важно помнить, что поскольку более поздние значения перезаписывают более ранние значения, эта операция может быть не коммуникативна.</p>
<p>In [23]:</p>
<pre class="wp-block-preformatted">print(europython | pycon)
print(pycon | europython)</pre>
<pre class="wp-block-preformatted">{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}</pre>
<p>Синтаксис | работает только непосредственно со словарями, тогда как синтаксис ** работает и с orderedict и с другими подобными словарям объектами.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%98%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B5_%D1%81_%D0%B4%D0%B5%D0%BA%D0%BE%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%B0%D0%BC%D0%B8"></span>Изменения в работе с декораторами<span class="ez-toc-section-end"></span></h2>
<p>До версии 3.9 в качестве декораторов могли выступать функции или классы, но не такие объекты как списки или словари. Рассмотрим пример, в котором это будет удобно использовать. Допустим есть UI-приложение с кнопками, и нужно добавить какое-то сообщение по нажатию на каждую кнопку. Было бы удобно это сделать с помощью декоратора, но что делать, если для каждой кнопки нужно печатать различные сообщения. Это можно сделать следующим образом:In [ ]:</p>
<pre class="wp-block-preformatted">buttons = [QPushButton(f'Button <strong>{</strong>i<strong>}</strong>') <strong>for</strong> i <strong>in</strong> range(10)]
button_0 = buttons[0]
button_1 = buttons[1]
@button_0.clicked.connect
<strong>def</strong> say_hello():
message.setText("Hello, World!")
@button_1.clicked.connect
<strong>def</strong> say_goodbye():
message.setText("Goodbye, World!")</pre>
<p>Создаем list comprehension из функций, явно присваем объектам значения элементов списка, и их можно использовать в качестве декораторов. Это будет работать, однако не будет эффективно, если объектов из которых будут созданы декораторы, будет достаточно много.</p>
<p>Это не единственный способ, но другие будут довольно неоднозначными. Рассмотрим два из них. В первом случае создадим функцию, которая будет возвращать необходимую для декоратора функцию:In [ ]:</p>
<pre class="wp-block-preformatted"><strong>def</strong> _(x):
<strong>return</strong> x
@_(buttons[0].clicked.connect)
<strong>def</strong> say_hello():
...</pre>
<p>Использование <code>eval</code>:In [ ]:</p>
<pre class="wp-block-preformatted">@eval("buttons[1].clicked.connect")
<strong>def</strong> say_bye():
...</pre>
<p>В Python 3.9 стало возможно создавать декораторы из любых объектов, например из элементов списков и словарей. Можно рассмотреть синтаксис, который реализует тот же самый пример:</p>
<p>In [ ]:</p>
<pre class="wp-block-preformatted">@buttons[0].clicked.connect
<strong>def</strong> say_hello():
message.setText("Hello, World!")
@buttons[1].clicked.connect
<strong>def</strong> say_goodbye():
message.setText("Goodbye, World!")</pre>
<p>Похожим образом будет выглядеть синтаксис для значений словаря:</p>
<p>In [ ]:</p>
<pre class="wp-block-preformatted">buttons = {'hello': QPushButton('Hello!'), 'goodbye': QPushButton('Goodbye!')}
@buttons['hello'].clicked.connect
<strong>def</strong> say_hello():
message.setText("Hello, World!")
@buttons['goodbye'].clicked.connect
<strong>def</strong> say_goodbye():
message.setText("Goodbye, World!")</pre>
<p>Этот функционал, несмотря на то, что не приносит новых возможностей, позволяет писать более чистый код и избегать рискованных решений вроде использования <code>eval</code>.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%98%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%81%D0%B5_%D1%82%D0%B8%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F"></span>Изменения в синтаксисе типирования<span class="ez-toc-section-end"></span></h2>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="%D0%94%D0%B6%D0%B5%D0%BD%D0%B5%D1%80%D0%B8%D0%BA%D0%B8"></span>Дженерики<span class="ez-toc-section-end"></span></h3>
<p>Дженерики это типы, которые могут быть параметризованы, обычно являются контейнерами, например dict. Параметризованные дженерики это типы, для которых указан внутренний тип, например dict[str, int]</p>
<p>Начиная с Python 3.7 стало можно указывать тип объекта, конкретизируя тип внутренних элементов контейнеры. Но для этого нужно было импортировать таки типы как <code>List</code> из модуля <code>typing</code>:</p>
<p>In [ ]:</p>
<pre class="wp-block-preformatted"><strong>from</strong> <strong>typing</strong> <strong>import</strong> List, Dict
<strong>def</strong> find(haystack: Dict[str, List[int]]) -> int:
<em>#def find(haystack: dict) -> int:</em>
...</pre>
<p>Можно было не конкретизировать тип внутренних значений, для этого не нужно было импортировать дополинтельные типы и можно было использовать стандартные типы dict и list. Благодаря этому нововведению, внешние библиотеки такие как Mypy стали распознавать дженерики.</p>
<p>Также, в версии 3.9 стало можно пользоваться аннотациями без явного их импорта из модуля <code>__future__</code></p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="%D0%A0%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2%D0%BE%D0%B7%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D0%B5%D0%B9_%D0%B0%D0%BD%D0%BD%D0%BE%D1%82%D0%B0%D1%86%D0%B8%D0%B9"></span>Расширение возможностей аннотаций<span class="ez-toc-section-end"></span></h3>
<p>Аннотации были доступны для использования и в более ранних версиях Python, однако их функция была скорее информационной, использовались они в первую очередь для документации. Синтаксис использования аннотаций до Python 3.9 выглядел таким образом:</p>
<p>In [24]:</p>
<pre class="wp-block-preformatted"><strong>def</strong> speed(distance: "feet", time: "seconds") -> "miles per hour":
fps2mph = 3600 / 5280
<strong>return</strong> distance / time * fps2mph</pre>
<p>В Python 3.9 появился новый объект типа Annotated, который принимает на вход два аргумента, первый это реальный тип, которым должен обладать аннотриуемый объект, а второй это название для целей документации:</p>
<p>In [ ]:</p>
<pre class="wp-block-preformatted"><strong>from</strong> <strong>typing</strong> <strong>import</strong> Annotated
<strong>def</strong> speed(
distance: Annotated[float, "feet"], time: Annotated[float, "seconds"]) -> Annotated[float, "miles per hour"]:
fps2mph = 3600 / 5280
<strong>return</strong> distance / time * fps2mph</pre>
<p>Когда происходит проверка аннотаций, проверяется только первый аргумент, в котором находится «реальный» тип объекта, а второй использовуется как и в предыдущих версиях:</p>
<p>In [25]:</p>
<pre class="wp-block-preformatted">speed.__annotations__</pre>
<p>Out[25]:</p>
<pre class="wp-block-preformatted">{'distance': 'feet', 'time': 'seconds', 'return': 'miles per hour'}</pre>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%98%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%B2%D1%8F%D0%B7%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5_%D1%81_%D1%87%D0%B0%D1%81%D0%BE%D0%B2%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BE%D1%8F%D1%81%D0%B0%D0%BC%D0%B8"></span>Изменения связанные с часовыми поясами<span class="ez-toc-section-end"></span></h2>
<p>В предыдущих версиях Python, модуль <code>datetime</code> не содержал информации о часовых поясах, и рекомендованным способом работы с ними была библиотека <code>python-dateutil</code>.</p>
<p>Однако начиная с Python 3.9 появился модуль zoneinfo, который содержит информацию о часовых поясах и позволяет создавать объекты им соответствующие:</p>
<p>In [31]:</p>
<pre class="wp-block-preformatted"><strong>from</strong> <strong>datetime</strong> <strong>import</strong> datetime, timezone
<strong>from</strong> <strong>zoneinfo</strong> <strong>import</strong> ZoneInfo
local_tz = ZoneInfo('Europe/Amsterdam')
datetime.now(tz=timezone.utc), datetime.now()</pre>
<p>Out[31]:</p>
<pre class="wp-block-preformatted">(datetime.datetime(2021, 5, 4, 15, 58, 36, 295472, tzinfo=datetime.timezone.utc),
datetime.datetime(2021, 5, 4, 17, 58, 36, 295477))</pre>
<p>В стандартной библиотеке не было информации ни о каких часовых поясах, кроме utc, и необходимо было использовать <code>pytz</code> чтобы создать объект, содержащий информацию о часовом поясе. Теперь это можно сделать без установки дополнительных библиотек:In [32]:</p>
<pre class="wp-block-preformatted"><strong>from</strong> <strong>zoneinfo</strong> <strong>import</strong> ZoneInfo
local_tz = ZoneInfo('Europe/Amsterdam')
datetime.now(tz=local_tz)</pre>
<p>Out[32]:</p>
<pre class="wp-block-preformatted">(datetime.datetime(2021, 5, 4, 17, 58, 37, 765947, tzinfo=zoneinfo.ZoneInfo(key='Europe/Amsterdam')),)</pre>
<p>In [ ]:</p>
<pre class="wp-block-preformatted">Всего часовых поясов больше чем можно было бы предположить, и многие из них представлены в модуле `zoneinfo`</pre>
<p>In [33]:</p>
<pre class="wp-block-preformatted"><strong>import</strong> <strong>zoneinfo</strong>
tzs = zoneinfo.available_timezones()
len(tzs)</pre>
<p>Out[33]:</p>
<pre class="wp-block-preformatted">594</pre>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9D%D0%BE%D0%B2%D1%8B%D0%B5_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B_%D1%81%D0%BE_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B0%D0%BC"></span>Новые методы работы со строкам<span class="ez-toc-section-end"></span></h2>
<p>Иногда нужно убрать первые или последние несколько символов из строки. Есть метод <code>strip</code>, который обладает казалось бы похожим функционалом, но он может иногда давать <a href="https://stackoverflow.com/questions/4148974/removing-a-prefix-from-a-string" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">неожиданные<span class="wpel-icon wpel-image wpel-icon-6"></span></a> <a href="https://bugs.python.org/issue37114" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">результаты<span class="wpel-icon wpel-image wpel-icon-6"></span></a> Например в таком случае:</p>
<p>In [34]:</p>
<pre class="wp-block-preformatted">"ababbbbbbaaccc".lstrip("ab")</pre>
<p>Out[34]:</p>
<pre class="wp-block-preformatted">'ccc'</pre>
<p>В Python 3.9 были <a href="https://www.python.org/dev/peps/pep-0616/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">добавлены<span class="wpel-icon wpel-image wpel-icon-6"></span></a> функции <code>removeprefix</code>, <code>removesuffix</code>, которые выполняют то, что от них ожидается: удаляют первые или последние несколько символов строки.In [35]:</p>
<pre class="wp-block-preformatted">"ababbbbbbaaccc".removeprefix("ab")</pre>
<p>Out[35]:</p>
<pre class="wp-block-preformatted">'abbbbbbaaccc'</pre>
<p>In [36]:</p>
<pre class="wp-block-preformatted">"ababbbbbbaaccc".removesuffix("c")</pre>
<p>Out[36]:</p>
<pre class="wp-block-preformatted">'ababbbbbbaacc'</pre>
<p>In [36]:</p>
<pre class="wp-block-preformatted">Если строка не содержит суффикс или префикс, строка не меняется, никаких исключений не появляется.</pre>
<p>In [37]:</p>
<pre class="wp-block-preformatted">"ababbbbbbaaccc".removesuffix("something else")</pre>
<p>Out[37]:</p>
<pre class="wp-block-preformatted">'ababbbbbbaaccc'</pre>
<p>Ссылки:</p>
<ul><li><a href="https://docs.python.org/3/whatsnew/3.9.html#summary-release-highlights" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://docs.python.org/3/whatsnew/3.9.html#summary-release-highlights<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li></ul>
<h1 class="wp-block-heading"><span class="ez-toc-section" id="Python_310"></span>Python 3.10<span class="ez-toc-section-end"></span></h1>
<p>Последняя версия Python 3.10 это <a href="https://www.python.org/downloads/release/python-3100b3/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">0b3<span class="wpel-icon wpel-image wpel-icon-6"></span></a>, которая вышла 17 июня 2021 года. Согласно расписанию релизов, полноценный релиз появится примерно в октябре 2021. Пока официального релиза нет, версия не доступна в пакетных менеджерах (таких как brew). Соответственно, чтобы ее установить, билд нужно скачать вручную с www.python.org и уствноваить на своей машине. Рассмотрим изменения, доступные в этой Python 3.9.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="Pattern_Matching"></span>Pattern Matching<span class="ez-toc-section-end"></span></h2>
<p>В более ранних версиях Python если нужно описать различное поведение, в зависимости от того, какой объект используется, скорее всего будет использоваться условный оператор:In [ ]:</p>
<pre class="wp-block-preformatted"><strong>if</strong> isinstance(x, tuple) <strong>and</strong> len(x) == 2:
host, port = x
mode = "http"
<strong>elif</strong> isinstance(x, tuple) <strong>and</strong> len(x) == 3:
host, port, mode = x</pre>
<p>Однако в Python 3.10 вместе с <a href="https://www.python.org/dev/peps/pep-0635/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">PEP-0635<span class="wpel-icon wpel-image wpel-icon-6"></span></a> будет добавлен новый оператор match, который может использоваться с case:In [ ]:</p>
<pre class="wp-block-preformatted">match x:
case host, port:
mode = "http"
case host, port, mode:
<strong>pass</strong>
cass Class1:
...
case host == 'localhost'
...</pre>
<p>Также с его помощью будет удобно реализовывать, например, обработку ошибок:In [ ]:</p>
<pre class="wp-block-preformatted"><strong>def</strong> http_error(status):
match status:
case 400:
<strong>return</strong> "Bad request"
case 404:
<strong>return</strong> "Not found"
case 418:
<strong>return</strong> "I'm a teapot"
case _:
<strong>return</strong> "Something's wrong with the Internet"</pre>
<p>Это одно из самых «громких» нововведений в последних версиях Python и возможно самое ожидаемое коммьюнити.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%91%D0%BE%D0%BB%D0%B5%D0%B5_%D1%83%D0%B4%D0%BE%D0%B1%D0%BD%D0%BE%D0%B5_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_Union_%D0%B4%D0%BB%D1%8F_%D1%82%D0%B8%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F"></span>Более удобное использование Union для типирования:<span class="ez-toc-section-end"></span></h2>
<p>Если раньше чтобы указать, что аргумент функции может быть одним из нескольких типов, необходимо было использовать Union, импортируемый из пакета typing:In [ ]:</p>
<pre class="wp-block-preformatted"><strong>from</strong> <strong>typing</strong> <strong>import</strong> Union
<strong>def</strong> square(number: Union[int, float]) -> Union[int, float]:
<strong>return</strong> number ** 2</pre>
<p>То начиная с Python 3.10 можно будет заменить его оператором pipe | и, соответственно, избавиться от импорта:In [ ]:</p>
<pre class="wp-block-preformatted"><strong>def</strong> square(number: int | float) -> int | float:
<strong>return</strong> number ** 2</pre>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9A%D0%BE%D0%BD%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%BD%D1%8B%D0%B5_%D0%BC%D0%B5%D0%BD%D0%B5%D0%B4%D0%B6%D0%B5%D1%80%D1%8B"></span>Контекстные менеджеры<span class="ez-toc-section-end"></span></h2>
<p>Синтаксис работы с контекстными менеджерами упростится, теперь несколько контекстных менеджеров можно объединять в одном <code>with</code>, а так же не обязательно присваивать им локальные имена:In [ ]:</p>
<pre class="wp-block-preformatted"><strong>with</strong> (
CtxManager1(),
CtxManager2()
):
...
<strong>with</strong> (CtxManager1() <strong>as</strong> example,
CtxManager2()):
...
<strong>with</strong> (
CtxManager1() <strong>as</strong> example1,
CtxManager2() <strong>as</strong> example2
):
...</pre>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%91%D0%BE%D0%BB%D0%B5%D0%B5_%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B5_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BE%D0%B1_%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0%D1%85"></span>Более информативные сообщения об ошибках<span class="ez-toc-section-end"></span></h2>
<p>Наверняка многие из читателей сталкивались с тем, что сообщение об ошибке слишком общее и само по себе не говорит о том, что нужно сделать чтобы ошибку исправить. В новой версиеи Python core-разработчики улучшили самые распространенные из них и теперь сообщения об ошибках будут намного более читабельными:In [ ]:</p>
<pre class="wp-block-preformatted">expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
^
<strong>SyntaxError</strong>: '{' was never closed</pre>
<p>In [ ]:</p>
<pre class="wp-block-preformatted">>>> <strong>if</strong> rocket.position > event_horizon
File "<stdin>", line 1
<strong>if</strong> rocket.position > event_horizon
^
<strong>SyntaxError</strong>: expected ':'</pre>
<p>In [ ]:</p>
<pre class="wp-block-preformatted">>>> {x,y <strong>for</strong> x,y <strong>in</strong> range(100)}
File "<stdin>", line 1
{x,y <strong>for</strong> x,y <strong>in</strong> range(100)}
^
<strong>SyntaxError</strong>: did you forget parentheses around the comprehension target?</pre>
<p>In [ ]:</p>
<pre class="wp-block-preformatted"><strong>if</strong> rocket.position = event_horizon:
File "<stdin>", line 1
<strong>if</strong> rocket.position = event_horizon:
^
<strong>SyntaxError</strong>: cannot assign to attribute here. Maybe you meant '==' instead</pre>
<p>In [ ]:</p>
<pre class="wp-block-preformatted"><strong>def</strong> foo():
... <strong>if</strong> lel:
... x = 2
File "<stdin>", line 3
x = 2
^
<strong>IndentationError</strong>: expected an indented block after 'if' statement <strong>in</strong> line 2</pre>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9E%D1%81%D1%82%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5"></span>Остальное<span class="ez-toc-section-end"></span></h2>
<ul><li>Модуль distutils постепенно выыводится из употребления, чтобы быть полностью удаленным в Python 3.12. Это связано с тем, что его функции были полностью заменены такими модулями как setuptools и packaging.</li><li>Улучшение читабельности сообщений в модуле <a href="https://www.python.org/dev/peps/pep-0626/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">debugging<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li></ul>
<p>Это не все изменения которые попадут в Python 3.10, с полным списком можно ознакомиться посмотрев <a href="https://docs.python.org/3.10/whatsnew/changelog.html#changelog" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">список изменений<span class="wpel-icon wpel-image wpel-icon-6"></span></a>.</p>
<hr class="wp-block-separator"/>
<p>Прокачать Python можно на курсах:</p>
<ul><li><a href="https://otus.pw/7RoI/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Python Developer. Basic<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li><li><a href="https://otus.pw/9tLD/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Python Developer. Professional<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li><li><a href="https://otus.pw/Xd6U/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Web-разработчик на Python<span class="wpel-icon wpel-image wpel-icon-6"></span></a> </li></ul>
<p></p>
</div><!-- .post-content -->
<div class="the-post-foot cf">
<div class="tag-share cf">
<div class="post-share">
<div class="post-share-icons cf">
<span class="counters">
</span>
<a href="https://www.facebook.com/sharer.php?u=https%3A%2F%2Fotus.ru%2Fjournal%2Fchto-novogo-poyavilos-v-python-v-2021-godu%2F" class="link facebook wpel-icon-right" target="_blank" title="Share on Facebook" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-facebook"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fotus.ru%2Fjournal%2Fchto-novogo-poyavilos-v-python-v-2021-godu%2F&text=%D0%A7%D1%82%D0%BE%20%D0%BD%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE%20%D0%BF%D0%BE%D1%8F%D0%B2%D0%B8%D0%BB%D0%BE%D1%81%D1%8C%20%D0%B2%20Python%20%D0%B2%202021%20%D0%B3%D0%BE%D0%B4%D1%83%3F" class="link twitter wpel-icon-right" target="_blank" title="Share on Twitter" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-twitter"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fotus.ru%2Fjournal%2Fchto-novogo-poyavilos-v-python-v-2021-godu%2F" class="link linkedin wpel-icon-right" target="_blank" title="LinkedIn" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-linkedin"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fotus.ru%2Fjournal%2Fchto-novogo-poyavilos-v-python-v-2021-godu%2F&media=https%3A%2F%2Fotus.ru%2Fjournal%2Fwp-content%2Fuploads%2F2021%2F06%2Foj-1080x720-kopiya-3.png&description=%D0%A7%D1%82%D0%BE%20%D0%BD%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE%20%D0%BF%D0%BE%D1%8F%D0%B2%D0%B8%D0%BB%D0%BE%D1%81%D1%8C%20%D0%B2%20Python%20%D0%B2%202021%20%D0%B3%D0%BE%D0%B4%D1%83%3F" class="link pinterest wpel-icon-right" target="_blank" title="Pinterest" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-pinterest-p"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
</div>
</div>
</div>
</div>
<div class="post-nav">
<div class="post previous cf">
<a href="https://otus.ru/journal/prodolzhaem-uchitsya/" title="Prev Post" class="nav-icon" data-wpel-link="internal">
<i class="fa fa-angle-left"></i>
</a>
<span class="content">
<a href="https://otus.ru/journal/prodolzhaem-uchitsya/" class="image-link" rel="previous" data-wpel-link="internal">
<img width="150" height="100" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20150%20100%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-thumbnail size-thumbnail lazyload wp-post-image" alt="Новые мероприятия в OTUS" decoding="async" data-srcset="https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9-150x100.png 150w, https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9-300x200.png 300w, https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9-1024x683.png 1024w, https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9-768x512.png 768w, https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9-270x180.png 270w, https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9-770x515.png 770w, https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9-370x245.png 370w, https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9.png 1080w" data-src="https://otus.ru/journal/wp-content/uploads/2021/05/oj-1080x720-9-150x100.png" data-sizes="(max-width: 150px) 100vw, 150px" title="Новые мероприятия в OTUS" /> </a>
<div class="post-meta">
<span class="label">Prev Post</span>
<div class="post-meta post-meta-b">
<h2 class="post-title">
<a href="https://otus.ru/journal/prodolzhaem-uchitsya/" data-wpel-link="internal">Продолжаем учиться!</a>
</h2>
<div class="below">
<a href="https://otus.ru/journal/prodolzhaem-uchitsya/" class="meta-item date-link" data-wpel-link="internal"><time class="post-date" datetime="2021-06-28T07:36:56+00:00">28 июня, 2021</time></a>
<span class="meta-sep"></span>
<span class="meta-item read-time">1 Min Read</span>
</div>
</div> </div>
</span>
</div>
<div class="post next cf">
<a href="https://otus.ru/journal/kak-ispravit-oshibki-ms-sql-i-vosstanovit-bazu-dannyh/" title="Next Post" class="nav-icon" data-wpel-link="internal">
<i class="fa fa-angle-right"></i>
</a>
<span class="content">
<a href="https://otus.ru/journal/kak-ispravit-oshibki-ms-sql-i-vosstanovit-bazu-dannyh/" class="image-link" rel="next" data-wpel-link="internal">
<img width="150" height="100" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20150%20100%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-thumbnail size-thumbnail lazyload wp-post-image" alt="Как исправить ошибки MS SQL и восстановить базу данных" decoding="async" data-srcset="https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1-150x100.png 150w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1-300x200.png 300w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1-1024x683.png 1024w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1-768x512.png 768w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1-270x180.png 270w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1-770x515.png 770w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1-370x245.png 370w, https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1.png 1080w" data-src="https://otus.ru/journal/wp-content/uploads/2021/06/oj-1080x720-3-1-150x100.png" data-sizes="(max-width: 150px) 100vw, 150px" title="Как исправить ошибки MS SQL и восстановить базу данных" /> </a>
<div class="post-meta">
<span class="label">Next Post</span>
<div class="post-meta post-meta-b">
<h2 class="post-title">
<a href="https://otus.ru/journal/kak-ispravit-oshibki-ms-sql-i-vosstanovit-bazu-dannyh/" data-wpel-link="internal">Как исправить ошибки MS SQL и восстановить базу данных</a>
</h2>
<div class="below">
<a href="https://otus.ru/journal/kak-ispravit-oshibki-ms-sql-i-vosstanovit-bazu-dannyh/" class="meta-item date-link" data-wpel-link="internal"><time class="post-date" datetime="2021-06-28T17:47:29+00:00">28 июня, 2021</time></a>
<span class="meta-sep"></span>
<span class="meta-item read-time">9 Mins Read</span>
</div>
</div> </div>
</span>
</div>
</div>
<section class="related-posts grid-3">
<h4 class="section-head"><span class="title">Читать ещё</span></h4>
<div class="ts-row posts cf">
<article class="post col-4">
<a href="https://otus.ru/journal/proekt-tg-autoposter-na-nest-js/" title="Проект «TG Autoposter на Nest.JS»" class="image-link" data-wpel-link="internal">
</a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/proekt-tg-autoposter-na-nest-js/" class="post-link" data-wpel-link="internal">Проект «TG Autoposter на Nest.JS»</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-12-23T00:44:53+00:00">23 декабря, 2025</time>
</div>
</div>
</article >
<article class="post col-4">
<a href="https://otus.ru/journal/uroven-gotovnosti-cto-k-2026/" title="Уровень готовности CTO к 2026" class="image-link" data-wpel-link="internal">
<img width="270" height="180" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20270%20180%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="image lazyload wp-post-image" alt="Уровень готовности CTO к 2026" title="Уровень готовности CTO к 2026" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-270x180.jpg 270w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-770x515.jpg 770w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-370x245.jpg 370w" data-src="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-270x180.jpg" data-sizes="(max-width: 270px) 100vw, 270px" /> </a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/uroven-gotovnosti-cto-k-2026/" class="post-link" data-wpel-link="internal">Уровень готовности CTO к 2026</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-11-16T19:50:59+00:00">16 ноября, 2025</time>
</div>
</div>
</article >
<article class="post col-4">
<a href="https://otus.ru/journal/langtrainee-razrabotka-mvp-ai-platformy-dlya-personalizirovannogo-izucheniya-yazykov/" title="LangTrainee: разработка MVP AI-платформы для персонализированного изучения языков" class="image-link" data-wpel-link="internal">
</a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/langtrainee-razrabotka-mvp-ai-platformy-dlya-personalizirovannogo-izucheniya-yazykov/" class="post-link" data-wpel-link="internal">LangTrainee: разработка MVP AI-платформы для персонализированного изучения языков</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-11-12T04:39:47+00:00">12 ноября, 2025</time>
</div>
</div>
</article >
</div>
</section>
</article> <!-- .the-post -->
</div>
<aside class="col-4 sidebar">
<div class="inner">
<ul>
<li id="search-2" class="widget widget_search"><h5 class="widget-title"><span>Поиск по блогу</span></h5>
<form method="get" class="search-form" action="https://otus.ru/journal/">
<label>
<span class="screen-reader-text">Search for:</span>
<input type="search" class="search-field" placeholder="Введите запрос и нажмите Enter" value="" name="s" title="Search for:" />
</label>
<button type="submit" class="search-submit"><i class="fa fa-search"></i></button>
</form>
</li>
<li id="tag_cloud-5" class="widget widget_tag_cloud"><h5 class="widget-title"><span>Метки</span></h5><div class="tagcloud"><a href="https://otus.ru/journal/tag/android-2/" class="tag-cloud-link tag-link-74 tag-link-position-1" style="font-size: 12.472222222222pt;" aria-label="Android (34 элемента)" data-wpel-link="internal">Android</a>
<a href="https://otus.ru/journal/tag/c-3/" class="tag-cloud-link tag-link-91 tag-link-position-2" style="font-size: 10.916666666667pt;" aria-label="C (23 элемента)" data-wpel-link="internal">C</a>
<a href="https://otus.ru/journal/tag/c-2/" class="tag-cloud-link tag-link-81 tag-link-position-3" style="font-size: 12.666666666667pt;" aria-label="C# (35 элементов)" data-wpel-link="internal">C#</a>
<a href="https://otus.ru/journal/tag/c/" class="tag-cloud-link tag-link-20 tag-link-position-4" style="font-size: 12.472222222222pt;" aria-label="c++ (34 элемента)" data-wpel-link="internal">c++</a>
<a href="https://otus.ru/journal/tag/computer-science/" class="tag-cloud-link tag-link-209 tag-link-position-5" style="font-size: 15.972222222222pt;" aria-label="computer science (78 элементов)" data-wpel-link="internal">computer science</a>
<a href="https://otus.ru/journal/tag/css/" class="tag-cloud-link tag-link-288 tag-link-position-6" style="font-size: 8.6805555555556pt;" aria-label="CSS (13 элементов)" data-wpel-link="internal">CSS</a>
<a href="https://otus.ru/journal/tag/data-science/" class="tag-cloud-link tag-link-151 tag-link-position-7" style="font-size: 8pt;" aria-label="Data Science (11 элементов)" data-wpel-link="internal">Data Science</a>
<a href="https://otus.ru/journal/tag/devops/" class="tag-cloud-link tag-link-98 tag-link-position-8" style="font-size: 10.138888888889pt;" aria-label="devops (19 элементов)" data-wpel-link="internal">devops</a>
<a href="https://otus.ru/journal/tag/docker/" class="tag-cloud-link tag-link-143 tag-link-position-9" style="font-size: 8.2916666666667pt;" aria-label="Docker (12 элементов)" data-wpel-link="internal">Docker</a>
<a href="https://otus.ru/journal/tag/gamedev/" class="tag-cloud-link tag-link-25 tag-link-position-10" style="font-size: 11.694444444444pt;" aria-label="gamedev (28 элементов)" data-wpel-link="internal">gamedev</a>
<a href="https://otus.ru/journal/tag/hr/" class="tag-cloud-link tag-link-103 tag-link-position-11" style="font-size: 8pt;" aria-label="hr (11 элементов)" data-wpel-link="internal">hr</a>
<a href="https://otus.ru/journal/tag/html/" class="tag-cloud-link tag-link-217 tag-link-position-12" style="font-size: 11.208333333333pt;" aria-label="HTML (25 элементов)" data-wpel-link="internal">HTML</a>
<a href="https://otus.ru/journal/tag/ios/" class="tag-cloud-link tag-link-101 tag-link-position-13" style="font-size: 8.9722222222222pt;" aria-label="iOS (14 элементов)" data-wpel-link="internal">iOS</a>
<a href="https://otus.ru/journal/tag/it/" class="tag-cloud-link tag-link-50 tag-link-position-14" style="font-size: 10.527777777778pt;" aria-label="IT (21 элемент)" data-wpel-link="internal">IT</a>
<a href="https://otus.ru/journal/tag/java/" class="tag-cloud-link tag-link-75 tag-link-position-15" style="font-size: 15.680555555556pt;" aria-label="Java (73 элемента)" data-wpel-link="internal">Java</a>
<a href="https://otus.ru/journal/tag/javascript/" class="tag-cloud-link tag-link-83 tag-link-position-16" style="font-size: 14.319444444444pt;" aria-label="JavaScript (53 элемента)" data-wpel-link="internal">JavaScript</a>
<a href="https://otus.ru/journal/tag/linux/" class="tag-cloud-link tag-link-141 tag-link-position-17" style="font-size: 11.888888888889pt;" aria-label="Linux (29 элементов)" data-wpel-link="internal">Linux</a>
<a href="https://otus.ru/journal/tag/machine-learning/" class="tag-cloud-link tag-link-167 tag-link-position-18" style="font-size: 8.6805555555556pt;" aria-label="Machine Learning (13 элементов)" data-wpel-link="internal">Machine Learning</a>
<a href="https://otus.ru/journal/tag/otus-book/" class="tag-cloud-link tag-link-261 tag-link-position-19" style="font-size: 9.9444444444444pt;" aria-label="otus book (18 элементов)" data-wpel-link="internal">otus book</a>
<a href="https://otus.ru/journal/tag/php/" class="tag-cloud-link tag-link-45 tag-link-position-20" style="font-size: 10.527777777778pt;" aria-label="PHP (21 элемент)" data-wpel-link="internal">PHP</a>
<a href="https://otus.ru/journal/tag/python/" class="tag-cloud-link tag-link-27 tag-link-position-21" style="font-size: 16.944444444444pt;" aria-label="Python (99 элементов)" data-wpel-link="internal">Python</a>
<a href="https://otus.ru/journal/tag/qa/" class="tag-cloud-link tag-link-155 tag-link-position-22" style="font-size: 11.402777777778pt;" aria-label="qa (26 элементов)" data-wpel-link="internal">qa</a>
<a href="https://otus.ru/journal/tag/sql/" class="tag-cloud-link tag-link-38 tag-link-position-23" style="font-size: 12.861111111111pt;" aria-label="SQL (37 элементов)" data-wpel-link="internal">SQL</a>
<a href="https://otus.ru/journal/tag/team-lead/" class="tag-cloud-link tag-link-364 tag-link-position-24" style="font-size: 9.9444444444444pt;" aria-label="team lead (18 элементов)" data-wpel-link="internal">team lead</a>
<a href="https://otus.ru/journal/tag/unity/" class="tag-cloud-link tag-link-24 tag-link-position-25" style="font-size: 8pt;" aria-label="unity (11 элементов)" data-wpel-link="internal">unity</a>
<a href="https://otus.ru/journal/tag/algoritmy/" class="tag-cloud-link tag-link-30 tag-link-position-26" style="font-size: 9.9444444444444pt;" aria-label="Алгоритмы (18 элементов)" data-wpel-link="internal">Алгоритмы</a>
<a href="https://otus.ru/journal/tag/bazy-dannyh/" class="tag-cloud-link tag-link-40 tag-link-position-27" style="font-size: 10.138888888889pt;" aria-label="Базы данных (19 элементов)" data-wpel-link="internal">Базы данных</a>
<a href="https://otus.ru/journal/tag/matematika/" class="tag-cloud-link tag-link-44 tag-link-position-28" style="font-size: 10.916666666667pt;" aria-label="Математика (23 элемента)" data-wpel-link="internal">Математика</a>
<a href="https://otus.ru/journal/tag/arhitektura-po/" class="tag-cloud-link tag-link-10 tag-link-position-29" style="font-size: 9.4583333333333pt;" aria-label="архитектура ПО (16 элементов)" data-wpel-link="internal">архитектура ПО</a>
<a href="https://otus.ru/journal/tag/bazy-dannyh-2/" class="tag-cloud-link tag-link-251 tag-link-position-30" style="font-size: 10.138888888889pt;" aria-label="базы данных (19 элементов)" data-wpel-link="internal">базы данных</a>
<a href="https://otus.ru/journal/tag/vebinar/" class="tag-cloud-link tag-link-201 tag-link-position-31" style="font-size: 13.930555555556pt;" aria-label="вебинар (48 элементов)" data-wpel-link="internal">вебинар</a>
<a href="https://otus.ru/journal/tag/dajdzhest/" class="tag-cloud-link tag-link-308 tag-link-position-32" style="font-size: 10.722222222222pt;" aria-label="дайджест (22 элемента)" data-wpel-link="internal">дайджест</a>
<a href="https://otus.ru/journal/tag/zapis-vebinara/" class="tag-cloud-link tag-link-226 tag-link-position-33" style="font-size: 14.902777777778pt;" aria-label="запись вебинара (61 элемент)" data-wpel-link="internal">запись вебинара</a>
<a href="https://otus.ru/journal/tag/zapis-uroka/" class="tag-cloud-link tag-link-272 tag-link-position-34" style="font-size: 16.069444444444pt;" aria-label="запись урока (80 элементов)" data-wpel-link="internal">запись урока</a>
<a href="https://otus.ru/journal/tag/informacionnaya-bezopasnost/" class="tag-cloud-link tag-link-232 tag-link-position-35" style="font-size: 10.138888888889pt;" aria-label="информационная безопасность (19 элементов)" data-wpel-link="internal">информационная безопасность</a>
<a href="https://otus.ru/journal/tag/karera-v-it/" class="tag-cloud-link tag-link-292 tag-link-position-36" style="font-size: 9.9444444444444pt;" aria-label="карьера в IT (18 элементов)" data-wpel-link="internal">карьера в IT</a>
<a href="https://otus.ru/journal/tag/podborka/" class="tag-cloud-link tag-link-7 tag-link-position-37" style="font-size: 12.666666666667pt;" aria-label="подборка (35 элементов)" data-wpel-link="internal">подборка</a>
<a href="https://otus.ru/journal/tag/podborka-statej/" class="tag-cloud-link tag-link-219 tag-link-position-38" style="font-size: 15.777777777778pt;" aria-label="подборка статей (75 элементов)" data-wpel-link="internal">подборка статей</a>
<a href="https://otus.ru/journal/tag/programmirovanie/" class="tag-cloud-link tag-link-65 tag-link-position-39" style="font-size: 22pt;" aria-label="программирование (332 элемента)" data-wpel-link="internal">программирование</a>
<a href="https://otus.ru/journal/tag/proekt/" class="tag-cloud-link tag-link-321 tag-link-position-40" style="font-size: 11.888888888889pt;" aria-label="проект (29 элементов)" data-wpel-link="internal">проект</a>
<a href="https://otus.ru/journal/tag/proektnaya-rabota/" class="tag-cloud-link tag-link-310 tag-link-position-41" style="font-size: 11.597222222222pt;" aria-label="проектная работа (27 элементов)" data-wpel-link="internal">проектная работа</a>
<a href="https://otus.ru/journal/tag/seti/" class="tag-cloud-link tag-link-181 tag-link-position-42" style="font-size: 12.958333333333pt;" aria-label="сети (38 элементов)" data-wpel-link="internal">сети</a>
<a href="https://otus.ru/journal/tag/testirovanie/" class="tag-cloud-link tag-link-69 tag-link-position-43" style="font-size: 13.930555555556pt;" aria-label="тестирование (48 элементов)" data-wpel-link="internal">тестирование</a>
<a href="https://otus.ru/journal/tag/upravlenie-komandoj/" class="tag-cloud-link tag-link-63 tag-link-position-44" style="font-size: 11.694444444444pt;" aria-label="управление командой (28 элементов)" data-wpel-link="internal">управление командой</a>
<a href="https://otus.ru/journal/tag/habr-2/" class="tag-cloud-link tag-link-203 tag-link-position-45" style="font-size: 13.930555555556pt;" aria-label="хабр (48 элементов)" data-wpel-link="internal">хабр</a></div>
</li>
</ul>
</div>
</aside>
</div> <!-- .ts-row -->
</div> <!-- .main -->
<footer class="main-footer dark bold">
<section class="lower-footer cf">
<div class="wrap">
<div class="links">
<div class="menu-menju-navykov-container"><ul id="menu-menju-navykov-1" class="menu"><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10413"><a href="https://otus.ru/categories/programming/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Программирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10414"><a href="https://otus.ru/categories/architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Архитектура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10415"><a href="https://otus.ru/categories/operations/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Инфраструктура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10416"><a href="https://otus.ru/categories/information-security-courses/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Безопасность<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10417"><a href="https://otus.ru/categories/data-science/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Data Science<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10418"><a href="https://otus.ru/categories/gamedev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">GameDev<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10419"><a href="https://otus.ru/categories/marketing-business/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Управление<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10420"><a href="https://otus.ru/categories/analytics/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Аналитика и анализ<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10421"><a href="https://otus.ru/categories/testing/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Тестирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </div>
<p class="copyright"> © 2015-2026 OTUS </p>
<div class="to-top">
<a href="#" class="back-to-top"><i class="fa fa-angle-up"></i> Top</a>
</div>
</div>
</section>
</footer>
</div> <!-- .main-wrap -->
<div class="mobile-menu-container off-canvas" id="mobile-menu">
<a href="#" class="close"><i class="fa fa-times"></i></a>
<div class="logo">
</div>
<ul class="mobile-menu"></ul>
</div>
<div class="search-modal-wrap">
<div class="search-modal-box" role="dialog" aria-modal="true">
<form method="get" class="search-form" action="https://otus.ru/journal/">
<input type="search" class="search-field" name="s" placeholder="Search..." value="" required />
<button type="submit" class="search-submit visuallyhidden">Submit</button>
<p class="message">
Type above and press <em>Enter</em> to search. Press <em>Esc</em> to cancel. </p>
</form>
</div>
</div>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/clearfy/components/comments-plus/assets/js/url-span.js" id="wbcr-comments-plus-url-span-js"></script>
<script type="text/javascript" id="ez-toc-scroll-scriptjs-js-extra">
/* <![CDATA[ */
var eztoc_smooth_local = {"scroll_offset":"30"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/js/smooth_scroll.min.js" id="ez-toc-scroll-scriptjs-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/vendor/js-cookie/js.cookie.min.js" id="ez-toc-js-cookie-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/vendor/sticky-kit/jquery.sticky-kit.min.js" id="ez-toc-jquery-sticky-kit-js"></script>
<script type="text/javascript" id="ez-toc-js-js-extra">
/* <![CDATA[ */
var ezTOC = {"smooth_scroll":"1","visibility_hide_by_default":"","scroll_offset":"30","fallbackIcon":"<span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span>"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/js/front.min.js" id="ez-toc-js-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/custom-script.js" id="custom-script-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/magnific-popup.js" id="magnific-popup-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jquery.fitvids.js" id="jquery-fitvids-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/imagesloaded.min.js" id="imagesloaded-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/object-fit-images.js" id="object-fit-images-js"></script>
<script type="text/javascript" id="contentberg-theme-js-extra">
/* <![CDATA[ */
var Bunyad = {"custom_ajax_url":"\/journal\/chto-novogo-poyavilos-v-python-v-2021-godu\/"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/theme.js" id="contentberg-theme-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/theia-sticky-sidebar.js" id="theia-sticky-sidebar-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jquery.slick.js" id="jquery-slick-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jarallax.js" id="jarallax-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/masonry.min.js" id="masonry-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery.masonry.min.js" id="jquery-masonry-js"></script>
</body>
</html>
<!-- Cache served by breeze CACHE - Last modified: Tue, 10 Mar 2026 23:34:36 GMT -->