HTML Diff
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]]) -&gt; int:<em>#def find(haystack: dict) -&gt; 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]]) -&gt; int:<em>#def find(haystack: dict) -&gt; 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") -&gt; "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") -&gt; "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"]) -&gt; 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"]) -&gt; 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]) -&gt; 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]) -&gt; Union[int, float]:<strong>return</strong>number ** 2<p>То начиная с Python 3.10 можно будет заменить его оператором pipe | и, соответственно, избавиться от импорта:In [ ]:</p>
115 <strong>def</strong>square(number: int | float) -&gt; int | float:<strong>return</strong>number ** 2<h2>Контекстные менеджеры</h2>
115 <strong>def</strong>square(number: int | float) -&gt; 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 &gt;&gt;&gt;<strong>if</strong>rocket.position &gt; event_horizon File "&lt;stdin&gt;", line 1<strong>if</strong>rocket.position &gt; event_horizon ^<strong>SyntaxError</strong>: expected ':'<p>In [ ]:</p>
120 &gt;&gt;&gt;<strong>if</strong>rocket.position &gt; event_horizon File "&lt;stdin&gt;", line 1<strong>if</strong>rocket.position &gt; event_horizon ^<strong>SyntaxError</strong>: expected ':'<p>In [ ]:</p>
121 &gt;&gt;&gt; {x,y<strong>for</strong>x,y<strong>in</strong>range(100)} File "&lt;stdin&gt;", 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 &gt;&gt;&gt; {x,y<strong>for</strong>x,y<strong>in</strong>range(100)} File "&lt;stdin&gt;", 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 "&lt;stdin&gt;", 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 "&lt;stdin&gt;", 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 "&lt;stdin&gt;", 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 "&lt;stdin&gt;", 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>