Compare commits

...

2 Commits

Author SHA1 Message Date
Vadim Nifadev
d0dd3ad2b7 Fix typos and spelling 2024-04-27 12:21:12 +03:00
Vadim Nifadev
5bbdcdd5a5 Translate CONTRIBUTORS, fix Markdown table syntax 2024-04-26 10:44:11 +03:00
2 changed files with 236 additions and 176 deletions

20
CONTRIBUTORS.md vendored
View File

@ -1,6 +1,6 @@
Following are the wonderful people (in no specific order) who have contributed their examples to wtfpython. Ниже перечислены (без определенного порядка) замечательные люди, которые внесли вклад в развитие wtfpython.
| Contributor | Github | Issues | | Автор | Github | Issues |
|-------------|--------|--------| |-------------|--------|--------|
| Lucas-C | [Lucas-C](https://github.com/Lucas-C) | [#36](https://github.com/satwikkansal/wtfpython/issues/36) | | Lucas-C | [Lucas-C](https://github.com/Lucas-C) | [#36](https://github.com/satwikkansal/wtfpython/issues/36) |
| MittalAshok | [MittalAshok](https://github.com/MittalAshok) | [#23](https://github.com/satwikkansal/wtfpython/issues/23) | | MittalAshok | [MittalAshok](https://github.com/MittalAshok) | [#23](https://github.com/satwikkansal/wtfpython/issues/23) |
@ -18,25 +18,25 @@ Following are the wonderful people (in no specific order) who have contributed t
| leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [#112](https://github.com/satwikkansal/wtfpython/issues/112) | | leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [#112](https://github.com/satwikkansal/wtfpython/issues/112) |
| mishaturnbull | [mishaturnbull](https://github.com/mishaturnbull) | [#108](https://github.com/satwikkansal/wtfpython/issues/108) | | mishaturnbull | [mishaturnbull](https://github.com/mishaturnbull) | [#108](https://github.com/satwikkansal/wtfpython/issues/108) |
| MuseBoy | [MuseBoy](https://github.com/MuseBoy) | [#101](https://github.com/satwikkansal/wtfpython/issues/101) | | MuseBoy | [MuseBoy](https://github.com/MuseBoy) | [#101](https://github.com/satwikkansal/wtfpython/issues/101) |
| Ghost account | N/A | [#96](https://github.com/satwikkansal/wtfpython/issues/96) | Ghost account | N/A | [#96](https://github.com/satwikkansal/wtfpython/issues/96) |
| koddo | [koddo](https://github.com/koddo) | [#80](https://github.com/satwikkansal/wtfpython/issues/80), [#73](https://github.com/satwikkansal/wtfpython/issues/73) | | koddo | [koddo](https://github.com/koddo) | [#80](https://github.com/satwikkansal/wtfpython/issues/80), [#73](https://github.com/satwikkansal/wtfpython/issues/73) |
| jab | [jab](https://github.com/jab) | [#77](https://github.com/satwikkansal/wtfpython/issues/77) | | jab | [jab](https://github.com/jab) | [#77](https://github.com/satwikkansal/wtfpython/issues/77) |
| Jongy | [Jongy](https://github.com/Jongy) | [#208](https://github.com/satwikkansal/wtfpython/issues/208), [#210](https://github.com/satwikkansal/wtfpython/issues/210), [#233](https://github.com/satwikkansal/wtfpython/issues/233) | | Jongy | [Jongy](https://github.com/Jongy) | [#208](https://github.com/satwikkansal/wtfpython/issues/208), [#210](https://github.com/satwikkansal/wtfpython/issues/210), [#233](https://github.com/satwikkansal/wtfpython/issues/233) |
| Diptangsu Goswami | [diptangsu](https://github.com/diptangsu) | [#193](https://github.com/satwikkansal/wtfpython/issues/193) | | Diptangsu Goswami | [diptangsu](https://github.com/diptangsu) | [#193](https://github.com/satwikkansal/wtfpython/issues/193) |
| Charles | [charles-l](https://github.com/charles-l) | [#245](https://github.com/satwikkansal/wtfpython/issues/245) | Charles | [charles-l](https://github.com/charles-l) | [#245](https://github.com/satwikkansal/wtfpython/issues/245) |
| LiquidFun | [LiquidFun](https://github.com/LiquidFun) | [#267](https://github.com/satwikkansal/wtfpython/issues/267) | LiquidFun | [LiquidFun](https://github.com/LiquidFun) | [#267](https://github.com/satwikkansal/wtfpython/issues/267) |
--- ---
**Translations** **Переводчики**
| Translator | Github | Language | | Переводчик | Github | Язык |
|-------------|--------|--------| |-------------|--------|--------|
| leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [Chinese](https://github.com/leisurelicht/wtfpython-cn) | | leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [Chinese](https://github.com/leisurelicht/wtfpython-cn) |
| vuduclyunitn | [vuduclyunitn](https://github.com/vuduclyunitn) | [Vietnamese](https://github.com/vuduclyunitn/wtfptyhon-vi) | | vuduclyunitn | [vuduclyunitn](https://github.com/vuduclyunitn) | [Vietnamese](https://github.com/vuduclyunitn/wtfptyhon-vi) |
| José De Freitas | [JoseDeFreitas](https://github.com/JoseDeFreitas) | [Spanish](https://github.com/JoseDeFreitas/wtfpython-es) | | José De Freitas | [JoseDeFreitas](https://github.com/JoseDeFreitas) | [Spanish](https://github.com/JoseDeFreitas/wtfpython-es) |
| Vadim Nifadev | [nifadyev](https://github.com/nifadyev) | [Russian](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) |
Спасибо всем за ваше время и за то, что делаете wtfpython еще более потрясающим! :smile:
Thank you all for your time and making wtfpython more awesome! :smile: PS: Этот список обновляется после каждого крупного релиза, если я забыл добавить сюда ваш вклад, пожалуйста, не стесняйтесь сделать Pull request.
PS: This list is updated after every major release, if I forgot to add your contribution here, please feel free to raise a Pull request.

View File

@ -1,98 +1,163 @@
<p align="center"><img src="/images/logo.png#gh-light-mode-only" alt=""><img src="/images/logo-dark.png#gh-dark-mode-only" alt=""></p> <p align="center"><img src="/images/logo.png#gh-light-mode-only" alt=""><img src="/images/logo-dark.png#gh-dark-mode-only" alt=""></p>
<h1 align="center">What the f*ck Python! 😱</h1> <h1 align="center">What the f*ck Python! 😱</h1>
<p align="center">Изучение и понимание Python с помощью нестандартного поведения и "магического" поведения.</p> <p align="center">Изучение и понимание Python с помощью удивительных примеров поведения.</p>
Переводы: [English Original](https://github.com/satwikkansal/wtfpython) [Chinese 中文](https://github.com/robertparley/wtfpython-cn) | [Vietnamese Tiếng Việt](https://github.com/vuduclyunitn/wtfptyhon-vi) | [Spanish Español](https://web.archive.org/web/20220511161045/https://github.com/JoseDeFreitas/wtfpython-es) | [Korean 한국어](https://github.com/buttercrab/wtfpython-ko) | [Russian Русский](https://github.com/nifadyev/wtfpython/tree/main/translations/README-ru.md) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) Переводы: [English Original](https://github.com/satwikkansal/wtfpython) [Chinese 中文](https://github.com/robertparley/wtfpython-cn) | [Vietnamese Tiếng Việt](https://github.com/vuduclyunitn/wtfptyhon-vi) | [Spanish Español](https://web.archive.org/web/20220511161045/https://github.com/JoseDeFreitas/wtfpython-es) | [Korean 한국어](https://github.com/buttercrab/wtfpython-ko) | [Russian Русский](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].)
Альтернативные способы: [Интерактивный сайт](https://wtfpython-interactive.vercel.app) | [Интерактивный Jupiter notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) Альтернативные способы: [Интерактивный сайт](https://wtfpython-interactive.vercel.app) | [Интерактивный Jupiter notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython)
Python, будучи прекрасно спроектированным высокоуровневым языком программирования, предоставляет множество возможностей для удобства программиста. Но иногда результаты работы Python кода могут показаться неочевидными на первый взгляд. Python, будучи прекрасно спроектированным высокоуровневым языком программирования, предоставляет множество возможностей для удобства программиста. Но иногда поведение Python кода могут показаться запутывающим на первый взгляд.
**wtfpython** задуман как проект, пытающийся объяснить, что именно происходит под капотом некоторых неочевидных фрагментов кода и менее известных возможностей Python. **wtfpython** задуман как проект, пытающийся объяснить, что именно происходит под капотом неочевидных фрагментов кода и малоизвестных возможностей Python.
Если вы опытный программист на Python, вы можете принять это как вызов и правильно объяснить WTF ситуации с первой попытки. Возможно, вы уже сталкивались с некоторыми из них раньше, и я смогу оживить ваши старые добрые воспоминания! 😅 Если вы опытный питонист, вы можете принять это как вызов и правильно объяснить WTF ситуации с первой попытки. Возможно, вы уже сталкивались с некоторыми из них раньше, и я смогу оживить ваши старые добрые воспоминания! 😅
PS: Если вы уже читали **wtfpython** раньше, с изменениями можно ознакомиться [здесь](https://github.com/satwikkansal/wtfpython/releases/) (примеры, отмеченные звездочкой - это примеры, добавленные в последней основной редакции). PS: Если вы уже читали **wtfpython** раньше, с изменениями можно ознакомиться [здесь](https://github.com/satwikkansal/wtfpython/releases/) (примеры, отмеченные звездочкой - это примеры, добавленные в последней основной редакции).
Ну что ж, приступим... Ну что ж, приступим...
# Содержание # Содержание
* [Содержание](#Содержание) - [Содержание](#содержание)
* [Структура примера](#Структура-примера) - [Структура примера](#структура-примера)
* [Применение](#Применение) - [Применение](#применение)
* [👀 Примеры](#👀-Примеры) - [👀 Примеры](#-примеры)
* [Секция: Напряги мозги!](#Секция:-Напряги-мозги!) - [Секция: Напряги мозги!](#секция-напряги-мозги)
* [▶ Первым делом!](#▶-Первым-делом!) - [▶ Первым делом!](#-первым-делом)
* [▶ Строки иногда ведут себя непредсказуемо](#▶-Строки-иногда-ведут-себя-непредсказуемо) - [💡 Обьяснение](#-обьяснение)
* [▶ Осторожнее с цепочкой операций](#▶-Осторожнее-с-цепочкой-операций) - [▶ Строки иногда ведут себя непредсказуемо](#-строки-иногда-ведут-себя-непредсказуемо)
* [▶ Как не надо использовать оператор `is`](#▶-Как-не-надо-использовать-оператор-`is`) - [💡 Объяснение](#-объяснение)
* [▶ Мистическое хэширование](#▶-Мистическое-хэширование) - [▶ Осторожнее с цепочкой операций](#-осторожнее-с-цепочкой-операций)
* [В глубине души мы все одинаковы.](#▶-В-глубине-души-мы-все-одинаковы.) - [💡 Объяснение:](#-объяснение-1)
* [▶ Беспорядок внутри порядка *](#▶-Беспорядок-внутри-порядка--*) - [▶ Как не надо использовать оператор `is`](#-как-не-надо-использовать-оператор-is)
* [▶ Продолжай пытаться... *](#▶-Продолжай-пытаться...-*) - [💡 Объяснение:](#-объяснение-2)
* [▶ Для чего?](#▶-Для-чего?) - [▶ Мистическое хеширование](#-мистическое-хеширование)
* [▶ Расхождение во времени исполнения](#▶-Расхождение-во-времени-исполнения) - [💡 Объяснение](#-объяснение-3)
* [▶ `is not ...` не является `is (not ...)`](#▶-`is-not-...`-не-является-`is-(not-...)`) - [В глубине души мы все одинаковы.](#-в-глубине-души-мы-все-одинаковы)
* [▶ Крестики-нолики, где X побеждает с первой попытки!](#▶-Крестики-нолики,-где-X-побеждает-с-первой-попытки!) - [💡 Объяснение:](#-объяснение-4)
* [▶ Переменная Шредингера *](#▶-Переменная-Шредингера-*) - [▶ Беспорядок внутри порядка \*](#-беспорядок-внутри-порядка-)
* [▶ Проблема курицы и яйца *](#▶-Проблема-курицы-и-яйца-*) - [💡 Объяснение:](#-объяснение-5)
* [▶ Отношения между подклассами](#▶-Отношения-между-подклассами) - [▶ Продолжай пытаться... \*](#-продолжай-пытаться-)
* [▶ Равенство и тождество методов](#▶-Равенство-и-тождество-методов) - [💡 Объяснение:](#-объяснение-6)
* [▶ All-true-ation (непереводимая игра слов) *](#▶-All-true-ation-(непереводимая-игра-слов)-*) - [▶ Для чего?](#-для-чего)
* [▶ Неожиданная запятая](#▶-Неожиданная-запятая) - [💡 Объяснение:](#-объяснение-7)
* [▶ Строки и обратные слэши](#▶-Строки-и-обратные-слэши) - [▶ Расхождение во времени исполнения](#-расхождение-во-времени-исполнения)
* [Не узел! (eng. not knot!)](#▶-Не-узел!-(eng.-not-knot!)) - [💡 Объяснение](#-объяснение-8)
* [▶ Строки наполовину в тройных кавычках](#▶-Строки-наполовину-в-тройных-кавычках) - [▶ `is not ...` не является `is (not ...)`](#-is-not--не-является-is-not-)
* [▶ Что не так с логическими значениями?](#▶-Что-не-так-с-логическими-значениями?) - [💡 Объяснение](#-объяснение-9)
* [▶ Атрибуты класса и экземпляра](#▶-Атрибуты-класса-и-экземпляра) - [▶ Крестики-нолики, где X побеждает с первой попытки!](#-крестики-нолики-где-x-побеждает-с-первой-попытки)
* [▶ Возврат None из генератора](#▶-Возврат-None-из-генератора) - [💡 Объяснение:](#-объяснение-10)
* [▶ Yield from возвращает... *](#▶-Yield-from-возвращает...-*) - [▶ Переменная Шредингера \*](#-переменная-шредингера-)
* [▶ Nan-рефлексивность *](#▶-Nan-рефлексивность-*) - [💡 Объяснение:](#-объяснение-11)
* [▶ Мутируем немутируемое!](#▶-Мутируем-немутируемое!) - [▶ Проблема курицы и яйца \*](#-проблема-курицы-и-яйца-)
* [▶ Исчезающая переменная из внешней области видимости](#▶-Исчезающая-переменная-из-внешней-области-видимости) - [💡 Объяснение](#-объяснение-12)
* [▶ Превышение предела целочисленного преобразования строк](#▶-Превышение-предела-целочисленного-преобразования-строк) - [▶ Отношения между подклассами](#-отношения-между-подклассами)
* [Секция: Скользкие склоны](#Секция:-Скользкие-склоны) - [💡 Объяснение](#-объяснение-13)
* [▶ Изменение словаря во время прохода по нему](#▶-Изменение-словаря-во-время-прохода-по-нему) - [▶ Равенство и тождество методов](#-равенство-и-тождество-методов)
* [▶ Упрямая операция `del`](#▶-Упрямая-операция-`del`) - [💡 Объяснение](#-объяснение-14)
* [▶ Переменная за пределами видимости](#▶-Переменная-за-пределами-видимости) - [▶ All-true-ation (непереводимая игра слов) \*](#-all-true-ation-непереводимая-игра-слов-)
* [▶ Удаление элемента списка во время прохода по списку](#▶-Удаление-элемента-списка-во-время-прохода-по-списку) - [💡 Объяснение:](#-объяснение-15)
* [▶ Сжатие итераторов с потерями *](#▶-Сжатие-итераторов-с-потерями-*) - [💡 Объяснение:](#-объяснение-16)
* [▶ Утечка переменных внутри цикла](#▶-Утечка-переменных-внутри-цикла) - [▶ Строки и обратные слэши](#-строки-и-обратные-слэши)
* [▶ Остерегайтесь изменяемых аргументов по умолчанию!](#▶-Остерегайтесь-изменяемых-аргументов-по-умолчанию!) - [💡 Объяснение](#-объяснение-17)
* [▶ Ловля исключений](#▶-Ловля-исключений) - [Не узел! (англ. not knot!)](#-не-узел-англ-not-knot)
* [▶ Одни и те же операнды, разная история!](#▶-Одни-и-те-же-операнды,-разная-история!) - [💡 Объяснение](#-объяснение-18)
* [▶ Разрешение имен игнорирует область видимости класса](#▶-Разрешение-имен-игнорирует-область-видимости-класса) - [▶ Строки, наполовину обернутые в тройные кавычки](#-строки-наполовину-обернутые-в-тройные-кавычки)
* [▶ Округляясь как банкир *](#▶-Округляясь-как-банкир-*) - [💡 Объяснение:](#-объяснение-19)
* [▶ Иголки в стоге сена *](#▶-Иголки-в-стоге-сена-*) - [▶ Что не так с логическими значениями?](#-что-не-так-с-логическими-значениями)
* [▶ Сплиты (splitsies) *](#▶-Сплиты-(splitsies)-*) - [💡 Объяснение:](#-объяснение-20)
* [▶ Подстановочное импортирование (wild imports) *](#▶-Подстановочное-импортирование-(wild-imports)-*) - [▶ Атрибуты класса и экземпляра](#-атрибуты-класса-и-экземпляра)
* [▶ Все ли отсортировано? *](#▶-Все-ли-отсортировано?-*) - [💡 Объяснение:](#-объяснение-21)
* [▶ Полночи не существует?](#▶-Полночи-не-существует?) - [▶ Возврат None из генератора](#-возврат-none-из-генератора)
* [Секция: Скрытые сокровища!](#Секция:-Скрытые-сокровища!) - [💡 Объяснение:](#-объяснение-22)
* [▶ Python, можешь ли ты помочь взлелеть?](#▶-Python,-можешь-ли-ты-помочь-взлелеть?) - [▶ Yield from возвращает... \*](#-yield-from-возвращает-)
* [▶ `goto`, но почему?](#▶-`goto`,-но-почему?) - [💡 Объяснение:](#-объяснение-23)
* [▶ Держитесь!](#▶-Держитесь!) - [▶ Nan-рефлексивность \*](#-nan-рефлексивность-)
* [▶ Давайте познакомимся с дружелюбным Дядей Барри](#▶-Давайте-познакомимся-с-дружелюбным-Дядей-Барри) - [💡 Объяснение:](#-объяснение-24)
* [▶ Даже Python понимает, что любовь - это сложно.](#▶-Даже-Python-понимает,-что-любовь---это-сложно.) - [▶ Изменяем неизменяемое!](#-изменяем-неизменяемое)
* [▶ Да, оно существует!](#▶-Да,-оно-существует!) - [💡 Объяснение:](#-объяснение-25)
* [▶ Многоточие *](#▶-Многоточие-*) - [▶ Исчезающая переменная из внешней области видимости](#-исчезающая-переменная-из-внешней-области-видимости)
* [▶ Писконечность (Inpinity)](#▶-Писконечность-(Inpinity)) - [💡 Объяснение:](#-объяснение-26)
* [▶ Давайте искажать](#▶-Давайте-искажать) - [▶ Загадочное преобразование типов ключей](#-загадочное-преобразование-типов-ключей)
* [Секция: Внешность обманчива!](#Секция:-Внешность-обманчива!) - [💡 Объяснение:](#-объяснение-27)
* [▶ Пропускаем строки?](#▶-Пропускаем-строки?) - [▶ Посмотрим, сможете ли вы угадать что здесь?](#-посмотрим-сможете-ли-вы-угадать-что-здесь)
* [▶ Телепортация](#▶-Телепортация) - [💡 Объяснение:](#-объяснение-28)
* [▶ Что-то не так...](#▶-Что-то-не-так...) - [▶ Превышение предела целочисленного преобразования строк](#-превышение-предела-целочисленного-преобразования-строк)
* [Секция: Разное](#Секция:-Разное) - [💡 Объяснение:](#-объяснение-29)
* [▶ `+=` быстрее](#▶-`+=`-быстрее) - [Секция: Скользкие склоны](#секция-скользкие-склоны)
* [▶ Сделаем гигантскую строку!](#▶-Сделаем-гигантскую-строку!) - [▶ Изменение словаря во время прохода по нему](#-изменение-словаря-во-время-прохода-по-нему)
* [▶ Замедляем поиск по `dict` *](#▶-Замедляем-поиск-по-`dict`-*) - [💡 Объяснение:](#-объяснение-30)
* [▶ Раздуваем экземпляры словарей *](#▶-Раздуваем-экземпляры-словарей-*) - [▶ Упрямая операция `del`](#-упрямая-операция-del)
* [▶ Минорное *](#▶-Минорное-*) - [💡 Объяснение:](#-объяснение-31)
* [Вклад в проект](#Вклад-в-проект) - [▶ Переменная за пределами видимости](#-переменная-за-пределами-видимости)
* [Благодарности](#Благодарности) - [💡 Объяснение:](#-объяснение-32)
* [🎓 Лицензия](#🎓-Лицензия) - [▶ Удаление элемента списка во время прохода по списку](#-удаление-элемента-списка-во-время-прохода-по-списку)
* [Удиви своих друзей!](#Удиви-своих-друзей!) - [💡 Объяснение:](#-объяснение-33)
* [Нужна PDF версия?](#Нужна-PDF-версия?) - [▶ Сжатие итераторов с потерями \*](#-сжатие-итераторов-с-потерями-)
- [💡 Объяснение:](#-объяснение-34)
- [▶ Утечка переменных внутри цикла](#-утечка-переменных-внутри-цикла)
- [💡 Объяснение:](#-объяснение-35)
- [▶ Остерегайтесь изменяемых аргументов по умолчанию!](#-остерегайтесь-изменяемых-аргументов-по-умолчанию)
- [💡 Объяснение:](#-объяснение-36)
- [▶ Ловля исключений](#-ловля-исключений)
- [💡 Объяснение](#-объяснение-37)
- [▶ Одни и те же операнды, разная история!](#-одни-и-те-же-операнды-разная-история)
- [💡 Объяснение:](#-объяснение-38)
- [▶ Разрешение имен игнорирует область видимости класса](#-разрешение-имен-игнорирует-область-видимости-класса)
- [💡 Объяснение](#-объяснение-39)
- [▶ Округляясь как банкир \*](#-округляясь-как-банкир-)
- [💡 Объяснение:](#-объяснение-40)
- [▶ Иголки в стоге сена \*](#-иголки-в-стоге-сена-)
- [💡 Объяснение:](#-объяснение-41)
- [▶ Сплиты (splitsies) \*](#-сплиты-splitsies-)
- [💡 Объяснение](#-объяснение-42)
- [▶ Подстановочное импортирование (wild imports) \*](#-подстановочное-импортирование-wild-imports-)
- [💡 Объяснение:](#-объяснение-43)
- [Все ли отсортировано? \*](#-все-ли-отсортировано-)
- [💡 Объяснение:](#-объяснение-44)
- [▶ Полночи не существует?](#-полночи-не-существует)
- [💡 Объяснение:](#-объяснение-45)
- [Секция: Скрытые сокровища!](#секция-скрытые-сокровища)
- [▶ Python, можешь ли ты помочь взлететь?](#-python-можешь-ли-ты-помочь-взлететь)
- [💡 Объяснение:](#-объяснение-46)
- [▶ `goto`, но почему?](#-goto-но-почему)
- [💡 Объяснение:](#-объяснение-47)
- [▶ Держитесь!](#-держитесь)
- [💡 Объяснение:](#-объяснение-48)
- [▶ Давайте познакомимся с дружелюбным Дядей Барри](#-давайте-познакомимся-с-дружелюбным-дядей-барри)
- [💡 Объяснение:](#-объяснение-49)
- [▶ Даже Python понимает, что любовь - это сложно.](#-даже-python-понимает-что-любовь---это-сложно)
- [💡 Объяснение:](#-объяснение-50)
- [▶ Да, оно существует!](#-да-оно-существует)
- [💡 Объяснение:](#-объяснение-51)
- [▶ Многоточие \*](#-многоточие-)
- [💡 Объяснение](#-объяснение-52)
- [▶ Писконечность (Inpinity)](#-писконечность-inpinity)
- [💡 Объяснение:](#-объяснение-53)
- [▶ Давайте искажать](#-давайте-искажать)
- [💡 Объяснение:](#-объяснение-54)
- [Секция: Внешность обманчива!](#секция-внешность-обманчива)
- [▶ Пропускаем строки?](#-пропускаем-строки)
- [💡 Объяснение](#-объяснение-55)
- [▶ Телепортация](#-телепортация)
- [💡 Объяснение:](#-объяснение-56)
- [▶ Что-то не так...](#-что-то-не-так)
- [💡 Объяснение](#-объяснение-57)
- [Секция: Разное](#секция-разное)
- [▶ `+=` быстрее `+`](#--быстрее-)
- [💡 Объяснение:](#-объяснение-58)
- [▶ Сделаем гигантскую строку!](#-сделаем-гигантскую-строку)
- [💡 Объяснение](#-объяснение-59)
- [▶ Замедляем поиск по `dict` \*](#-замедляем-поиск-по-dict-)
- [💡 Объяснение:](#-объяснение-60)
- [▶ Раздуваем экземпляры словарей \*](#-раздуваем-экземпляры-словарей-)
- [💡 Объяснение:](#-объяснение-61)
- [▶ Минорное \*](#-минорное-)
- [Вклад в проект](#вклад-в-проект)
- [Благодарности](#благодарности)
- [Несколько хороших ссылок!](#несколько-хороших-ссылок)
- [🎓 Лицензия](#-лицензия)
- [Удиви своих друзей!](#удиви-своих-друзей)
- [Нужна PDF версия?](#нужна-pdf-версия)
# Структура примера # Структура примера
@ -137,11 +202,11 @@ PS: Если вы уже читали **wtfpython** раньше, с измен
Хороший способ получить максимальную пользу от этих примеров - читать их последовательно, причем для каждого из них важно: Хороший способ получить максимальную пользу от этих примеров - читать их последовательно, причем для каждого из них важно:
- Внимательно изучить исходный код. Если вы опытный программист на Python, то в большинстве случаев сможете предугадать, что произойдет дальше. - Внимательно изучить исходный код. Если вы опытный Python программист, то в большинстве случаев сможете предугадать, что произойдет дальше.
- Прочитать фрагменты вывода и, - Прочитать фрагменты вывода и,
- Проверить, совпадают ли выходные данные с вашими ожиданиями. - Проверить, совпадают ли выходные данные с вашими ожиданиями.
- Убедиться, что вы знаете точную причину, по которой вывод получился именно таким. - Убедиться, что вы знаете точную причину, по которой вывод получился именно таким.
- Если ответ отрицательный (что совершенно нормально), сделать глубокий вдох и прочитать объяснение (а если пример все еще непонятен, и создайте issue [здесь](https://github.com/satwikkansal/wtfpython/issues/new)). - Если ответ отрицательный (что совершенно нормально), сделать глубокий вдох и прочитать объяснение (а если пример все еще непонятен, и создайте [issue](https://github.com/satwikkansal/wtfpython/issues/new)).
- Если "да", ощутите мощь своих познаний в Python и переходите к следующему примеру. - Если "да", ощутите мощь своих познаний в Python и переходите к следующему примеру.
PS: Вы также можете читать WTFPython в командной строке, используя [pypi package](https://pypi.python.org/pypi/wtfpython), PS: Вы также можете читать WTFPython в командной строке, используя [pypi package](https://pypi.python.org/pypi/wtfpython),
@ -344,7 +409,7 @@ False
- Строки интернируются во время компиляции (`'wtf'` будет интернирована, но `''.join(['w'', 't', 'f'])` - нет) - Строки интернируются во время компиляции (`'wtf'` будет интернирована, но `''.join(['w'', 't', 'f'])` - нет)
- Строки, не состоящие из букв ASCII, цифр или знаков подчеркивания, не интернируются. В примере выше `'wtf!'` не интернируется из-за `!`. Реализацию этого правила в CPython можно найти [здесь](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19) - Строки, не состоящие из букв ASCII, цифр или знаков подчеркивания, не интернируются. В примере выше `'wtf!'` не интернируется из-за `!`. Реализацию этого правила в CPython можно найти [здесь](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19)
![image](/images/string-intern/string_intern.png) ![image](/images/string-intern/string_intern.png)
- Когда переменные `a` и `b` принимают значение `"wtf!"` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на вторую переменную. Если это выполняется в отдельных строках, он не "знает", что уже существует `"wtf!"` как объект (потому что `"wtf!"` не является неявно интернированным в соответствии с фактами, упомянутыми выше). Это оптимизация во время компиляции, не применяется к версиям CPython 3.7.x (более подробное обсуждение смотрите здесь [issue](https://github.com/satwikkansal/wtfpython/issues/100)). - Когда переменные `a` и `b` принимают значение `"wtf!"` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на вторую переменную. Если это выполняется в отдельных строках, он не "знает", что уже существует `"wtf!"` как объект (потому что `"wtf!"` не является неявно интернированным в соответствии с фактами, упомянутыми выше). Это оптимизация во время компиляции, не применяется к версиям CPython 3.7.x (более подробное обсуждение смотрите [здесь](https://github.com/satwikkansal/wtfpython/issues/100)).
- Единица компиляции в интерактивной среде IPython состоит из одного оператора, тогда как в случае модулей она состоит из всего модуля. `a, b = "wtf!", "wtf!"` - это одно утверждение, тогда как `a = "wtf!"; b = "wtf!"` - это два утверждения в одной строке. Это объясняет, почему тождества различны в `a = "wtf!"; b = "wtf!"`, но одинаковы при вызове в модуле. - Единица компиляции в интерактивной среде IPython состоит из одного оператора, тогда как в случае модулей она состоит из всего модуля. `a, b = "wtf!", "wtf!"` - это одно утверждение, тогда как `a = "wtf!"; b = "wtf!"` - это два утверждения в одной строке. Это объясняет, почему тождества различны в `a = "wtf!"; b = "wtf!"`, но одинаковы при вызове в модуле.
- Резкое изменение в выводе четвертого фрагмента связано с [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) техникой, известной как складывание констант (англ. Constant folding). Это означает, что выражение `'a'*20` заменяется на `'aaaaaaaaaaaaaaaaaaaa'` во время компиляции, чтобы сэкономить несколько тактов во время выполнения. Складывание констант происходит только для строк длиной менее 21. (Почему? Представьте себе размер файла `.pyc`, созданного в результате выполнения выражения `'a'*10**10`). [Вот](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) исходный текст реализации для этого. - Резкое изменение в выводе четвертого фрагмента связано с [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) техникой, известной как складывание констант (англ. Constant folding). Это означает, что выражение `'a'*20` заменяется на `'aaaaaaaaaaaaaaaaaaaa'` во время компиляции, чтобы сэкономить несколько тактов во время выполнения. Складывание констант происходит только для строк длиной менее 21. (Почему? Представьте себе размер файла `.pyc`, созданного в результате выполнения выражения `'a'*10**10`). [Вот](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) исходный текст реализации для этого.
- Примечание: В Python 3.7 складывание констант было перенесено из оптимизатора peephole в новый оптимизатор AST с некоторыми изменениями в логике, поэтому четвертый фрагмент не работает в Python 3.7. Подробнее об изменении можно прочитать [здесь](https://bugs.python.org/issue11549). - Примечание: В Python 3.7 складывание констант было перенесено из оптимизатора peephole в новый оптимизатор AST с некоторыми изменениями в логике, поэтому четвертый фрагмент не работает в Python 3.7. Подробнее об изменении можно прочитать [здесь](https://bugs.python.org/issue11549).
@ -378,7 +443,7 @@ False
#### 💡 Объяснение: #### 💡 Объяснение:
Согласно https://docs.python.org/3/reference/expressions.html#comparisons Согласно [документации](https://docs.python.org/3/reference/expressions.html#comparisons)
> Формально, если a, b, c, ..., y, z - выражения, а op1, op2, ..., opN - операторы сравнения, то a op1 b op2 c ... y opN z эквивалентно a op1 b и b op2 c и ... y opN z, за исключением того, что каждое выражение оценивается не более одного раза. > Формально, если a, b, c, ..., y, z - выражения, а op1, op2, ..., opN - операторы сравнения, то a op1 b op2 c ... y opN z эквивалентно a op1 b и b op2 c и ... y opN z, за исключением того, что каждое выражение оценивается не более одного раза.
@ -491,7 +556,7 @@ False
Подобная оптимизация применима и к другим **изменяемым** объектам, таким как пустые кортежи. Поскольку списки являются изменяемыми, поэтому `[] is []` вернет `False`, а `() is ()` вернет `True`. Это объясняет наш второй фрагмент. Перейдем к третьему, Подобная оптимизация применима и к другим **изменяемым** объектам, таким как пустые кортежи. Поскольку списки являются изменяемыми, поэтому `[] is []` вернет `False`, а `() is ()` вернет `True`. Это объясняет наш второй фрагмент. Перейдем к третьему,
**И `a`, и `b` ссылаются на один и тот же объект при инициализации одним и тем же значением в одной и той же строкеi**. **И `a`, и `b` ссылаются на один и тот же объект при инициализации одним и тем же значением в одной и той же строке**.
**Вывод** **Вывод**
@ -511,7 +576,7 @@ False
* Когда a и b инициализируются со значением `257` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на него во второй переменной. Если делать это в отдельных строках, интерпретатор не "знает", что объект `257` уже существует. * Когда a и b инициализируются со значением `257` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на него во второй переменной. Если делать это в отдельных строках, интерпретатор не "знает", что объект `257` уже существует.
* Это оптимизация компилятора и относится именно к интерактивной среде. Когда вы вводите две строки в интерпретаторе, они компилируются отдельно, поэтому оптимизируются отдельно. Если выполнить этот пример в файле `.py', поведение будет отличаться, потому что файл компилируется весь сразу. Эта оптимизация не ограничивается целыми числами, она работает и для других неизменяемых типов данных, таких как строки (проверьте пример "Строки - это сложно") и плавающие числа, * Эта оптимизация компилятора относится именно к интерактивной среде. Когда вы вводите две строки в интерпретаторе, они компилируются отдельно, поэтому оптимизируются отдельно. Если выполнить этот пример в файле `.py', поведение будет отличаться, потому что файл компилируется целиком. Эта оптимизация не ограничивается целыми числами, она работает и для других неизменяемых типов данных, таких как строки (смотреть пример "Строки - это сложно") и плавающие числа,
```py ```py
>>> a, b = 257.0, 257.0 >>> a, b = 257.0, 257.0
@ -519,12 +584,12 @@ False
True True
``` ```
* Почему это не сработало в Python 3.7? Абстрактная причина в том, что такие оптимизации компилятора зависят от реализации (т.е. могут меняться в зависимости от версии, ОС и т.д.). Я все еще выясняю, какое именно изменение реализации вызвало проблему, вы можете проверить этот [issue](https://github.com/satwikkansal/wtfpython/issues/100) для получения обновлений. * Почему это не сработало в Python 3.7? Абстрактная причина в том, что такие оптимизации компилятора зависят от реализации (т.е. могут меняться в зависимости от версии, ОС и т.д.). Я все еще выясняю, какое именно изменение реализации вызвало проблему, вы можете следить за этим [issue](https://github.com/satwikkansal/wtfpython/issues/100) для получения обновлений.
--- ---
### ▶ Мистическое хэширование ### ▶ Мистическое хеширование
<!-- Example ID: eb17db53-49fd-4b61-85d6-345c5ca213ff ---> <!-- Example ID: eb17db53-49fd-4b61-85d6-345c5ca213ff --->
1\. 1\.
```py ```py
@ -556,7 +621,7 @@ complex
#### 💡 Объяснение #### 💡 Объяснение
* Уникальность ключей в словаре Python определяется *эквивалентностью*, а не тождеством. Поэтому, даже если `5`, `5.0` и `5 + 0j` являются различными объектами разных типов, поскольку они равны, они не могут находиться в одном и том же `dict` (или `set`). Как только вы вставите любой из них, попытка поиска по любому другому, но эквивалентному ключу будет успешной с исходным сопоставленным значением (а не завершится ошибкой `KeyError`): * Уникальность ключей в словаре Python определяется *эквивалентностью*, а не тождеством. Поэтому, даже если `5`, `5.0` и `5 + 0j` являются различными объектами разных типов, поскольку они эквивалентны, они не могут находиться в одном и том же `dict` (или `set`). Как только вы вставите любой из них, попытка поиска по любому другому, но эквивалентному ключу будет успешной с исходным сопоставленным значением (а не завершится ошибкой `KeyError`):
```py ```py
>>> 5 == 5.0 == 5 + 0j >>> 5 == 5.0 == 5 + 0j
True True
@ -569,7 +634,7 @@ complex
>>> (5 in some_dict) and (5 + 0j in some_dict) >>> (5 in some_dict) and (5 + 0j in some_dict)
True True
``` ```
* Это применимо и во время присваения значения элементу. Поэтому, в выражении `some_dict[5] = "Python"` Python находит существующий элемент с эквивалентным ключом `5.0 -> "Ruby"`, перезаписывает его значение на место, а исходный ключ оставляет в покое. * Это применимо и во время присваивания значения элементу. Поэтому, в выражении `some_dict[5] = "Python"` Python находит существующий элемент с эквивалентным ключом `5.0 -> "Ruby"`, перезаписывает его значение на место, а исходный ключ оставляет в покое.
```py ```py
>>> some_dict >>> some_dict
{5.0: 'Ruby'} {5.0: 'Ruby'}
@ -577,16 +642,17 @@ complex
>>> some_dict >>> some_dict
{5.0: 'Python'} {5.0: 'Python'}
``` ```
* Итак, как мы можем обновить ключ до `5` (вместо `5.0`)? На самом деле мы не можем сделать это обновление на месте, но что мы можем сделать, так это сначала удалить ключ (`del some_dict[5.0]`), а затем установить его (`some_dict[5]`), чтобы получить целое число `5` в качестве ключа вместо плавающего `5.0`, хотя это нужно в редких случаях. * Итак, как мы можем обновить ключ до `5` (вместо `5.0`)? На самом деле мы не можем сделать это обновление на месте, но все же это возможно, нужно сначала удалить ключ (`del some_dict[5.0]`), а затем установить его (`some_dict[5]`), чтобы получить целое число `5` в качестве ключа вместо плавающего `5.0`, хотя это нужно в редких случаях.
* Как Python нашел `5` в словаре, содержащем `5.0`? Python делает это за постоянное время без необходимости сканирования каждого элемента, используя хэш-функции. Когда Python ищет ключ `foo` в словаре, он сначала вычисляет `hash(foo)` (что выполняется в постоянном времени). Поскольку в Python требуется, чтобы объекты, которые одинаковы в сравнении, имели одинаковое хэш-значение (смотри [документацию](https://docs.python.org/3/reference/datamodel.html#object.__hash__)), `5`, `5.0` и `5 + 0j` выполняют это условие.
* Как Python нашел `5` в словаре, содержащем `5.0`? Python делает это за постоянное время без необходимости сканирования каждого элемента, используя хэш-функции. Когда Python ищет ключ `foo` в словаре, он сначала вычисляет `hash(foo)` (что выполняется в постоянном времени). Поскольку в Python требуется, чтобы объекты, которые сравниваются одинаково, имели одинаковое хэш-значение ([docs](https://docs.python.org/3/reference/datamodel.html#object.__hash__) здесь), `5`, `5.0` и `5 + 0j` имеют одинаковое хэш-значение.
```py ```py
>>> 5 == 5.0 == 5 + 0j >>> 5 == 5.0 == 5 + 0j
True True
>>> hash(5) == hash(5.0) == hash(5 + 0j) >>> hash(5) == hash(5.0) == hash(5 + 0j)
True True
``` ```
**Примечание:** Обратное не обязательно верно: Объекты с одинаковыми хэш-значениями сами могут быть неравными. (Это вызывает так называемую [хэш-коллизию](https://en.wikipedia.org/wiki/Collision_(computer_science)) и ухудшает производительность постоянного времени, которую обычно обеспечивает хэширование). **Примечание:** Обратное не обязательно верно: Объекты с одинаковыми хэш-значениями сами могут быть неравными. (Это вызывает так называемую [хэш-коллизию](https://en.wikipedia.org/wiki/Collision_(computer_science)) и ухудшает производительность постоянного времени, которую обычно обеспечивает хеширование).
--- ---
@ -604,14 +670,14 @@ class WTF:
False False
>>> WTF() is WTF() # идентификаторы также различаются >>> WTF() is WTF() # идентификаторы также различаются
False False
>>> hash(WTF()) == hash(WTF()) # хэши тоже должны отличаться >>> hash(WTF()) == hash(WTF()) # хеши тоже должны отличаться
True True
>>> id(WTF()) == id(WTF()) >>> id(WTF()) == id(WTF())
True True
``` ```
#### 💡 Объяснение: #### 💡 Объяснение:
* При вызове `id` Python создал объект класса `WTF` и передал его функции `id`. Функция `id` забирает свой `id` (местоположение в памяти) и выбрасывает объект. Объект уничтожается. * При вызове `id` Python создал объект класса `WTF` и передал его функции `id`. Функция `id` забирает свой `id` (расположение в памяти) и выбрасывает объект. Объект уничтожается.
* Когда мы делаем это дважды подряд, Python выделяет ту же самую область памяти и для второго объекта. Поскольку (в CPython) `id` использует участок памяти в качестве идентификатора объекта, идентификатор двух объектов одинаков. * Когда мы делаем это дважды подряд, Python выделяет ту же самую область памяти и для второго объекта. Поскольку (в CPython) `id` использует участок памяти в качестве идентификатора объекта, идентификатор двух объектов одинаков.
* Таким образом, id объекта уникален только во время жизни объекта. После уничтожения объекта или до его создания, другой объект может иметь такой же id. * Таким образом, id объекта уникален только во время жизни объекта. После уничтожения объекта или до его создания, другой объект может иметь такой же id.
* Но почему выражение с оператором `is` равно `False`? Давайте посмотрим с помощью этого фрагмента. * Но почему выражение с оператором `is` равно `False`? Давайте посмотрим с помощью этого фрагмента.
@ -641,7 +707,7 @@ True
--- ---
### ▶ Беспорядок внутри порядка * ### ▶ Беспорядок внутри порядка *
<!-- Example ID: 91bff1f8-541d-455a-9de4-6cd8ff00ea66 ---> <!-- Example ID: 91bff1f8-541d-455a-9de4-6cd8ff00ea66 --->
```py ```py
from collections import OrderedDict from collections import OrderedDict
@ -657,13 +723,13 @@ another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a';
class DictWithHash(dict): class DictWithHash(dict):
""" """
A dict that also implements __hash__ magic. Словарь с реализованным методом __hash__.
""" """
__hash__ = lambda self: 0 __hash__ = lambda self: 0
class OrderedDictWithHash(OrderedDict): class OrderedDictWithHash(OrderedDict):
""" """
An OrderedDict that also implements __hash__ magic. OrderedDict с реализованным методом __hash__.
""" """
__hash__ = lambda self: 0 __hash__ = lambda self: 0
``` ```
@ -677,7 +743,7 @@ True
>>> ordered_dict == another_ordered_dict # почему же c != a ?? >>> ordered_dict == another_ordered_dict # почему же c != a ??
False False
# Мы все знаем, что множество состоит только из уникальных элементов, # Мы все знаем, что множество состоит из уникальных элементов,
# давайте попробуем составить множество из этих словарей и посмотрим, что получится... # давайте попробуем составить множество из этих словарей и посмотрим, что получится...
>>> len({dictionary, ordered_dict, another_ordered_dict}) >>> len({dictionary, ordered_dict, another_ordered_dict})
@ -695,7 +761,7 @@ TypeError: unhashable type: 'dict'
>>> another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a'; >>> another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a';
>>> len({dictionary, ordered_dict, another_ordered_dict}) >>> len({dictionary, ordered_dict, another_ordered_dict})
1 1
>>> len({ordered_dict, another_ordered_dict, dictionary}) # changing the order >>> len({ordered_dict, another_ordered_dict, dictionary}) # изменим порядок элементов
2 2
``` ```
@ -703,7 +769,7 @@ TypeError: unhashable type: 'dict'
#### 💡 Объяснение: #### 💡 Объяснение:
- Переходное (интрантизивное) равенство между `dictionary`, `ordered_dict` и `another_ordered_dict` не выполняется из-за реализации магического метода `__eq__` в классе `OrderedDict`. Перевод цитаты из [документации](https://docs.python.org/3/library/collections.html#ordereddict-objects) - Переходное (интранзитивное) равенство между `dictionary`, `ordered_dict` и `another_ordered_dict` не выполняется из-за реализации магического метода `__eq__` в классе `OrderedDict`. Перевод цитаты из [документации](https://docs.python.org/3/library/collections.html#ordereddict-objects)
> Тесты равенства между объектами OrderedDict чувствительны к порядку и реализуются как `list(od1.items())==list(od2.items())`. Тесты на равенство между объектами `OrderedDict` и другими объектами Mapping нечувствительны к порядку, как обычные словари. > Тесты равенства между объектами OrderedDict чувствительны к порядку и реализуются как `list(od1.items())==list(od2.items())`. Тесты на равенство между объектами `OrderedDict` и другими объектами Mapping нечувствительны к порядку, как обычные словари.
- Причина такого поведения равенства в том, что оно позволяет напрямую подставлять объекты `OrderedDict` везде, где используется обычный словарь. - Причина такого поведения равенства в том, что оно позволяет напрямую подставлять объекты `OrderedDict` везде, где используется обычный словарь.
@ -794,7 +860,7 @@ Iteration 0
#### 💡 Объяснение: #### 💡 Объяснение:
- Когда один из операторов `return`, `break` или `continue` выполняется в блоке `try` оператора "try...finally", на выходе также выполняется пункт `finally`. - Когда один из операторов `return`, `break` или `continue` выполняется в блоке `try` оператора "try...finally", на выходе также выполняется блок `finally`.
- Возвращаемое значение функции определяется последним выполненным оператором `return`. Поскольку блок `finally` выполняется всегда, оператор `return`, выполненный в блоке `finally`, всегда будет последним. - Возвращаемое значение функции определяется последним выполненным оператором `return`. Поскольку блок `finally` выполняется всегда, оператор `return`, выполненный в блоке `finally`, всегда будет последним.
- Предостережение - если в блоке `finally` выполняется оператор `return` или `break`, то временно сохраненное исключение отбрасывается. - Предостережение - если в блоке `finally` выполняется оператор `return` или `break`, то временно сохраненное исключение отбрасывается.
@ -966,7 +1032,7 @@ board = [row] * 3
[['X', '', ''], ['X', '', ''], ['X', '', '']] [['X', '', ''], ['X', '', ''], ['X', '', '']]
``` ```
Мы же не назначили три `"Х"`? Мы же не назначали три `"Х"`?
#### 💡 Объяснение: #### 💡 Объяснение:
@ -1006,7 +1072,7 @@ for x in range(7):
funcs_results = [func() for func in funcs] funcs_results = [func() for func in funcs]
``` ```
**Вывод (Python version):** **Вывод:**
```py ```py
>>> results >>> results
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4, 5, 6]
@ -1039,7 +1105,7 @@ ClosureVars(nonlocals={}, globals={'x': 6}, builtins={}, unbound=set())
[42, 42, 42, 42, 42, 42, 42] [42, 42, 42, 42, 42, 42, 42]
``` ```
* Чтобы получить желаемое поведение, вы можете передать переменную цикла как именованную переменную в функцию. **Почему это работает?** Потому что это определит переменную *внутри* области видимости функции. Она больше не будет обращаться к глобальной области видимости для поиска значения переменной, а создаст локальную переменную, которая будет хранить значение `x` в данный момент времени. * Чтобы получить желаемое поведение, вы можете передать переменную цикла как именованную аргумент в функцию. **Почему это работает?** Потому что это определит переменную *внутри* области видимости функции. Она больше не будет обращаться к глобальной области видимости для поиска значения переменной, а создаст локальную переменную, которая будет хранить значение `x` в данный момент времени.
```py ```py
funcs = [] funcs = []
@ -1079,7 +1145,7 @@ True
True True
``` ```
Так какой же базовый класс является "окончательным"? Кстати, это еще не все, Так какой же базовый класс является "родительским"? Кстати, это еще не все,
2\. 2\.
@ -1137,12 +1203,11 @@ False
* Отношения подклассов не обязательно являются транзитивными в Python. Можно переопределить магический метод `__subclasscheck__` в метаклассе. * Отношения подклассов не обязательно являются транзитивными в Python. Можно переопределить магический метод `__subclasscheck__` в метаклассе.
* Когда вызывается `issubclass(cls, Hashable)`, он просто ищет не-фальшивый метод "`__hash__`" в `cls` или во всем, от чего он наследуется. * Когда вызывается `issubclass(cls, Hashable)`, он просто ищет не-фальшивый метод "`__hash__`" в `cls` или во всем, от чего он наследуется.
* Поскольку `object` является хэшируемым, а `list` - нехэшируемым, это нарушает отношение транзитивности. * Поскольку `object` является хэшируемым, а `list` - нет, это нарушает отношение транзитивности.
* Более подробное объяснение можно найти [здесь] (https://www.naftaliharris.com/blog/python-subclass-intransitivity/). * Более подробное объяснение можно найти [здесь](https://www.naftaliharris.com/blog/python-subclass-intransitivity/).
--- ---
### ▶ Равенство и тождество методов ### ▶ Равенство и тождество методов
<!-- Example ID: 94802911-48fe-4242-defa-728ae893fa32 ---> <!-- Example ID: 94802911-48fe-4242-defa-728ae893fa32 --->
@ -1202,7 +1267,7 @@ True
#### 💡 Объяснение #### 💡 Объяснение
* Функции являются [дескрипторами](https://docs.python.org/3/howto/descriptor.html). Всякий раз, когда к функции обращаются как к * Функции являются [дескрипторами](https://docs.python.org/3/howto/descriptor.html). Всякий раз, когда к функции обращаются как к
атрибута, вызывается дескриптор, создавая объект метода, который "связывает" функцию с объектом, владеющим атрибутом. При вызове метод вызывает функцию, неявно передавая связанный объект в качестве первого аргумента атрибуту, вызывается дескриптор, создавая объект метода, который "связывает" функцию с объектом, владеющим атрибутом. При вызове метод вызывает функцию, неявно передавая связанный объект в качестве первого аргумента
(именно так мы получаем `self` в качестве первого аргумента, несмотря на то, что не передаем его явно). (именно так мы получаем `self` в качестве первого аргумента, несмотря на то, что не передаем его явно).
```py ```py
>>> o1.method >>> o1.method
@ -1338,7 +1403,7 @@ True
#### 💡 Объяснение #### 💡 Объяснение
- В обычной строке обратная слэш используется для экранирования символов, которые могут иметь специальное значение (например, одинарная кавычка, двойная кавычка и сам обратный слэш). - В обычной строке обратный слэш используется для экранирования символов, которые могут иметь специальное значение (например, одинарная кавычка, двойная кавычка и сам обратный слэш).
```py ```py
>>> "wt\"f" >>> "wt\"f"
'wt"f' 'wt"f'
@ -1355,12 +1420,12 @@ True
>>> print(r"\\n") >>> print(r"\\n")
'\\n' '\\n'
``` ```
- Это означает, что когда синтаксический анализатор встречает обратный слэш в необработанной строке, он ожидает, что за ней последует другой символ. А в нашем случае (`print(r"\")`) обратная слэш экранирует двойную кавычку, оставив парсер без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слеш не работает в конце необработанной строки. - Это означает, что когда синтаксический анализатор встречает обратный слэш в необработанной строке, он ожидает, что за ней последует другой символ. А в нашем случае (`print(r"\")`) обратный слэш экранирует двойную кавычку, оставив синтаксический анализатор без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слэш не работает в конце необработанной строки.
-- ---
### ▶ Не узел! (eng. not knot!) ### ▶ Не узел! (англ. not knot!)
<!-- Example ID: 7034deb1-7443-417d-94ee-29a800524de8 ---> <!-- Example ID: 7034deb1-7443-417d-94ee-29a800524de8 --->
```py ```py
x = True x = True
@ -1383,12 +1448,12 @@ SyntaxError: invalid syntax
* Старшинство операторов влияет на выполнение выражения, и оператор `==` имеет более высокий приоритет, чем оператор `not` в Python. * Старшинство операторов влияет на выполнение выражения, и оператор `==` имеет более высокий приоритет, чем оператор `not` в Python.
* Поэтому `not x == y` эквивалентно `not (x == y)`, что эквивалентно `not (True == False)`, в итоге равное `True`. * Поэтому `not x == y` эквивалентно `not (x == y)`, что эквивалентно `not (True == False)`, в итоге равное `True`.
* Но `x == not y` вызывает `SyntaxError`, потому что его можно считать эквивалентным `(x == not) y`, а не `x == (not y)`, что можно было бы ожидать на первый взгляд. * Но `x == not y` вызывает `SyntaxError`, потому что его можно считать эквивалентным `(x == not) y`, а не `x == (not y)`, что можно было бы ожидать на первый взгляд.
* Парсер ожидал, что ключевое слово `not` будет частью оператора `not in` (потому что оба оператора `==` и `not in` имеют одинаковый приоритет), но после того, как он не смог найти ключевое слово `in`, следующее за `not`, он выдает `SyntaxError`. * Синтаксический анализатор (англ. parser) ожидал, что ключевое слово `not` будет частью оператора `not in` (потому что оба оператора `==` и `not in` имеют одинаковый приоритет), но после того, как он не смог найти ключевое слово `in`, следующее за `not`, он выдает `SyntaxError`.
--- ---
### ▶ Строки наполовину в тройных кавычках ### ▶ Строки, наполовину обернутые в тройные кавычки
<!-- Example ID: c55da3e2-1034-43b9-abeb-a7a970a2ad9e ---> <!-- Example ID: c55da3e2-1034-43b9-abeb-a7a970a2ad9e --->
**Вывод:** **Вывод:**
```py ```py
@ -1503,7 +1568,7 @@ I have lost faith in truth!
* Изначально в Python не было типа `bool` (использовали 0 для false и ненулевое значение 1 для true). В версиях 2.x были добавлены `True`, `False` и тип `bool`, но для обратной совместимости `True` и `False` нельзя было сделать константами. Они просто были встроенными переменными, и их можно было переназначить. * Изначально в Python не было типа `bool` (использовали 0 для false и ненулевое значение 1 для true). В версиях 2.x были добавлены `True`, `False` и тип `bool`, но для обратной совместимости `True` и `False` нельзя было сделать константами. Они просто были встроенными переменными, и их можно было переназначить.
* Python 3 был несовместим с предыдущими версиями, эту проблему наконец-то исправили, и поэтому последний фрагмент не будет работать с Python 3.x! * Python 3 несовместим с предыдущими версиями, эту проблему наконец-то исправили, и поэтому последний фрагмент не будет работать с Python 3.x!
--- ---
@ -1651,7 +1716,7 @@ def some_func(x):
[] []
``` ```
То же самое, это тоже не сработало. Что происходит? Опять не сработало. Что происходит?
#### 💡 Объяснение: #### 💡 Объяснение:
@ -1659,7 +1724,7 @@ def some_func(x):
> "... `return expr` в генераторе вызывает исключение `StopIteration(expr)` при выходе из генератора." > "... `return expr` в генераторе вызывает исключение `StopIteration(expr)` при выходе из генератора."
+ В случае `some_func(3)` `StopIteration` возникает в начале из-за оператора `return`. Исключение `StopIteration` автоматически перехватывается внутри обертки `list(...)` и цикла `for`. Поэтому два вышеприведенных фрагмента приводят к пустому списку. + В случае `some_func(3)` `StopIteration` возникает в начале из-за оператора `return`. Исключение `StopIteration` автоматически перехватывается внутри обертки `list(...)` и цикла `for`. Поэтому два вышеприведенных фрагмента возвращают пустой список.
+ Чтобы получить `["wtf"]` из генератора `some_func`, нужно перехватить исключение `StopIteration`. + Чтобы получить `["wtf"]` из генератора `some_func`, нужно перехватить исключение `StopIteration`.
@ -1721,7 +1786,7 @@ nan
```py ```py
>>> x = float('nan') >>> x = float('nan')
>>> y = x / x >>> y = x / x
>>> y is y # идендичность сохраняется >>> y is y # идентичность сохраняется
True True
>>> y == y # сравнение ложно для y >>> y == y # сравнение ложно для y
False False
@ -1733,7 +1798,7 @@ True
- `'inf'` и `'nan'` - это специальные строки (без учета регистра), которые при явном приведении к типу `float` используются для представления математической "бесконечности" и "не число" соответственно. - `'inf'` и `'nan'` - это специальные строки (без учета регистра), которые при явном приведении к типу `float` используются для представления математической "бесконечности" и "не число" соответственно.
- Согласно стандартам IEEE `NaN != NaN`, но соблюдение этого правила нарушает предположение о рефлексивности элемента коллекции в Python, то есть если `x` является частью коллекции, такой как `list`, реализации, методы сравнения предполагают, что `x == x`. Поэтому при сравнении элементов сначала сравниваются их идентификаторы (так как это быстрее), а значения сравниваются только при несовпадении идентификаторов. Следующий фрагмент сделает вещи более ясными: - Согласно стандартам IEEE, `NaN != NaN`, но соблюдение этого правила нарушает предположение о рефлексивности элемента коллекции в Python, то есть если `x` является частью коллекции, такой как `list`, реализации методов сравнения предполагают, что `x == x`. Поэтому при сравнении элементов сначала сравниваются их идентификаторы (так как это быстрее), а значения сравниваются только при несовпадении идентификаторов. Следующий фрагмент сделает вещи более ясными:
```py ```py
>>> x = float('nan') >>> x = float('nan')
@ -1753,7 +1818,7 @@ True
--- ---
### ▶ Мутируем немутируемое! ### ▶ Изменяем неизменяемое!
<!-- Example ID: 15a9e782-1695-43ea-817a-a9208f6bb33d ---> <!-- Example ID: 15a9e782-1695-43ea-817a-a9208f6bb33d --->
@ -1783,8 +1848,7 @@ TypeError: 'tuple' object does not support item assignment
* Перевод цитаты из [документации](https://docs.python.org/3/reference/datamodel.html) * Перевод цитаты из [документации](https://docs.python.org/3/reference/datamodel.html)
> Неизменяемые последовательности > Объект неизменяемого типа последовательности не может измениться после создания. (Если объект содержит ссылки на другие объекты, эти объекты могут быть изменяемыми и могут быть изменены; однако набор объектов, на которые непосредственно ссылается неизменяемый объект, не может изменяться.)
Объект неизменяемого типа последовательности не может измениться после создания. (Если объект содержит ссылки на другие объекты, эти объекты могут быть изменяемыми и могут быть изменены; однако набор объектов, на которые непосредственно ссылается неизменяемый объект, не может изменяться.)
* Оператор `+=` изменяет список на месте. Присваивание элемента не работает, но когда возникает исключение, элемент уже был изменен на месте. * Оператор `+=` изменяет список на месте. Присваивание элемента не работает, но когда возникает исключение, элемент уже был изменен на месте.
* Также есть объяснение в официальном [Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works). * Также есть объяснение в официальном [Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works).
@ -1836,30 +1900,30 @@ NameError: name 'e' is not defined
del N del N
``` ```
Это означает, что исключению должно быть присвоено другое имя, чтобы на него можно было ссылаться после завершения блока `except`. Исключения очищаются, потому что с прикрепленным к ним трейсбэком они образуют цикл ссылок со стеком вызовов, сохраняя все локальные объекты в этой стэке до следующей сборки мусора. Это означает, что исключению должно быть присвоено другое имя, чтобы на него можно было ссылаться после завершения блока `except`. Исключения очищаются, потому что с прикрепленным к ним трейсбэком они образуют цикл ссылок со стэком вызовов, сохраняя все локальные объекты в этой стэке до следующей сборки мусора.
* В Python clauses не имеют области видимости. В примере все объекты в одной области видимости, а переменная `e` была удалена из-за выполнения блока `except`. Этого нельзя сказать о функциях, которые имеют отдельные внутренние области видимости. Пример ниже иллюстрирует это: * В Python clauses не имеют области видимости. В примере все объекты в одной области видимости, а переменная `e` была удалена из-за выполнения блока `except`. Этого нельзя сказать о функциях, которые имеют отдельные внутренние области видимости. Пример ниже иллюстрирует это:
```py ```py
def f(x): def f(x):
del(x) del(x)
print(x) print(x)
x = 5 x = 5
y = [5, 4, 3] y = [5, 4, 3]
``` ```
**Результат:** **Результат:**
```py ```py
>>> f(x) >>> f(x)
UnboundLocalError: local variable 'x' referenced before assignment UnboundLocalError: local variable 'x' referenced before assignment
>>> f(y) >>> f(y)
UnboundLocalError: local variable 'x' referenced before assignment UnboundLocalError: local variable 'x' referenced before assignment
>>> x >>> x
5 5
>>> y >>> y
[5, 4, 3] [5, 4, 3]
``` ```
* В Python 2.x, имя переменной `e` назначается на экземпляр `Exception()`, и при попытки вывести значение `e` ничего не выводится. * В Python 2.x, имя переменной `e` назначается на экземпляр `Exception()`, и при попытки вывести значение `e` ничего не выводится.
@ -1954,13 +2018,9 @@ a, b = a[b] = {}, 5
> Оператор присваивания исполняет список выражений (помните, что это может быть одно выражение или список, разделенный запятыми, в последнем случае получается кортеж) и присваивает единственный результирующий объект каждому из целевых списков, слева направо. > Оператор присваивания исполняет список выражений (помните, что это может быть одно выражение или список, разделенный запятыми, в последнем случае получается кортеж) и присваивает единственный результирующий объект каждому из целевых списков, слева направо.
* `+` в `(target_list "=")+` означает, что может быть **один или более** целевых списков. В данном случае целевыми списками являются `a, b` и `a[b]` (обратите внимание, что список выражений ровно один, в нашем случае это `{}, 5`). * `+` в `(target_list "=")+` означает, что может быть **один или более** целевых списков. В данном случае целевыми списками являются `a, b` и `a[b]` (обратите внимание, что список выражений ровно один, в нашем случае это `{}, 5`).
* После исполнения списка выражений его значение распаковывается в целевые списки **слева направо**. Так, в нашем случае сначала кортеж `{}, 5` распаковывается в `a, b`, и теперь у нас есть `a = {}` и `b = 5`. * После исполнения списка выражений его значение распаковывается в целевые списки **слева направо**. Так, в нашем случае сначала кортеж `{}, 5` распаковывается в `a, b`, и теперь у нас есть `a = {}` и `b = 5`.
* Теперь `a` имеет значение `{}`, которое является изменяемым объектом. * Теперь `a` имеет значение `{}`, которое является изменяемым объектом.
* Вторым целевым списком является `a[b]` (вы можете ожидать, что это вызовет ошибку, поскольку `a` и `b` не были определены в предыдущих утверждениях. Но помните, мы только что присвоили `a` значение `{}` и `b` - `5`). * Вторым целевым списком является `a[b]` (вы можете ожидать, что это вызовет ошибку, поскольку `a` и `b` не были определены в предыдущих утверждениях. Но помните, мы только что присвоили `a` значение `{}` и `b` - `5`).
* Теперь мы устанавливаем ключ `5` в словаре в кортеж `({}, 5)`, создавая круговую ссылку (`{...}` в выводе ссылается на тот же объект, на который уже ссылается `a`). Другим более простым примером круговой ссылки может быть * Теперь мы устанавливаем ключ `5` в словаре в кортеж `({}, 5)`, создавая круговую ссылку (`{...}` в выводе ссылается на тот же объект, на который уже ссылается `a`). Другим более простым примером круговой ссылки может быть
```py ```py
@ -2010,7 +2070,7 @@ ValueError: Exceeds the limit (4300) for integer string conversion:
#### 💡 Объяснение: #### 💡 Объяснение:
Этот вызов `int()` прекрасно работает в Python 3.10.6 и вызывает ошибку `ValueError` в Python 3.10.8, 3.11. Обратите внимание, что Python все еще может работать с большими целыми числами. Ошибка возникает только при преобразовании между целыми числами и строками. Этот вызов `int()` прекрасно работает в Python 3.10.6 и вызывает ошибку `ValueError` в Python 3.10.8, 3.11. Обратите внимание, что Python все еще может работать с большими целыми числами. Ошибка возникает только при преобразовании между целыми числами и строками.
К счастью, вы можете увеличить предел допустимого количества цифр. Для этого можно воспользоваться одним из следующих способов: К счастью, вы можете увеличить предел допустимого количества цифр. Для этого можно воспользоваться одним из следующих способов:
- `-X int_max_str_digits` - флаг командной строкиcommand-line flag - `-X int_max_str_digits` - флаг командной строки
- `set_int_max_str_digits()` - функция из модуля `sys` - `set_int_max_str_digits()` - функция из модуля `sys`
- `PYTHONINTMAXSTRDIGITS` - переменная окружения - `PYTHONINTMAXSTRDIGITS` - переменная окружения
@ -2230,7 +2290,7 @@ for idx, item in enumerate(list_4):
>>> some_list = [1, 2, 3, 4] >>> some_list = [1, 2, 3, 4]
>>> id(some_list) >>> id(some_list)
139798789457608 139798789457608
>>> id(some_list[:]) # Notice that python creates new object for sliced list. >>> id(some_list[:]) # Обратите внимание, создается новый объект из среза списка
139798779601192 139798779601192
``` ```
@ -2239,7 +2299,7 @@ for idx, item in enumerate(list_4):
* `remove` удаляет первое подходящее значение, а не конкретный индекс, вызывает `ValueError`, если значение не найдено. * `remove` удаляет первое подходящее значение, а не конкретный индекс, вызывает `ValueError`, если значение не найдено.
* `pop` удаляет элемент по определенному индексу и возвращает его, вызывает `IndexError`, если указан неверный индекс. * `pop` удаляет элемент по определенному индексу и возвращает его, вызывает `IndexError`, если указан неверный индекс.
**Почему на выходе получается `[2, 4]`? **Почему на выходе получается `[2, 4]`?**
- Проход по списку выполняется индекс за индексом, и когда мы удаляем `1` из `list_2` или `list_4`, содержимое списков становится `[2, 3, 4]`. Оставшиеся элементы сдвинуты вниз, то есть `2` находится на индексе 0, а `3` - на индексе 1. Поскольку на следующей итерации будет просматриваться индекс 1 (который и есть `3`), `2` будет пропущен полностью. Аналогичное произойдет с каждым альтернативным элементом в последовательности списка. - Проход по списку выполняется индекс за индексом, и когда мы удаляем `1` из `list_2` или `list_4`, содержимое списков становится `[2, 3, 4]`. Оставшиеся элементы сдвинуты вниз, то есть `2` находится на индексе 0, а `3` - на индексе 1. Поскольку на следующей итерации будет просматриваться индекс 1 (который и есть `3`), `2` будет пропущен полностью. Аналогичное произойдет с каждым альтернативным элементом в последовательности списка.
* Объяснение примера можно найти на [StackOverflow](https://stackoverflow.com/questions/45946228/what-happens-when-you-try-to-delete-a-list-element-while-iterating-over-it). * Объяснение примера можно найти на [StackOverflow](https://stackoverflow.com/questions/45946228/what-happens-when-you-try-to-delete-a-list-element-while-iterating-over-it).
@ -2354,7 +2414,7 @@ print(x, ': x in global')
#### 💡 Объяснение: #### 💡 Объяснение:
- В Python циклы for используют область видимости, в которой они существуют, и оставляют свою определенную переменную цикла после завершения. Это также относится к случаям, когда мы явно определили переменную цикла for в глобальном пространстве имен. В этом случае будет произведена перепривязка существующей переменной. - В Python циклы for используют область видимости, в которой они существуют, и оставляют свою определенную переменную цикла после завершения. Это также относится к случаям, когда мы явно определили переменную цикла for в глобальном пространстве имен. В этом случае будет произведена повторная привязка существующей переменной.
- Различия в выводе интерпретаторов Python 2.x и Python 3.x для примера с пониманием списков можно объяснить следующим изменением, задокументированным в журнале изменений [What's New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html): - Различия в выводе интерпретаторов Python 2.x и Python 3.x для примера с пониманием списков можно объяснить следующим изменением, задокументированным в журнале изменений [What's New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html):
@ -2386,7 +2446,7 @@ def some_func(default_arg=[]):
#### 💡 Объяснение: #### 💡 Объяснение:
- Изменяемые аргументы функций по умолчанию в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется недавно присвоенное им значение. Когда мы явно передали `[]` в `some_func в качестве аргумента, значение по умолчанию переменной `default_arg` не было использовано, поэтому функция вернулась, как и ожидалось. - Изменяемые аргументы функций по умолчанию в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется недавно присвоенное им значение. Когда мы явно передали `[]` в `some_func` в качестве аргумента, значение по умолчанию переменной `default_arg` не было использовано, поэтому функция вернулась, как и ожидалось.
```py ```py
def some_func(default_arg=[]): def some_func(default_arg=[]):
@ -2396,7 +2456,7 @@ def some_func(default_arg=[]):
**Результат:** **Результат:**
```py ```py
>>> some_func.__defaults__ # Выражение выведет значения стандартных аргументов фукнции >>> some_func.__defaults__ # Выражение выведет значения стандартных аргументов функции
([],) ([],)
>>> some_func() >>> some_func()
>>> some_func.__defaults__ >>> some_func.__defaults__
@ -2580,7 +2640,7 @@ class SomeClass:
#### 💡 Объяснение #### 💡 Объяснение
- Области видимости, вложенные внутрь определения класса, игнорируют имена, связанные на уровне класса. - Области видимости, вложенные внутрь определения класса, игнорируют имена, связанные на уровне класса.
- Выражение-генератор имеет свою собственную область видимости. - Выражение-генератор имеет свою собственную область видимости.
- Начиная с версии Python 3.X, списковые вычисления также имеют свою собственную область видимости. - Начиная с версии Python 3.X, списковые выражения (list comprehensions) также имеют свою собственную область видимости.
--- ---
@ -2716,7 +2776,7 @@ b = "javascript"
**Результат:** **Результат:**
```py ```py
# assert выражение с сообщением об ошиб # assert выражение с сообщением об ошибке
>>> assert(a == b, "Both languages are different") >>> assert(a == b, "Both languages are different")
# Исключение AssertionError не возникло # Исключение AssertionError не возникло
``` ```
@ -2939,7 +2999,7 @@ False
(tuple, list) (tuple, list)
``` ```
- В отличие от метода `sorted, метод `reversed` возвращает итератор. Почему? Потому что сортировка требует, чтобы итератор либо изменялся на месте, либо использовал дополнительный контейнер (список), в то время как реверсирование может работать просто путем итерации от последнего индекса к первому. - В отличие от метода `sorted`, метод `reversed` возвращает итератор. Почему? Потому что сортировка требует, чтобы итератор либо изменялся на месте, либо использовал дополнительный контейнер (список), в то время как реверсирование может работать просто путем итерации от последнего индекса к первому.
- Поэтому при сравнении `sorted(y) == sorted(y)` первый вызов `sorted()` будет потреблять итератор `y`, а следующий вызов просто вернет пустой список. - Поэтому при сравнении `sorted(y) == sorted(y)` первый вызов `sorted()` будет потреблять итератор `y`, а следующий вызов просто вернет пустой список.
@ -2992,7 +3052,7 @@ if noon_time:
Секция содержит менее известные интересные нюансы работы Python, которые неизвестны большинству новичков. Секция содержит менее известные интересные нюансы работы Python, которые неизвестны большинству новичков.
### ▶ Python, можешь ли ты помочь взлелеть? ### ▶ Python, можешь ли ты помочь взлететь?
<!-- Example ID: a92f3645-1899-4d50-9721-0031be4aec3f ---> <!-- Example ID: a92f3645-1899-4d50-9721-0031be4aec3f --->
Что ж, поехали Что ж, поехали
@ -3007,7 +3067,7 @@ Sshh... It's a super-secret.
+ Модуль `antigravity` - одно из немногих пасхальных яиц, выпущенных разработчиками Python. + Модуль `antigravity` - одно из немногих пасхальных яиц, выпущенных разработчиками Python.
+ `import antigravity` открывает веб-браузер, указывающий на [классический комикс XKCD](https://xkcd.com/353/) о Python. + `import antigravity` открывает веб-браузер, указывающий на [классический комикс XKCD](https://xkcd.com/353/) о Python.
+ Это еще не все. Внутри пасхального яйца находится **еще одно пасхальное яйцо**. Если вы посмотрите на [код](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), там определена функция, которая якобы реализует [алгоритм геохашинга XKCD](https://xkcd.com/426/). + Это еще не все. Внутри пасхального яйца находится **еще одно пасхальное яйцо**. Если вы посмотрите на [код](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), там определена функция, которая якобы реализует алгоритм [XKCD](https://xkcd.com/426/).
--- ---
@ -3164,7 +3224,7 @@ True
### ▶ Да, оно существует! ### ▶ Да, оно существует!
<!-- Example ID: 4286db3d-1ea7-47c9-8fb6-a9a04cac6e49 ---> <!-- Example ID: 4286db3d-1ea7-47c9-8fb6-a9a04cac6e49 --->
**Ключевое слово `else` в связвке с циклом `for`.** Один из стандартных примеров: **Ключевое слово `else` в связке с циклом `for`.** Один из стандартных примеров:
```py ```py
def does_exists_num(l, to_find): def does_exists_num(l, to_find):
@ -3239,7 +3299,7 @@ Ellipsis
- Многоточие может использоваться в нескольких случаях, - Многоточие может использоваться в нескольких случаях,
+ В качестве заполнителя для кода, который еще не написан (аналогично оператору `pass`) + В качестве заполнителя для кода, который еще не написан (аналогично оператору `pass`)
+ В синтаксисе срезов (slices) для представления полных срезов в оставшемся направлении + В синтаксисе срезов (slices) для представления полных срезов в оставшемся направлении
``py ```py
>>> import numpy as np >>> import numpy as np
>>> three_dimensional_array = np.arange(8).reshape(2, 2, 2) >>> three_dimensional_array = np.arange(8).reshape(2, 2, 2)
array([ array([
@ -3264,7 +3324,7 @@ Ellipsis
[5, 7]]) [5, 7]])
``` ```
Примечание: это будет работать для любого количества измерений. Можно даже выбрать срез в первом и последнем измерении и игнорировать средние (`n_dimensional_array[firs_dim_slice, ..., last_dim_slice]`) Примечание: это будет работать для любого количества измерений. Можно даже выбрать срез в первом и последнем измерении и игнорировать средние (`n_dimensional_array[firs_dim_slice, ..., last_dim_slice]`)
+ В [подсказках типов](https://docs.python.org/3/library/typing.html) для указания только части типа (например, `(Callable[..., int]` или `Tuple[str, ...]`)) + В [подсказках типов](https://docs.python.org/3/library/typing.html) для указания только части типа (например, `Callable[..., int]` или `Tuple[str, ...]`)
+ Вы также можете использовать `Ellipsis` в качестве аргумента функции по умолчанию (в случаях, когда вы хотите провести различие между сценариями "аргумент не передан" и "значение не передано"). + Вы также можете использовать `Ellipsis` в качестве аргумента функции по умолчанию (в случаях, когда вы хотите провести различие между сценариями "аргумент не передан" и "значение не передано").
--- ---
@ -3483,7 +3543,7 @@ def square(x):
## Секция: Разное ## Секция: Разное
### ▶ `+=` быстрее ### ▶ `+=` быстрее `+`
<!-- Example ID: bfd19c60-a807-4a26-9598-4912b86ddb36 ---> <!-- Example ID: bfd19c60-a807-4a26-9598-4912b86ddb36 --->
```py ```py
@ -3587,7 +3647,7 @@ def convert_list_to_string(l, iters):
>>> %timeit -n100 add_string_with_plus(1000) >>> %timeit -n100 add_string_with_plus(1000)
388 µs ± 22.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 388 µs ± 22.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit -n100 add_string_with_plus(10000) # Quadratic increase in execution time >>> %timeit -n100 add_string_with_plus(10000) # Квадратичное увеличение времени выполнения
9 ms ± 298 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 9 ms ± 298 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
``` ```
@ -3627,7 +3687,7 @@ KeyError: 1
#### 💡 Объяснение: #### 💡 Объяснение:
+ В CPython есть общая функция поиска по словарю, которая работает со всеми типами ключей (`str`, `int`, любой объект ...), и специализированная для распространенного случая словарей, состоящих только из `str`-ключей. + В CPython есть общая функция поиска по словарю, которая работает со всеми типами ключей (`str`, `int`, любой объект ...), и специализированная для распространенного случая словарей, состоящих только из `str`-ключей.
+ Специализированная функция (названная `lookdict_unicode` в [исходный код CPython](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841)) знает, что все существующие ключи (включая искомый ключ) являются строками, и использует более быстрое и простое сравнение строк для сравнения ключей, вместо вызова метода `__eq__`. + Специализированная функция (названная `lookdict_unicode` в [CPython](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841)) знает, что все существующие ключи (включая искомый ключ) являются строками, и использует более быстрое и простое сравнение строк для сравнения ключей, вместо вызова метода `__eq__`.
+ При первом обращении к экземпляру `dict` с ключом, не являющимся `str`, он модифицируется, чтобы в дальнейшем для поиска использовалась общая функция. + При первом обращении к экземпляру `dict` с ключом, не являющимся `str`, он модифицируется, чтобы в дальнейшем для поиска использовалась общая функция.
+ Этот процесс не обратим для конкретного экземпляра `dict`, и ключ даже не обязательно должен существовать в словаре. Поэтому попытка неудачного поиска имеет тот же эффект. + Этот процесс не обратим для конкретного экземпляра `dict`, и ключ даже не обязательно должен существовать в словаре. Поэтому попытка неудачного поиска имеет тот же эффект.
@ -3706,7 +3766,7 @@ def dict_size(o):
* Несколько странных, но семантически правильных утверждений: * Несколько странных, но семантически правильных утверждений:
+ `[] = ()` - семантически корректное утверждение (распаковка пустого `кортежа` в пустой `список`) + `[] = ()` - семантически корректное утверждение (распаковка пустого `кортежа` в пустой `список`)
+ `'a'[0][0][0][0][0]` также является семантически корректным утверждением, поскольку в Python строки являются [последовательностями](https://docs.python.org/3/glossary.html#term-sequence)(итерируемыми объектами, поддерживающими доступ к элементам с использованием целочисленных индексов). + `'a'[0][0][0][0][0]` также является семантически корректным утверждением, поскольку в Python строки являются [последовательностями](https://docs.python.org/3/glossary.html#term-sequence) (итерируемыми объектами, поддерживающими доступ к элементам с использованием целочисленных индексов).
+ `3 --0-- 5 == 8` и `--5 == 5` - оба семантически корректные утверждения и имеют значение `True`. + `3 --0-- 5 == 8` и `--5 == 5` - оба семантически корректные утверждения и имеют значение `True`.
* Учитывая, что `a` - это число, `++a` и `--a` являются корректными утверждениями Python, но ведут себя не так, как аналогичные утверждения в таких языках, как C, C++ или Java. * Учитывая, что `a` - это число, `++a` и `--a` являются корректными утверждениями Python, но ведут себя не так, как аналогичные утверждения в таких языках, как C, C++ или Java.