2 added
2 removed
Original
2026-01-01
Modified
2026-03-10
1
<ul><li><a>Краткая история Python</a></li>
1
<ul><li><a>Краткая история Python</a></li>
2
<li><a>What’s new in Python 3.9?</a><ul><li><a>Работа со словарями</a></li>
2
<li><a>What’s new in Python 3.9?</a><ul><li><a>Работа со словарями</a></li>
3
<li><a>Изменения в работе с декораторами</a></li>
3
<li><a>Изменения в работе с декораторами</a></li>
4
<li><a>Изменения в синтаксисе типирования</a><ul><li><a>Дженерики</a></li>
4
<li><a>Изменения в синтаксисе типирования</a><ul><li><a>Дженерики</a></li>
5
<li><a>Расширение возможностей аннотаций</a></li>
5
<li><a>Расширение возможностей аннотаций</a></li>
6
</ul></li>
6
</ul></li>
7
<li><a>Изменения связанные с часовыми поясами</a></li>
7
<li><a>Изменения связанные с часовыми поясами</a></li>
8
<li><a>Новые методы работы со строкам</a></li>
8
<li><a>Новые методы работы со строкам</a></li>
9
</ul></li>
9
</ul></li>
10
<li><a>Python 3.10</a><ul><li><a>Pattern Matching</a></li>
10
<li><a>Python 3.10</a><ul><li><a>Pattern Matching</a></li>
11
<li><a>Более удобное использование Union для типирования:</a></li>
11
<li><a>Более удобное использование Union для типирования:</a></li>
12
<li><a>Контекстные менеджеры</a></li>
12
<li><a>Контекстные менеджеры</a></li>
13
<li><a>Более информативные сообщения об ошибках</a></li>
13
<li><a>Более информативные сообщения об ошибках</a></li>
14
<li><a>Остальное</a></li>
14
<li><a>Остальное</a></li>
15
</ul></li>
15
</ul></li>
16
</ul><p>Python был разработан около тридцати лет назад, первая его официальная версия вышла в 1991 году и имела номер 0.9. После этого довольно долгое время язык развивался, и популярность он получил в 2000-х годах, во время мажорной второй версии. Однако уже тогда было понятно, что в языке необходимы изменения, которые будут обратно несовместимы с текущими версиями, такие как например, изменения в поведении юникодных строк. Однако вторая версия Python была уже очень популярна к этому моменту, поэтому третья работа над третьей версией велась одновременно с работой над 2.7. Довольно долго у core-разработчиков Python не было определенной стратегии, поэтому до версии 3.4 изменения были довольно хаотичны.</p>
16
</ul><p>Python был разработан около тридцати лет назад, первая его официальная версия вышла в 1991 году и имела номер 0.9. После этого довольно долгое время язык развивался, и популярность он получил в 2000-х годах, во время мажорной второй версии. Однако уже тогда было понятно, что в языке необходимы изменения, которые будут обратно несовместимы с текущими версиями, такие как например, изменения в поведении юникодных строк. Однако вторая версия Python была уже очень популярна к этому моменту, поэтому третья работа над третьей версией велась одновременно с работой над 2.7. Довольно долго у core-разработчиков Python не было определенной стратегии, поэтому до версии 3.4 изменения были довольно хаотичны.</p>
17
<p>С 2019 года Python адаптирует годичные релизные циклы. Это изменение было представлено в <a>PEP-602</a> Что это значит для пользоватеоей Python?</p>
17
<p>С 2019 года Python адаптирует годичные релизные циклы. Это изменение было представлено в <a>PEP-602</a> Что это значит для пользоватеоей Python?</p>
18
<ul><li>новая минорная (3.X.0) версия выходит каждый год</li>
18
<ul><li>новая минорная (3.X.0) версия выходит каждый год</li>
19
<li>фаза активной разработки версии 3.X+1.0 начинается в тот момент, когда в релих отправляется 3.X.beta и продолжается 12 месяцев</li>
19
<li>фаза активной разработки версии 3.X+1.0 начинается в тот момент, когда в релих отправляется 3.X.beta и продолжается 12 месяцев</li>
20
<li>каждая минорная версия активно поддерживается в течении полутора лет</li>
20
<li>каждая минорная версия активно поддерживается в течении полутора лет</li>
21
<li>каждая минорная версия получает обновления безопасности в течении трех с половиной лет Пример расписания релизов для версии 3.9 можно посмотреть на рисунке:</li>
21
<li>каждая минорная версия получает обновления безопасности в течении трех с половиной лет Пример расписания релизов для версии 3.9 можно посмотреть на рисунке:</li>
22
</ul><h2>What’s new in Python 3.9?</h2>
22
</ul><h2>What’s new in Python 3.9?</h2>
23
<p>Релиз Python 3.9 произошел 2020-10-05. Рассмотрим что есть нового в этой версии.</p>
23
<p>Релиз Python 3.9 произошел 2020-10-05. Рассмотрим что есть нового в этой версии.</p>
24
<h2>Работа со словарями</h2>
24
<h2>Работа со словарями</h2>
25
<p>Допустим, есть два словаря, которые мы зотим объединить.</p>
25
<p>Допустим, есть два словаря, которые мы зотим объединить.</p>
26
<p>В версиях до 3.9 можно было бы сделать таким образом:</p>
26
<p>В версиях до 3.9 можно было бы сделать таким образом:</p>
27
<p>In [9]:</p>
27
<p>In [9]:</p>
28
pycon = {2017: "Portland", 2018: "Cleveland", 2019: "Cleveland", 2020: "online"} europython = {2017: "Rimini", 2018: "Edinburgh", 2019: "Basel"} {**pycon, **europython}<p>Out[9]:</p>
28
pycon = {2017: "Portland", 2018: "Cleveland", 2019: "Cleveland", 2020: "online"} europython = {2017: "Rimini", 2018: "Edinburgh", 2019: "Basel"} {**pycon, **europython}<p>Out[9]:</p>
29
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Синтаксис ** разворачивает словарь, и когда они объединяются, более позднее значение затирается более новым. Аналогичные дейтсвия можно совершить, если использовать следующий синтаксис:</p>
29
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Синтаксис ** разворачивает словарь, и когда они объединяются, более позднее значение затирается более новым. Аналогичные дейтсвия можно совершить, если использовать следующий синтаксис:</p>
30
<p>In [7]:</p>
30
<p>In [7]:</p>
31
merged_dict = pycon.copy()<strong>for</strong>key, value<strong>in</strong>europython.items(): merged_dict[key] = value merged_dict<p>Out[7]:</p>
31
merged_dict = pycon.copy()<strong>for</strong>key, value<strong>in</strong>europython.items(): merged_dict[key] = value merged_dict<p>Out[7]:</p>
32
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Или таким образом:</p>
32
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Или таким образом:</p>
33
<p>In [8]:</p>
33
<p>In [8]:</p>
34
pycon.update(europython) pycon<p>Out[8]:</p>
34
pycon.update(europython) pycon<p>Out[8]:</p>
35
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Этот способ пойдойдет в случае если нужно изменить первоначальный словарь.</p>
35
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Этот способ пойдойдет в случае если нужно изменить первоначальный словарь.</p>
36
<p>In [14]:</p>
36
<p>In [14]:</p>
37
merged_dict = pycon.copy().update(europython)<p>Out[14]:</p>
37
merged_dict = pycon.copy().update(europython)<p>Out[14]:</p>
38
{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}<p>In [ ]:</p>
38
{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}<p>In [ ]:</p>
39
Однако если нужно сохранить эти данные в новом словаре, этим способом воспользоваться нельзя, в последнем примере<p>In [17]:</p>
39
Однако если нужно сохранить эти данные в новом словаре, этим способом воспользоваться нельзя, в последнем примере<p>In [17]:</p>
40
merged_dict<strong>is</strong><strong>None</strong><p>Out[17]:</p>
40
merged_dict<strong>is</strong><strong>None</strong><p>Out[17]:</p>
41
True<p>В библиотеке collections есть объект ChainMap, который тоже обхединяет словари, но его результатом будет объект ChainMap, а не словарь. Он состоит из нескольких словарей, следующих друг за другом. Если взять значение по ключу, то вернется то значение, которое встречается раньше. То есть, в этом примере для ключа 2019, вернется значение Cleveland</p>
41
True<p>В библиотеке collections есть объект ChainMap, который тоже обхединяет словари, но его результатом будет объект ChainMap, а не словарь. Он состоит из нескольких словарей, следующих друг за другом. Если взять значение по ключу, то вернется то значение, которое встречается раньше. То есть, в этом примере для ключа 2019, вернется значение Cleveland</p>
42
<p>In [28]:</p>
42
<p>In [28]:</p>
43
<strong>from</strong><strong>collections</strong><strong>import</strong>ChainMap merged_dict = ChainMap(pycon, europython) merged_dict<p>Out[28]:</p>
43
<strong>from</strong><strong>collections</strong><strong>import</strong>ChainMap merged_dict = ChainMap(pycon, europython) merged_dict<p>Out[28]:</p>
44
ChainMap({2017: 'Amsterdam', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}, {2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel'})<p>В Python 3.8 был представлен walrus-оператор. С его помощью можно решить проблему примера с update и скопировать словарь в новую переменную:In [11]:</p>
44
ChainMap({2017: 'Amsterdam', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}, {2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel'})<p>В Python 3.8 был представлен walrus-оператор. С его помощью можно решить проблему примера с update и скопировать словарь в новую переменную:In [11]:</p>
45
(merged_dict := pycon.copy()).update(europython) merged_dict<p>Out[11]:</p>
45
(merged_dict := pycon.copy()).update(europython) merged_dict<p>Out[11]:</p>
46
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>В Python 3.9 в <a>PEP-0614</a> добавлен синтаксис | (читается как pipe), который объединяет словари аналогично первому примеру:</p>
46
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>В Python 3.9 в <a>PEP-0614</a> добавлен синтаксис | (читается как pipe), который объединяет словари аналогично первому примеру:</p>
47
<p>In [13]:</p>
47
<p>In [13]:</p>
48
pycon | europython<p>Out[13]:</p>
48
pycon | europython<p>Out[13]:</p>
49
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>При этом первоначальный словарь не меняется:</p>
49
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>При этом первоначальный словарь не меняется:</p>
50
<p>In [14]:</p>
50
<p>In [14]:</p>
51
pycon<p>Out[14]:</p>
51
pycon<p>Out[14]:</p>
52
{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}<p>Если все-таки нужно обновить первоначальный словарь, можно воспользоваться синтаксисом |= (работает по аналогии с +=): a |= b a = a|bIn [16]:</p>
52
{2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'}<p>Если все-таки нужно обновить первоначальный словарь, можно воспользоваться синтаксисом |= (работает по аналогии с +=): a |= b a = a|bIn [16]:</p>
53
pycon |= europython pycon<p>Out[16]:</p>
53
pycon |= europython pycon<p>Out[16]:</p>
54
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Важно помнить, что поскольку более поздние значения перезаписывают более ранние значения, эта операция может быть не коммуникативна.</p>
54
{2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Важно помнить, что поскольку более поздние значения перезаписывают более ранние значения, эта операция может быть не коммуникативна.</p>
55
<p>In [23]:</p>
55
<p>In [23]:</p>
56
print(europython | pycon) print(pycon | europython) {2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'} {2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Синтаксис | работает только непосредственно со словарями, тогда как синтаксис ** работает и с orderedict и с другими подобными словарям объектами.</p>
56
print(europython | pycon) print(pycon | europython) {2017: 'Portland', 2018: 'Cleveland', 2019: 'Cleveland', 2020: 'online'} {2017: 'Rimini', 2018: 'Edinburgh', 2019: 'Basel', 2020: 'online'}<p>Синтаксис | работает только непосредственно со словарями, тогда как синтаксис ** работает и с orderedict и с другими подобными словарям объектами.</p>
57
<h2>Изменения в работе с декораторами</h2>
57
<h2>Изменения в работе с декораторами</h2>
58
<p>До версии 3.9 в качестве декораторов могли выступать функции или классы, но не такие объекты как списки или словари. Рассмотрим пример, в котором это будет удобно использовать. Допустим есть UI-приложение с кнопками, и нужно добавить какое-то сообщение по нажатию на каждую кнопку. Было бы удобно это сделать с помощью декоратора, но что делать, если для каждой кнопки нужно печатать различные сообщения. Это можно сделать следующим образом:In [ ]:</p>
58
<p>До версии 3.9 в качестве декораторов могли выступать функции или классы, но не такие объекты как списки или словари. Рассмотрим пример, в котором это будет удобно использовать. Допустим есть UI-приложение с кнопками, и нужно добавить какое-то сообщение по нажатию на каждую кнопку. Было бы удобно это сделать с помощью декоратора, но что делать, если для каждой кнопки нужно печатать различные сообщения. Это можно сделать следующим образом:In [ ]:</p>
59
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!")<p>Создаем list comprehension из функций, явно присваем объектам значения элементов списка, и их можно использовать в качестве декораторов. Это будет работать, однако не будет эффективно, если объектов из которых будут созданы декораторы, будет достаточно много.</p>
59
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!")<p>Создаем list comprehension из функций, явно присваем объектам значения элементов списка, и их можно использовать в качестве декораторов. Это будет работать, однако не будет эффективно, если объектов из которых будут созданы декораторы, будет достаточно много.</p>
60
<p>Это не единственный способ, но другие будут довольно неоднозначными. Рассмотрим два из них. В первом случае создадим функцию, которая будет возвращать необходимую для декоратора функцию:In [ ]:</p>
60
<p>Это не единственный способ, но другие будут довольно неоднозначными. Рассмотрим два из них. В первом случае создадим функцию, которая будет возвращать необходимую для декоратора функцию:In [ ]:</p>
61
<strong>def</strong>_(x):<strong>return</strong>x @_(buttons[0].clicked.connect)<strong>def</strong>say_hello(): ...<p>Использование eval:In [ ]:</p>
61
<strong>def</strong>_(x):<strong>return</strong>x @_(buttons[0].clicked.connect)<strong>def</strong>say_hello(): ...<p>Использование eval:In [ ]:</p>
62
@eval("buttons[1].clicked.connect")<strong>def</strong>say_bye(): ...<p>В Python 3.9 стало возможно создавать декораторы из любых объектов, например из элементов списков и словарей. Можно рассмотреть синтаксис, который реализует тот же самый пример:</p>
62
@eval("buttons[1].clicked.connect")<strong>def</strong>say_bye(): ...<p>В Python 3.9 стало возможно создавать декораторы из любых объектов, например из элементов списков и словарей. Можно рассмотреть синтаксис, который реализует тот же самый пример:</p>
63
<p>In [ ]:</p>
63
<p>In [ ]:</p>
64
@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!")<p>Похожим образом будет выглядеть синтаксис для значений словаря:</p>
64
@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!")<p>Похожим образом будет выглядеть синтаксис для значений словаря:</p>
65
<p>In [ ]:</p>
65
<p>In [ ]:</p>
66
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!")<p>Этот функционал, несмотря на то, что не приносит новых возможностей, позволяет писать более чистый код и избегать рискованных решений вроде использования eval.</p>
66
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!")<p>Этот функционал, несмотря на то, что не приносит новых возможностей, позволяет писать более чистый код и избегать рискованных решений вроде использования eval.</p>
67
<h2>Изменения в синтаксисе типирования</h2>
67
<h2>Изменения в синтаксисе типирования</h2>
68
<h3>Дженерики</h3>
68
<h3>Дженерики</h3>
69
<p>Дженерики это типы, которые могут быть параметризованы, обычно являются контейнерами, например dict. Параметризованные дженерики это типы, для которых указан внутренний тип, например dict[str, int]</p>
69
<p>Дженерики это типы, которые могут быть параметризованы, обычно являются контейнерами, например dict. Параметризованные дженерики это типы, для которых указан внутренний тип, например dict[str, int]</p>
70
-
<p>Начиная с Python 3.7 стало можно указывать тип объекта, конкретизируя тип внутренних элементов контейнеры. Но для этого нужно было импортировать таки типы как List из модуля typing:</p>
70
+
<p>Начиная с Python 3.7 стало можно указывать тип объекта, конкре��изируя тип внутренних элементов контейнеры. Но для этого нужно было импортировать таки типы как List из модуля typing:</p>
71
<p>In [ ]:</p>
71
<p>In [ ]:</p>
72
<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>...<p>Можно было не конкретизировать тип внутренних значений, для этого не нужно было импортировать дополинтельные типы и можно было использовать стандартные типы dict и list. Благодаря этому нововведению, внешние библиотеки такие как Mypy стали распознавать дженерики.</p>
72
<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>...<p>Можно было не конкретизировать тип внутренних значений, для этого не нужно было импортировать дополинтельные типы и можно было использовать стандартные типы dict и list. Благодаря этому нововведению, внешние библиотеки такие как Mypy стали распознавать дженерики.</p>
73
<p>Также, в версии 3.9 стало можно пользоваться аннотациями без явного их импорта из модуля __future__</p>
73
<p>Также, в версии 3.9 стало можно пользоваться аннотациями без явного их импорта из модуля __future__</p>
74
<h3>Расширение возможностей аннотаций</h3>
74
<h3>Расширение возможностей аннотаций</h3>
75
<p>Аннотации были доступны для использования и в более ранних версиях Python, однако их функция была скорее информационной, использовались они в первую очередь для документации. Синтаксис использования аннотаций до Python 3.9 выглядел таким образом:</p>
75
<p>Аннотации были доступны для использования и в более ранних версиях Python, однако их функция была скорее информационной, использовались они в первую очередь для документации. Синтаксис использования аннотаций до Python 3.9 выглядел таким образом:</p>
76
<p>In [24]:</p>
76
<p>In [24]:</p>
77
<strong>def</strong>speed(distance: "feet", time: "seconds") -> "miles per hour": fps2mph = 3600 / 5280<strong>return</strong>distance / time * fps2mph<p>В Python 3.9 появился новый объект типа Annotated, который принимает на вход два аргумента, первый это реальный тип, которым должен обладать аннотриуемый объект, а второй это название для целей документации:</p>
77
<strong>def</strong>speed(distance: "feet", time: "seconds") -> "miles per hour": fps2mph = 3600 / 5280<strong>return</strong>distance / time * fps2mph<p>В Python 3.9 появился новый объект типа Annotated, который принимает на вход два аргумента, первый это реальный тип, которым должен обладать аннотриуемый объект, а второй это название для целей документации:</p>
78
<p>In [ ]:</p>
78
<p>In [ ]:</p>
79
<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<p>Когда происходит проверка аннотаций, проверяется только первый аргумент, в котором находится "реальный" тип объекта, а второй использовуется как и в предыдущих версиях:</p>
79
<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<p>Когда происходит проверка аннотаций, проверяется только первый аргумент, в котором находится "реальный" тип объекта, а второй использовуется как и в предыдущих версиях:</p>
80
<p>In [25]:</p>
80
<p>In [25]:</p>
81
speed.__annotations__<p>Out[25]:</p>
81
speed.__annotations__<p>Out[25]:</p>
82
{'distance': 'feet', 'time': 'seconds', 'return': 'miles per hour'}<h2>Изменения связанные с часовыми поясами</h2>
82
{'distance': 'feet', 'time': 'seconds', 'return': 'miles per hour'}<h2>Изменения связанные с часовыми поясами</h2>
83
<p>В предыдущих версиях Python, модуль datetime не содержал информации о часовых поясах, и рекомендованным способом работы с ними была библиотека python-dateutil.</p>
83
<p>В предыдущих версиях Python, модуль datetime не содержал информации о часовых поясах, и рекомендованным способом работы с ними была библиотека python-dateutil.</p>
84
<p>Однако начиная с Python 3.9 появился модуль zoneinfo, который содержит информацию о часовых поясах и позволяет создавать объекты им соответствующие:</p>
84
<p>Однако начиная с Python 3.9 появился модуль zoneinfo, который содержит информацию о часовых поясах и позволяет создавать объекты им соответствующие:</p>
85
<p>In [31]:</p>
85
<p>In [31]:</p>
86
<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()<p>Out[31]:</p>
86
<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()<p>Out[31]:</p>
87
(datetime.datetime(2021, 5, 4, 15, 58, 36, 295472, tzinfo=datetime.timezone.utc), datetime.datetime(2021, 5, 4, 17, 58, 36, 295477))<p>В стандартной библиотеке не было информации ни о каких часовых поясах, кроме utc, и необходимо было использовать pytz чтобы создать объект, содержащий информацию о часовом поясе. Теперь это можно сделать без установки дополнительных библиотек:In [32]:</p>
87
(datetime.datetime(2021, 5, 4, 15, 58, 36, 295472, tzinfo=datetime.timezone.utc), datetime.datetime(2021, 5, 4, 17, 58, 36, 295477))<p>В стандартной библиотеке не было информации ни о каких часовых поясах, кроме utc, и необходимо было использовать pytz чтобы создать объект, содержащий информацию о часовом поясе. Теперь это можно сделать без установки дополнительных библиотек:In [32]:</p>
88
<strong>from</strong><strong>zoneinfo</strong><strong>import</strong>ZoneInfo local_tz = ZoneInfo('Europe/Amsterdam') datetime.now(tz=local_tz)<p>Out[32]:</p>
88
<strong>from</strong><strong>zoneinfo</strong><strong>import</strong>ZoneInfo local_tz = ZoneInfo('Europe/Amsterdam') datetime.now(tz=local_tz)<p>Out[32]:</p>
89
(datetime.datetime(2021, 5, 4, 17, 58, 37, 765947, tzinfo=zoneinfo.ZoneInfo(key='Europe/Amsterdam')),)<p>In [ ]:</p>
89
(datetime.datetime(2021, 5, 4, 17, 58, 37, 765947, tzinfo=zoneinfo.ZoneInfo(key='Europe/Amsterdam')),)<p>In [ ]:</p>
90
-
Всего часовых поясов больше чем мож��о было бы предположить, и многие из них представлены в модуле `zoneinfo`<p>In [33]:</p>
90
+
Всего часовых поясов больше чем можно было бы предположить, и многие из них представлены в модуле `zoneinfo`<p>In [33]:</p>
91
<strong>import</strong><strong>zoneinfo</strong>tzs = zoneinfo.available_timezones() len(tzs)<p>Out[33]:</p>
91
<strong>import</strong><strong>zoneinfo</strong>tzs = zoneinfo.available_timezones() len(tzs)<p>Out[33]:</p>
92
594<h2>Новые методы работы со строкам</h2>
92
594<h2>Новые методы работы со строкам</h2>
93
<p>Иногда нужно убрать первые или последние несколько символов из строки. Есть метод strip, который обладает казалось бы похожим функционалом, но он может иногда давать <a>неожиданные</a> <a>результаты</a> Например в таком случае:</p>
93
<p>Иногда нужно убрать первые или последние несколько символов из строки. Есть метод strip, который обладает казалось бы похожим функционалом, но он может иногда давать <a>неожиданные</a> <a>результаты</a> Например в таком случае:</p>
94
<p>In [34]:</p>
94
<p>In [34]:</p>
95
"ababbbbbbaaccc".lstrip("ab")<p>Out[34]:</p>
95
"ababbbbbbaaccc".lstrip("ab")<p>Out[34]:</p>
96
'ccc'<p>В Python 3.9 были <a>добавлены</a> функции removeprefix, removesuffix, которые выполняют то, что от них ожидается: удаляют первые или последние несколько символов строки.In [35]:</p>
96
'ccc'<p>В Python 3.9 были <a>добавлены</a> функции removeprefix, removesuffix, которые выполняют то, что от них ожидается: удаляют первые или последние несколько символов строки.In [35]:</p>
97
"ababbbbbbaaccc".removeprefix("ab")<p>Out[35]:</p>
97
"ababbbbbbaaccc".removeprefix("ab")<p>Out[35]:</p>
98
'abbbbbbaaccc'<p>In [36]:</p>
98
'abbbbbbaaccc'<p>In [36]:</p>
99
"ababbbbbbaaccc".removesuffix("c")<p>Out[36]:</p>
99
"ababbbbbbaaccc".removesuffix("c")<p>Out[36]:</p>
100
'ababbbbbbaacc'<p>In [36]:</p>
100
'ababbbbbbaacc'<p>In [36]:</p>
101
Если строка не содержит суффикс или префикс, строка не меняется, никаких исключений не появляется.<p>In [37]:</p>
101
Если строка не содержит суффикс или префикс, строка не меняется, никаких исключений не появляется.<p>In [37]:</p>
102
"ababbbbbbaaccc".removesuffix("something else")<p>Out[37]:</p>
102
"ababbbbbbaaccc".removesuffix("something else")<p>Out[37]:</p>
103
'ababbbbbbaaccc'<p>Ссылки:</p>
103
'ababbbbbbaaccc'<p>Ссылки:</p>
104
<ul><li><a>https://docs.python.org/3/whatsnew/3.9.html#summary-release-highlights</a></li>
104
<ul><li><a>https://docs.python.org/3/whatsnew/3.9.html#summary-release-highlights</a></li>
105
</ul><h2>Python 3.10</h2>
105
</ul><h2>Python 3.10</h2>
106
<p>Последняя версия Python 3.10 это <a>0b3</a>, которая вышла 17 июня 2021 года. Согласно расписанию релизов, полноценный релиз появится примерно в октябре 2021. Пока официального релиза нет, версия не доступна в пакетных менеджерах (таких как brew). Соответственно, чтобы ее установить, билд нужно скачать вручную с www.python.org и уствноваить на своей машине. Рассмотрим изменения, доступные в этой Python 3.9.</p>
106
<p>Последняя версия Python 3.10 это <a>0b3</a>, которая вышла 17 июня 2021 года. Согласно расписанию релизов, полноценный релиз появится примерно в октябре 2021. Пока официального релиза нет, версия не доступна в пакетных менеджерах (таких как brew). Соответственно, чтобы ее установить, билд нужно скачать вручную с www.python.org и уствноваить на своей машине. Рассмотрим изменения, доступные в этой Python 3.9.</p>
107
<h2>Pattern Matching</h2>
107
<h2>Pattern Matching</h2>
108
<p>В более ранних версиях Python если нужно описать различное поведение, в зависимости от того, какой объект используется, скорее всего будет использоваться условный оператор:In [ ]:</p>
108
<p>В более ранних версиях Python если нужно описать различное поведение, в зависимости от того, какой объект используется, скорее всего будет использоваться условный оператор:In [ ]:</p>
109
<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<p>Однако в Python 3.10 вместе с <a>PEP-0635</a> будет добавлен новый оператор match, который может использоваться с case:In [ ]:</p>
109
<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<p>Однако в Python 3.10 вместе с <a>PEP-0635</a> будет добавлен новый оператор match, который может использоваться с case:In [ ]:</p>
110
match x: case host, port: mode = "http" case host, port, mode:<strong>pass</strong>cass Class1: ... case host == 'localhost' ...<p>Также с его помощью будет удобно реализовывать, например, обработку ошибок:In [ ]:</p>
110
match x: case host, port: mode = "http" case host, port, mode:<strong>pass</strong>cass Class1: ... case host == 'localhost' ...<p>Также с его помощью будет удобно реализовывать, например, обработку ошибок:In [ ]:</p>
111
<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"<p>Это одно из самых "громких" нововведений в последних версиях Python и возможно самое ожидаемое коммьюнити.</p>
111
<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"<p>Это одно из самых "громких" нововведений в последних версиях Python и возможно самое ожидаемое коммьюнити.</p>
112
<h2>Более удобное использование Union для типирования:</h2>
112
<h2>Более удобное использование Union для типирования:</h2>
113
<p>Если раньше чтобы указать, что аргумент функции может быть одним из нескольких типов, необходимо было использовать Union, импортируемый из пакета typing:In [ ]:</p>
113
<p>Если раньше чтобы указать, что аргумент функции может быть одним из нескольких типов, необходимо было использовать Union, импортируемый из пакета typing:In [ ]:</p>
114
<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<p>То начиная с Python 3.10 можно будет заменить его оператором pipe | и, соответственно, избавиться от импорта:In [ ]:</p>
114
<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<p>То начиная с Python 3.10 можно будет заменить его оператором pipe | и, соответственно, избавиться от импорта:In [ ]:</p>
115
<strong>def</strong>square(number: int | float) -> int | float:<strong>return</strong>number ** 2<h2>Контекстные менеджеры</h2>
115
<strong>def</strong>square(number: int | float) -> int | float:<strong>return</strong>number ** 2<h2>Контекстные менеджеры</h2>
116
<p>Синтаксис работы с контекстными менеджерами упростится, теперь несколько контекстных менеджеров можно объединять в одном with, а так же не обязательно присваивать им локальные имена:In [ ]:</p>
116
<p>Синтаксис работы с контекстными менеджерами упростится, теперь несколько контекстных менеджеров можно объединять в одном with, а так же не обязательно присваивать им локальные имена:In [ ]:</p>
117
<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 ): ...<h2>Более информативные сообщения об ошибках</h2>
117
<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 ): ...<h2>Более информативные сообщения об ошибках</h2>
118
<p>Наверняка многие из читателей сталкивались с тем, что сообщение об ошибке слишком общее и само по себе не говорит о том, что нужно сделать чтобы ошибку исправить. В новой версиеи Python core-разработчики улучшили самые распространенные из них и теперь сообщения об ошибках будут намного более читабельными:In [ ]:</p>
118
<p>Наверняка многие из читателей сталкивались с тем, что сообщение об ошибке слишком общее и само по себе не говорит о том, что нужно сделать чтобы ошибку исправить. В новой версиеи Python core-разработчики улучшили самые распространенные из них и теперь сообщения об ошибках будут намного более читабельными:In [ ]:</p>
119
expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4, ^<strong>SyntaxError</strong>: '{' was never closed<p>In [ ]:</p>
119
expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4, ^<strong>SyntaxError</strong>: '{' was never closed<p>In [ ]:</p>
120
>>><strong>if</strong>rocket.position > event_horizon File "<stdin>", line 1<strong>if</strong>rocket.position > event_horizon ^<strong>SyntaxError</strong>: expected ':'<p>In [ ]:</p>
120
>>><strong>if</strong>rocket.position > event_horizon File "<stdin>", line 1<strong>if</strong>rocket.position > event_horizon ^<strong>SyntaxError</strong>: expected ':'<p>In [ ]:</p>
121
>>> {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?<p>In [ ]:</p>
121
>>> {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?<p>In [ ]:</p>
122
<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<p>In [ ]:</p>
122
<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<p>In [ ]:</p>
123
<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<h2>Остальное</h2>
123
<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<h2>Остальное</h2>
124
<ul><li>Модуль distutils постепенно выыводится из употребления, чтобы быть полностью удаленным в Python 3.12. Это связано с тем, что его функции были полностью заменены такими модулями как setuptools и packaging.</li>
124
<ul><li>Модуль distutils постепенно выыводится из употребления, чтобы быть полностью удаленным в Python 3.12. Это связано с тем, что его функции были полностью заменены такими модулями как setuptools и packaging.</li>
125
<li>Улучшение читабельности сообщений в модуле <a>debugging</a></li>
125
<li>Улучшение читабельности сообщений в модуле <a>debugging</a></li>
126
</ul><p>Это не все изменения которые попадут в Python 3.10, с полным списком можно ознакомиться посмотрев <a>список изменений</a>.</p>
126
</ul><p>Это не все изменения которые попадут в Python 3.10, с полным списком можно ознакомиться посмотрев <a>список изменений</a>.</p>
127
<p>Прокачать Python можно на курсах:</p>
127
<p>Прокачать Python можно на курсах:</p>
128
<ul><li><a>Python Developer. Basic</a></li>
128
<ul><li><a>Python Developer. Basic</a></li>
129
<li><a>Python Developer. Professional</a></li>
129
<li><a>Python Developer. Professional</a></li>
130
<li><a>Web-разработчик на Python</a></li>
130
<li><a>Web-разработчик на Python</a></li>
131
</ul>
131
</ul>