mirror of
https://github.com/satwikkansal/wtfpython
synced 2024-11-24 03:54:25 +01:00
Fix typos and spelling
This commit is contained in:
parent
5bbdcdd5a5
commit
d0dd3ad2b7
356
translations/README-ru.md
vendored
356
translations/README-ru.md
vendored
@ -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>
|
||||
<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)
|
||||
|
||||
Python, будучи прекрасно спроектированным высокоуровневым языком программирования, предоставляет множество возможностей для удобства программиста. Но иногда результаты работы Python кода могут показаться неочевидными на первый взгляд.
|
||||
Python, будучи прекрасно спроектированным высокоуровневым языком программирования, предоставляет множество возможностей для удобства программиста. Но иногда поведение Python кода могут показаться запутывающим на первый взгляд.
|
||||
|
||||
**wtfpython** задуман как проект, пытающийся объяснить, что именно происходит под капотом некоторых неочевидных фрагментов кода и менее известных возможностей Python.
|
||||
**wtfpython** задуман как проект, пытающийся объяснить, что именно происходит под капотом неочевидных фрагментов кода и малоизвестных возможностей Python.
|
||||
|
||||
Если вы опытный программист на Python, вы можете принять это как вызов и правильно объяснить WTF ситуации с первой попытки. Возможно, вы уже сталкивались с некоторыми из них раньше, и я смогу оживить ваши старые добрые воспоминания! 😅
|
||||
Если вы опытный питонист, вы можете принять это как вызов и правильно объяснить WTF ситуации с первой попытки. Возможно, вы уже сталкивались с некоторыми из них раньше, и я смогу оживить ваши старые добрые воспоминания! 😅
|
||||
|
||||
PS: Если вы уже читали **wtfpython** раньше, с изменениями можно ознакомиться [здесь](https://github.com/satwikkansal/wtfpython/releases/) (примеры, отмеченные звездочкой - это примеры, добавленные в последней основной редакции).
|
||||
|
||||
Ну что ж, приступим...
|
||||
|
||||
# Содержание
|
||||
* [Содержание](#Содержание)
|
||||
* [Структура примера](#Структура-примера)
|
||||
* [Применение](#Применение)
|
||||
* [👀 Примеры](#👀-Примеры)
|
||||
* [Секция: Напряги мозги!](#Секция:-Напряги-мозги!)
|
||||
* [▶ Первым делом!](#▶-Первым-делом!)
|
||||
* [▶ Строки иногда ведут себя непредсказуемо](#▶-Строки-иногда-ведут-себя-непредсказуемо)
|
||||
* [▶ Осторожнее с цепочкой операций](#▶-Осторожнее-с-цепочкой-операций)
|
||||
* [▶ Как не надо использовать оператор `is`](#▶-Как-не-надо-использовать-оператор-`is`)
|
||||
* [▶ Мистическое хэширование](#▶-Мистическое-хэширование)
|
||||
* [▶ В глубине души мы все одинаковы.](#▶-В-глубине-души-мы-все-одинаковы.)
|
||||
* [▶ Беспорядок внутри порядка *](#▶-Беспорядок-внутри-порядка--*)
|
||||
* [▶ Продолжай пытаться... *](#▶-Продолжай-пытаться...-*)
|
||||
* [▶ Для чего?](#▶-Для-чего?)
|
||||
* [▶ Расхождение во времени исполнения](#▶-Расхождение-во-времени-исполнения)
|
||||
* [▶ `is not ...` не является `is (not ...)`](#▶-`is-not-...`-не-является-`is-(not-...)`)
|
||||
* [▶ Крестики-нолики, где X побеждает с первой попытки!](#▶-Крестики-нолики,-где-X-побеждает-с-первой-попытки!)
|
||||
* [▶ Переменная Шредингера *](#▶-Переменная-Шредингера-*)
|
||||
* [▶ Проблема курицы и яйца *](#▶-Проблема-курицы-и-яйца-*)
|
||||
* [▶ Отношения между подклассами](#▶-Отношения-между-подклассами)
|
||||
* [▶ Равенство и тождество методов](#▶-Равенство-и-тождество-методов)
|
||||
* [▶ All-true-ation (непереводимая игра слов) *](#▶-All-true-ation-(непереводимая-игра-слов)-*)
|
||||
* [▶ Неожиданная запятая](#▶-Неожиданная-запятая)
|
||||
* [▶ Строки и обратные слэши](#▶-Строки-и-обратные-слэши)
|
||||
* [▶ Не узел! (eng. not knot!)](#▶-Не-узел!-(eng.-not-knot!))
|
||||
* [▶ Строки наполовину в тройных кавычках](#▶-Строки-наполовину-в-тройных-кавычках)
|
||||
* [▶ Что не так с логическими значениями?](#▶-Что-не-так-с-логическими-значениями?)
|
||||
* [▶ Атрибуты класса и экземпляра](#▶-Атрибуты-класса-и-экземпляра)
|
||||
* [▶ Возврат None из генератора](#▶-Возврат-None-из-генератора)
|
||||
* [▶ Yield from возвращает... *](#▶-Yield-from-возвращает...-*)
|
||||
* [▶ Nan-рефлексивность *](#▶-Nan-рефлексивность-*)
|
||||
* [▶ Мутируем немутируемое!](#▶-Мутируем-немутируемое!)
|
||||
* [▶ Исчезающая переменная из внешней области видимости](#▶-Исчезающая-переменная-из-внешней-области-видимости)
|
||||
* [▶ Превышение предела целочисленного преобразования строк](#▶-Превышение-предела-целочисленного-преобразования-строк)
|
||||
* [Секция: Скользкие склоны](#Секция:-Скользкие-склоны)
|
||||
* [▶ Изменение словаря во время прохода по нему](#▶-Изменение-словаря-во-время-прохода-по-нему)
|
||||
* [▶ Упрямая операция `del`](#▶-Упрямая-операция-`del`)
|
||||
* [▶ Переменная за пределами видимости](#▶-Переменная-за-пределами-видимости)
|
||||
* [▶ Удаление элемента списка во время прохода по списку](#▶-Удаление-элемента-списка-во-время-прохода-по-списку)
|
||||
* [▶ Сжатие итераторов с потерями *](#▶-Сжатие-итераторов-с-потерями-*)
|
||||
* [▶ Утечка переменных внутри цикла](#▶-Утечка-переменных-внутри-цикла)
|
||||
* [▶ Остерегайтесь изменяемых аргументов по умолчанию!](#▶-Остерегайтесь-изменяемых-аргументов-по-умолчанию!)
|
||||
* [▶ Ловля исключений](#▶-Ловля-исключений)
|
||||
* [▶ Одни и те же операнды, разная история!](#▶-Одни-и-те-же-операнды,-разная-история!)
|
||||
* [▶ Разрешение имен игнорирует область видимости класса](#▶-Разрешение-имен-игнорирует-область-видимости-класса)
|
||||
* [▶ Округляясь как банкир *](#▶-Округляясь-как-банкир-*)
|
||||
* [▶ Иголки в стоге сена *](#▶-Иголки-в-стоге-сена-*)
|
||||
* [▶ Сплиты (splitsies) *](#▶-Сплиты-(splitsies)-*)
|
||||
* [▶ Подстановочное импортирование (wild imports) *](#▶-Подстановочное-импортирование-(wild-imports)-*)
|
||||
* [▶ Все ли отсортировано? *](#▶-Все-ли-отсортировано?-*)
|
||||
* [▶ Полночи не существует?](#▶-Полночи-не-существует?)
|
||||
* [Секция: Скрытые сокровища!](#Секция:-Скрытые-сокровища!)
|
||||
* [▶ Python, можешь ли ты помочь взлелеть?](#▶-Python,-можешь-ли-ты-помочь-взлелеть?)
|
||||
* [▶ `goto`, но почему?](#▶-`goto`,-но-почему?)
|
||||
* [▶ Держитесь!](#▶-Держитесь!)
|
||||
* [▶ Давайте познакомимся с дружелюбным Дядей Барри](#▶-Давайте-познакомимся-с-дружелюбным-Дядей-Барри)
|
||||
* [▶ Даже Python понимает, что любовь - это сложно.](#▶-Даже-Python-понимает,-что-любовь---это-сложно.)
|
||||
* [▶ Да, оно существует!](#▶-Да,-оно-существует!)
|
||||
* [▶ Многоточие *](#▶-Многоточие-*)
|
||||
* [▶ Писконечность (Inpinity)](#▶-Писконечность-(Inpinity))
|
||||
* [▶ Давайте искажать](#▶-Давайте-искажать)
|
||||
* [Секция: Внешность обманчива!](#Секция:-Внешность-обманчива!)
|
||||
* [▶ Пропускаем строки?](#▶-Пропускаем-строки?)
|
||||
* [▶ Телепортация](#▶-Телепортация)
|
||||
* [▶ Что-то не так...](#▶-Что-то-не-так...)
|
||||
* [Секция: Разное](#Секция:-Разное)
|
||||
* [▶ `+=` быстрее](#▶-`+=`-быстрее)
|
||||
* [▶ Сделаем гигантскую строку!](#▶-Сделаем-гигантскую-строку!)
|
||||
* [▶ Замедляем поиск по `dict` *](#▶-Замедляем-поиск-по-`dict`-*)
|
||||
* [▶ Раздуваем экземпляры словарей *](#▶-Раздуваем-экземпляры-словарей-*)
|
||||
* [▶ Минорное *](#▶-Минорное-*)
|
||||
* [Вклад в проект](#Вклад-в-проект)
|
||||
* [Благодарности](#Благодарности)
|
||||
* [🎓 Лицензия](#🎓-Лицензия)
|
||||
* [Удиви своих друзей!](#Удиви-своих-друзей!)
|
||||
* [Нужна PDF версия?](#Нужна-PDF-версия?)
|
||||
- [Содержание](#содержание)
|
||||
- [Структура примера](#структура-примера)
|
||||
- [Применение](#применение)
|
||||
- [👀 Примеры](#-примеры)
|
||||
- [Секция: Напряги мозги!](#секция-напряги-мозги)
|
||||
- [▶ Первым делом!](#-первым-делом)
|
||||
- [💡 Обьяснение](#-обьяснение)
|
||||
- [▶ Строки иногда ведут себя непредсказуемо](#-строки-иногда-ведут-себя-непредсказуемо)
|
||||
- [💡 Объяснение](#-объяснение)
|
||||
- [▶ Осторожнее с цепочкой операций](#-осторожнее-с-цепочкой-операций)
|
||||
- [💡 Объяснение:](#-объяснение-1)
|
||||
- [▶ Как не надо использовать оператор `is`](#-как-не-надо-использовать-оператор-is)
|
||||
- [💡 Объяснение:](#-объяснение-2)
|
||||
- [▶ Мистическое хеширование](#-мистическое-хеширование)
|
||||
- [💡 Объяснение](#-объяснение-3)
|
||||
- [▶ В глубине души мы все одинаковы.](#-в-глубине-души-мы-все-одинаковы)
|
||||
- [💡 Объяснение:](#-объяснение-4)
|
||||
- [▶ Беспорядок внутри порядка \*](#-беспорядок-внутри-порядка-)
|
||||
- [💡 Объяснение:](#-объяснение-5)
|
||||
- [▶ Продолжай пытаться... \*](#-продолжай-пытаться-)
|
||||
- [💡 Объяснение:](#-объяснение-6)
|
||||
- [▶ Для чего?](#-для-чего)
|
||||
- [💡 Объяснение:](#-объяснение-7)
|
||||
- [▶ Расхождение во времени исполнения](#-расхождение-во-времени-исполнения)
|
||||
- [💡 Объяснение](#-объяснение-8)
|
||||
- [▶ `is not ...` не является `is (not ...)`](#-is-not--не-является-is-not-)
|
||||
- [💡 Объяснение](#-объяснение-9)
|
||||
- [▶ Крестики-нолики, где X побеждает с первой попытки!](#-крестики-нолики-где-x-побеждает-с-первой-попытки)
|
||||
- [💡 Объяснение:](#-объяснение-10)
|
||||
- [▶ Переменная Шредингера \*](#-переменная-шредингера-)
|
||||
- [💡 Объяснение:](#-объяснение-11)
|
||||
- [▶ Проблема курицы и яйца \*](#-проблема-курицы-и-яйца-)
|
||||
- [💡 Объяснение](#-объяснение-12)
|
||||
- [▶ Отношения между подклассами](#-отношения-между-подклассами)
|
||||
- [💡 Объяснение](#-объяснение-13)
|
||||
- [▶ Равенство и тождество методов](#-равенство-и-тождество-методов)
|
||||
- [💡 Объяснение](#-объяснение-14)
|
||||
- [▶ All-true-ation (непереводимая игра слов) \*](#-all-true-ation-непереводимая-игра-слов-)
|
||||
- [💡 Объяснение:](#-объяснение-15)
|
||||
- [💡 Объяснение:](#-объяснение-16)
|
||||
- [▶ Строки и обратные слэши](#-строки-и-обратные-слэши)
|
||||
- [💡 Объяснение](#-объяснение-17)
|
||||
- [▶ Не узел! (англ. not knot!)](#-не-узел-англ-not-knot)
|
||||
- [💡 Объяснение](#-объяснение-18)
|
||||
- [▶ Строки, наполовину обернутые в тройные кавычки](#-строки-наполовину-обернутые-в-тройные-кавычки)
|
||||
- [💡 Объяснение:](#-объяснение-19)
|
||||
- [▶ Что не так с логическими значениями?](#-что-не-так-с-логическими-значениями)
|
||||
- [💡 Объяснение:](#-объяснение-20)
|
||||
- [▶ Атрибуты класса и экземпляра](#-атрибуты-класса-и-экземпляра)
|
||||
- [💡 Объяснение:](#-объяснение-21)
|
||||
- [▶ Возврат None из генератора](#-возврат-none-из-генератора)
|
||||
- [💡 Объяснение:](#-объяснение-22)
|
||||
- [▶ Yield from возвращает... \*](#-yield-from-возвращает-)
|
||||
- [💡 Объяснение:](#-объяснение-23)
|
||||
- [▶ Nan-рефлексивность \*](#-nan-рефлексивность-)
|
||||
- [💡 Объяснение:](#-объяснение-24)
|
||||
- [▶ Изменяем неизменяемое!](#-изменяем-неизменяемое)
|
||||
- [💡 Объяснение:](#-объяснение-25)
|
||||
- [▶ Исчезающая переменная из внешней области видимости](#-исчезающая-переменная-из-внешней-области-видимости)
|
||||
- [💡 Объяснение:](#-объяснение-26)
|
||||
- [▶ Загадочное преобразование типов ключей](#-загадочное-преобразование-типов-ключей)
|
||||
- [💡 Объяснение:](#-объяснение-27)
|
||||
- [▶ Посмотрим, сможете ли вы угадать что здесь?](#-посмотрим-сможете-ли-вы-угадать-что-здесь)
|
||||
- [💡 Объяснение:](#-объяснение-28)
|
||||
- [▶ Превышение предела целочисленного преобразования строк](#-превышение-предела-целочисленного-преобразования-строк)
|
||||
- [💡 Объяснение:](#-объяснение-29)
|
||||
- [Секция: Скользкие склоны](#секция-скользкие-склоны)
|
||||
- [▶ Изменение словаря во время прохода по нему](#-изменение-словаря-во-время-прохода-по-нему)
|
||||
- [💡 Объяснение:](#-объяснение-30)
|
||||
- [▶ Упрямая операция `del`](#-упрямая-операция-del)
|
||||
- [💡 Объяснение:](#-объяснение-31)
|
||||
- [▶ Переменная за пределами видимости](#-переменная-за-пределами-видимости)
|
||||
- [💡 Объяснение:](#-объяснение-32)
|
||||
- [▶ Удаление элемента списка во время прохода по списку](#-удаление-элемента-списка-во-время-прохода-по-списку)
|
||||
- [💡 Объяснение:](#-объяснение-33)
|
||||
- [▶ Сжатие итераторов с потерями \*](#-сжатие-итераторов-с-потерями-)
|
||||
- [💡 Объяснение:](#-объяснение-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 и переходите к следующему примеру.
|
||||
|
||||
PS: Вы также можете читать WTFPython в командной строке, используя [pypi package](https://pypi.python.org/pypi/wtfpython),
|
||||
@ -344,7 +409,7 @@ False
|
||||
- Строки интернируются во время компиляции (`'wtf'` будет интернирована, но `''.join(['w'', 't', 'f'])` - нет)
|
||||
- Строки, не состоящие из букв ASCII, цифр или знаков подчеркивания, не интернируются. В примере выше `'wtf!'` не интернируется из-за `!`. Реализацию этого правила в CPython можно найти [здесь](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19)
|
||||
![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!"`, но одинаковы при вызове в модуле.
|
||||
- Резкое изменение в выводе четвертого фрагмента связано с [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).
|
||||
@ -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, за исключением того, что каждое выражение оценивается не более одного раза.
|
||||
|
||||
@ -491,7 +556,7 @@ False
|
||||
|
||||
Подобная оптимизация применима и к другим **изменяемым** объектам, таким как пустые кортежи. Поскольку списки являются изменяемыми, поэтому `[] is []` вернет `False`, а `() is ()` вернет `True`. Это объясняет наш второй фрагмент. Перейдем к третьему,
|
||||
|
||||
**И `a`, и `b` ссылаются на один и тот же объект при инициализации одним и тем же значением в одной и той же строкеi**.
|
||||
**И `a`, и `b` ссылаются на один и тот же объект при инициализации одним и тем же значением в одной и той же строке**.
|
||||
|
||||
**Вывод**
|
||||
|
||||
@ -511,7 +576,7 @@ False
|
||||
|
||||
* Когда a и b инициализируются со значением `257` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на него во второй переменной. Если делать это в отдельных строках, интерпретатор не "знает", что объект `257` уже существует.
|
||||
|
||||
* Это оптимизация компилятора и относится именно к интерактивной среде. Когда вы вводите две строки в интерпретаторе, они компилируются отдельно, поэтому оптимизируются отдельно. Если выполнить этот пример в файле `.py', поведение будет отличаться, потому что файл компилируется весь сразу. Эта оптимизация не ограничивается целыми числами, она работает и для других неизменяемых типов данных, таких как строки (проверьте пример "Строки - это сложно") и плавающие числа,
|
||||
* Эта оптимизация компилятора относится именно к интерактивной среде. Когда вы вводите две строки в интерпретаторе, они компилируются отдельно, поэтому оптимизируются отдельно. Если выполнить этот пример в файле `.py', поведение будет отличаться, потому что файл компилируется целиком. Эта оптимизация не ограничивается целыми числами, она работает и для других неизменяемых типов данных, таких как строки (смотреть пример "Строки - это сложно") и плавающие числа,
|
||||
|
||||
```py
|
||||
>>> a, b = 257.0, 257.0
|
||||
@ -519,12 +584,12 @@ False
|
||||
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 --->
|
||||
1\.
|
||||
```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
|
||||
>>> 5 == 5.0 == 5 + 0j
|
||||
True
|
||||
@ -569,7 +634,7 @@ complex
|
||||
>>> (5 in some_dict) and (5 + 0j in some_dict)
|
||||
True
|
||||
```
|
||||
* Это применимо и во время присваения значения элементу. Поэтому, в выражении `some_dict[5] = "Python"` Python находит существующий элемент с эквивалентным ключом `5.0 -> "Ruby"`, перезаписывает его значение на место, а исходный ключ оставляет в покое.
|
||||
* Это применимо и во время присваивания значения элементу. Поэтому, в выражении `some_dict[5] = "Python"` Python находит существующий элемент с эквивалентным ключом `5.0 -> "Ruby"`, перезаписывает его значение на место, а исходный ключ оставляет в покое.
|
||||
```py
|
||||
>>> some_dict
|
||||
{5.0: 'Ruby'}
|
||||
@ -577,16 +642,17 @@ complex
|
||||
>>> some_dict
|
||||
{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
|
||||
>>> 5 == 5.0 == 5 + 0j
|
||||
True
|
||||
>>> hash(5) == hash(5.0) == hash(5 + 0j)
|
||||
True
|
||||
```
|
||||
**Примечание:** Обратное не обязательно верно: Объекты с одинаковыми хэш-значениями сами могут быть неравными. (Это вызывает так называемую [хэш-коллизию](https://en.wikipedia.org/wiki/Collision_(computer_science)) и ухудшает производительность постоянного времени, которую обычно обеспечивает хэширование).
|
||||
**Примечание:** Обратное не обязательно верно: Объекты с одинаковыми хэш-значениями сами могут быть неравными. (Это вызывает так называемую [хэш-коллизию](https://en.wikipedia.org/wiki/Collision_(computer_science)) и ухудшает производительность постоянного времени, которую обычно обеспечивает хеширование).
|
||||
|
||||
---
|
||||
|
||||
@ -604,14 +670,14 @@ class WTF:
|
||||
False
|
||||
>>> WTF() is WTF() # идентификаторы также различаются
|
||||
False
|
||||
>>> hash(WTF()) == hash(WTF()) # хэши тоже должны отличаться
|
||||
>>> hash(WTF()) == hash(WTF()) # хеши тоже должны отличаться
|
||||
True
|
||||
>>> id(WTF()) == id(WTF())
|
||||
True
|
||||
```
|
||||
#### 💡 Объяснение:
|
||||
|
||||
* При вызове `id` Python создал объект класса `WTF` и передал его функции `id`. Функция `id` забирает свой `id` (местоположение в памяти) и выбрасывает объект. Объект уничтожается.
|
||||
* При вызове `id` Python создал объект класса `WTF` и передал его функции `id`. Функция `id` забирает свой `id` (расположение в памяти) и выбрасывает объект. Объект уничтожается.
|
||||
* Когда мы делаем это дважды подряд, Python выделяет ту же самую область памяти и для второго объекта. Поскольку (в CPython) `id` использует участок памяти в качестве идентификатора объекта, идентификатор двух объектов одинаков.
|
||||
* Таким образом, id объекта уникален только во время жизни объекта. После уничтожения объекта или до его создания, другой объект может иметь такой же id.
|
||||
* Но почему выражение с оператором `is` равно `False`? Давайте посмотрим с помощью этого фрагмента.
|
||||
@ -657,13 +723,13 @@ another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a';
|
||||
|
||||
class DictWithHash(dict):
|
||||
"""
|
||||
A dict that also implements __hash__ magic.
|
||||
Словарь с реализованным методом __hash__.
|
||||
"""
|
||||
__hash__ = lambda self: 0
|
||||
|
||||
class OrderedDictWithHash(OrderedDict):
|
||||
"""
|
||||
An OrderedDict that also implements __hash__ magic.
|
||||
OrderedDict с реализованным методом __hash__.
|
||||
"""
|
||||
__hash__ = lambda self: 0
|
||||
```
|
||||
@ -677,7 +743,7 @@ True
|
||||
>>> ordered_dict == another_ordered_dict # почему же c != a ??
|
||||
False
|
||||
|
||||
# Мы все знаем, что множество состоит только из уникальных элементов,
|
||||
# Мы все знаем, что множество состоит из уникальных элементов,
|
||||
# давайте попробуем составить множество из этих словарей и посмотрим, что получится...
|
||||
|
||||
>>> 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';
|
||||
>>> len({dictionary, ordered_dict, another_ordered_dict})
|
||||
1
|
||||
>>> len({ordered_dict, another_ordered_dict, dictionary}) # changing the order
|
||||
>>> len({ordered_dict, another_ordered_dict, dictionary}) # изменим порядок элементов
|
||||
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` везде, где используется обычный словарь.
|
||||
@ -794,7 +860,7 @@ Iteration 0
|
||||
|
||||
#### 💡 Объяснение:
|
||||
|
||||
- Когда один из операторов `return`, `break` или `continue` выполняется в блоке `try` оператора "try...finally", на выходе также выполняется пункт `finally`.
|
||||
- Когда один из операторов `return`, `break` или `continue` выполняется в блоке `try` оператора "try...finally", на выходе также выполняется блок `finally`.
|
||||
- Возвращаемое значение функции определяется последним выполненным оператором `return`. Поскольку блок `finally` выполняется всегда, оператор `return`, выполненный в блоке `finally`, всегда будет последним.
|
||||
- Предостережение - если в блоке `finally` выполняется оператор `return` или `break`, то временно сохраненное исключение отбрасывается.
|
||||
|
||||
@ -966,7 +1032,7 @@ board = [row] * 3
|
||||
[['X', '', ''], ['X', '', ''], ['X', '', '']]
|
||||
```
|
||||
|
||||
Мы же не назначили три `"Х"`?
|
||||
Мы же не назначали три `"Х"`?
|
||||
|
||||
#### 💡 Объяснение:
|
||||
|
||||
@ -1006,7 +1072,7 @@ for x in range(7):
|
||||
funcs_results = [func() for func in funcs]
|
||||
```
|
||||
|
||||
**Вывод (Python version):**
|
||||
**Вывод:**
|
||||
```py
|
||||
>>> results
|
||||
[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]
|
||||
```
|
||||
|
||||
* Чтобы получить желаемое поведение, вы можете передать переменную цикла как именованную переменную в функцию. **Почему это работает?** Потому что это определит переменную *внутри* области видимости функции. Она больше не будет обращаться к глобальной области видимости для поиска значения переменной, а создаст локальную переменную, которая будет хранить значение `x` в данный момент времени.
|
||||
* Чтобы получить желаемое поведение, вы можете передать переменную цикла как именованную аргумент в функцию. **Почему это работает?** Потому что это определит переменную *внутри* области видимости функции. Она больше не будет обращаться к глобальной области видимости для поиска значения переменной, а создаст локальную переменную, которая будет хранить значение `x` в данный момент времени.
|
||||
|
||||
```py
|
||||
funcs = []
|
||||
@ -1079,7 +1145,7 @@ True
|
||||
True
|
||||
```
|
||||
|
||||
Так какой же базовый класс является "окончательным"? Кстати, это еще не все,
|
||||
Так какой же базовый класс является "родительским"? Кстати, это еще не все,
|
||||
|
||||
2\.
|
||||
|
||||
@ -1137,12 +1203,11 @@ False
|
||||
|
||||
* Отношения подклассов не обязательно являются транзитивными в Python. Можно переопределить магический метод `__subclasscheck__` в метаклассе.
|
||||
* Когда вызывается `issubclass(cls, Hashable)`, он просто ищет не-фальшивый метод "`__hash__`" в `cls` или во всем, от чего он наследуется.
|
||||
* Поскольку `object` является хэшируемым, а `list` - нехэшируемым, это нарушает отношение транзитивности.
|
||||
* Более подробное объяснение можно найти [здесь] (https://www.naftaliharris.com/blog/python-subclass-intransitivity/).
|
||||
* Поскольку `object` является хэшируемым, а `list` - нет, это нарушает отношение транзитивности.
|
||||
* Более подробное объяснение можно найти [здесь](https://www.naftaliharris.com/blog/python-subclass-intransitivity/).
|
||||
|
||||
---
|
||||
|
||||
|
||||
### ▶ Равенство и тождество методов
|
||||
<!-- Example ID: 94802911-48fe-4242-defa-728ae893fa32 --->
|
||||
|
||||
@ -1202,7 +1267,7 @@ True
|
||||
|
||||
#### 💡 Объяснение
|
||||
* Функции являются [дескрипторами](https://docs.python.org/3/howto/descriptor.html). Всякий раз, когда к функции обращаются как к
|
||||
атрибута, вызывается дескриптор, создавая объект метода, который "связывает" функцию с объектом, владеющим атрибутом. При вызове метод вызывает функцию, неявно передавая связанный объект в качестве первого аргумента
|
||||
атрибуту, вызывается дескриптор, создавая объект метода, который "связывает" функцию с объектом, владеющим атрибутом. При вызове метод вызывает функцию, неявно передавая связанный объект в качестве первого аргумента
|
||||
(именно так мы получаем `self` в качестве первого аргумента, несмотря на то, что не передаем его явно).
|
||||
```py
|
||||
>>> o1.method
|
||||
@ -1338,7 +1403,7 @@ True
|
||||
|
||||
#### 💡 Объяснение
|
||||
|
||||
- В обычной строке обратная слэш используется для экранирования символов, которые могут иметь специальное значение (например, одинарная кавычка, двойная кавычка и сам обратный слэш).
|
||||
- В обычной строке обратный слэш используется для экранирования символов, которые могут иметь специальное значение (например, одинарная кавычка, двойная кавычка и сам обратный слэш).
|
||||
```py
|
||||
>>> "wt\"f"
|
||||
'wt"f'
|
||||
@ -1355,12 +1420,12 @@ True
|
||||
>>> print(r"\\n")
|
||||
'\\n'
|
||||
```
|
||||
- Это означает, что когда синтаксический анализатор встречает обратный слэш в необработанной строке, он ожидает, что за ней последует другой символ. А в нашем случае (`print(r"\")`) обратная слэш экранирует двойную кавычку, оставив парсер без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слеш не работает в конце необработанной строки.
|
||||
- Это означает, что когда синтаксический анализатор встречает обратный слэш в необработанной строке, он ожидает, что за ней последует другой символ. А в нашем случае (`print(r"\")`) обратный слэш экранирует двойную кавычку, оставив синтаксический анализатор без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слэш не работает в конце необработанной строки.
|
||||
|
||||
--
|
||||
---
|
||||
|
||||
|
||||
### ▶ Не узел! (eng. not knot!)
|
||||
### ▶ Не узел! (англ. not knot!)
|
||||
<!-- Example ID: 7034deb1-7443-417d-94ee-29a800524de8 --->
|
||||
```py
|
||||
x = True
|
||||
@ -1383,12 +1448,12 @@ SyntaxError: invalid syntax
|
||||
* Старшинство операторов влияет на выполнение выражения, и оператор `==` имеет более высокий приоритет, чем оператор `not` в Python.
|
||||
* Поэтому `not x == y` эквивалентно `not (x == y)`, что эквивалентно `not (True == False)`, в итоге равное `True`.
|
||||
* Но `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 --->
|
||||
**Вывод:**
|
||||
```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 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)` при выходе из генератора."
|
||||
|
||||
+ В случае `some_func(3)` `StopIteration` возникает в начале из-за оператора `return`. Исключение `StopIteration` автоматически перехватывается внутри обертки `list(...)` и цикла `for`. Поэтому два вышеприведенных фрагмента приводят к пустому списку.
|
||||
+ В случае `some_func(3)` `StopIteration` возникает в начале из-за оператора `return`. Исключение `StopIteration` автоматически перехватывается внутри обертки `list(...)` и цикла `for`. Поэтому два вышеприведенных фрагмента возвращают пустой список.
|
||||
|
||||
+ Чтобы получить `["wtf"]` из генератора `some_func`, нужно перехватить исключение `StopIteration`.
|
||||
|
||||
@ -1721,7 +1786,7 @@ nan
|
||||
```py
|
||||
>>> x = float('nan')
|
||||
>>> y = x / x
|
||||
>>> y is y # идендичность сохраняется
|
||||
>>> y is y # идентичность сохраняется
|
||||
True
|
||||
>>> y == y # сравнение ложно для y
|
||||
False
|
||||
@ -1733,7 +1798,7 @@ True
|
||||
|
||||
- `'inf'` и `'nan'` - это специальные строки (без учета регистра), которые при явном приведении к типу `float` используются для представления математической "бесконечности" и "не число" соответственно.
|
||||
|
||||
- Согласно стандартам IEEE `NaN != NaN`, но соблюдение этого правила нарушает предположение о рефлексивности элемента коллекции в Python, то есть если `x` является частью коллекции, такой как `list`, реализации, методы сравнения предполагают, что `x == x`. Поэтому при сравнении элементов сначала сравниваются их идентификаторы (так как это быстрее), а значения сравниваются только при несовпадении идентификаторов. Следующий фрагмент сделает вещи более ясными:
|
||||
- Согласно стандартам IEEE, `NaN != NaN`, но соблюдение этого правила нарушает предположение о рефлексивности элемента коллекции в Python, то есть если `x` является частью коллекции, такой как `list`, реализации методов сравнения предполагают, что `x == x`. Поэтому при сравнении элементов сначала сравниваются их идентификаторы (так как это быстрее), а значения сравниваются только при несовпадении идентификаторов. Следующий фрагмент сделает вещи более ясными:
|
||||
|
||||
```py
|
||||
>>> x = float('nan')
|
||||
@ -1753,7 +1818,7 @@ True
|
||||
---
|
||||
|
||||
|
||||
### ▶ Мутируем немутируемое!
|
||||
### ▶ Изменяем неизменяемое!
|
||||
|
||||
<!-- 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)
|
||||
|
||||
> Неизменяемые последовательности
|
||||
Объект неизменяемого типа последовательности не может измениться после создания. (Если объект содержит ссылки на другие объекты, эти объекты могут быть изменяемыми и могут быть изменены; однако набор объектов, на которые непосредственно ссылается неизменяемый объект, не может изменяться.)
|
||||
> Объект неизменяемого типа последовательности не может измениться после создания. (Если объект содержит ссылки на другие объекты, эти объекты могут быть изменяемыми и могут быть изменены; однако набор объектов, на которые непосредственно ссылается неизменяемый объект, не может изменяться.)
|
||||
|
||||
* Оператор `+=` изменяет список на месте. Присваивание элемента не работает, но когда возникает исключение, элемент уже был изменен на месте.
|
||||
* Также есть объяснение в официальном [Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works).
|
||||
@ -1836,11 +1900,11 @@ NameError: name 'e' is not defined
|
||||
del N
|
||||
```
|
||||
|
||||
Это означает, что исключению должно быть присвоено другое имя, чтобы на него можно было ссылаться после завершения блока `except`. Исключения очищаются, потому что с прикрепленным к ним трейсбэком они образуют цикл ссылок со стеком вызовов, сохраняя все локальные объекты в этой стэке до следующей сборки мусора.
|
||||
Это означает, что исключению должно быть присвоено другое имя, чтобы на него можно было ссылаться после завершения блока `except`. Исключения очищаются, потому что с прикрепленным к ним трейсбэком они образуют цикл ссылок со стэком вызовов, сохраняя все локальные объекты в этой стэке до следующей сборки мусора.
|
||||
|
||||
* В Python clauses не имеют области видимости. В примере все объекты в одной области видимости, а переменная `e` была удалена из-за выполнения блока `except`. Этого нельзя сказать о функциях, которые имеют отдельные внутренние области видимости. Пример ниже иллюстрирует это:
|
||||
|
||||
```py
|
||||
```py
|
||||
def f(x):
|
||||
del(x)
|
||||
print(x)
|
||||
@ -1954,13 +2018,9 @@ a, b = a[b] = {}, 5
|
||||
> Оператор присваивания исполняет список выражений (помните, что это может быть одно выражение или список, разделенный запятыми, в последнем случае получается кортеж) и присваивает единственный результирующий объект каждому из целевых списков, слева направо.
|
||||
|
||||
* `+` в `(target_list "=")+` означает, что может быть **один или более** целевых списков. В данном случае целевыми списками являются `a, b` и `a[b]` (обратите внимание, что список выражений ровно один, в нашем случае это `{}, 5`).
|
||||
|
||||
* После исполнения списка выражений его значение распаковывается в целевые списки **слева направо**. Так, в нашем случае сначала кортеж `{}, 5` распаковывается в `a, b`, и теперь у нас есть `a = {}` и `b = 5`.
|
||||
|
||||
* Теперь `a` имеет значение `{}`, которое является изменяемым объектом.
|
||||
|
||||
* Вторым целевым списком является `a[b]` (вы можете ожидать, что это вызовет ошибку, поскольку `a` и `b` не были определены в предыдущих утверждениях. Но помните, мы только что присвоили `a` значение `{}` и `b` - `5`).
|
||||
|
||||
* Теперь мы устанавливаем ключ `5` в словаре в кортеж `({}, 5)`, создавая круговую ссылку (`{...}` в выводе ссылается на тот же объект, на который уже ссылается `a`). Другим более простым примером круговой ссылки может быть
|
||||
|
||||
```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 все еще может работать с большими целыми числами. Ошибка возникает только при преобразовании между целыми числами и строками.
|
||||
К счастью, вы можете увеличить предел допустимого количества цифр. Для этого можно воспользоваться одним из следующих способов:
|
||||
- `-X int_max_str_digits` - флаг командной строкиcommand-line flag
|
||||
- `-X int_max_str_digits` - флаг командной строки
|
||||
- `set_int_max_str_digits()` - функция из модуля `sys`
|
||||
- `PYTHONINTMAXSTRDIGITS` - переменная окружения
|
||||
|
||||
@ -2230,7 +2290,7 @@ for idx, item in enumerate(list_4):
|
||||
>>> some_list = [1, 2, 3, 4]
|
||||
>>> id(some_list)
|
||||
139798789457608
|
||||
>>> id(some_list[:]) # Notice that python creates new object for sliced list.
|
||||
>>> id(some_list[:]) # Обратите внимание, создается новый объект из среза списка
|
||||
139798779601192
|
||||
```
|
||||
|
||||
@ -2239,7 +2299,7 @@ for idx, item in enumerate(list_4):
|
||||
* `remove` удаляет первое подходящее значение, а не конкретный индекс, вызывает `ValueError`, если значение не найдено.
|
||||
* `pop` удаляет элемент по определенному индексу и возвращает его, вызывает `IndexError`, если указан неверный индекс.
|
||||
|
||||
**Почему на выходе получается `[2, 4]`?
|
||||
**Почему на выходе получается `[2, 4]`?**
|
||||
- Проход по списку выполняется индекс за индексом, и когда мы удаляем `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).
|
||||
@ -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):
|
||||
|
||||
@ -2386,7 +2446,7 @@ def some_func(default_arg=[]):
|
||||
|
||||
#### 💡 Объяснение:
|
||||
|
||||
- Изменяемые аргументы функций по умолчанию в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется недавно присвоенное им значение. Когда мы явно передали `[]` в `some_func в качестве аргумента, значение по умолчанию переменной `default_arg` не было использовано, поэтому функция вернулась, как и ожидалось.
|
||||
- Изменяемые аргументы функций по умолчанию в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется недавно присвоенное им значение. Когда мы явно передали `[]` в `some_func` в качестве аргумента, значение по умолчанию переменной `default_arg` не было использовано, поэтому функция вернулась, как и ожидалось.
|
||||
|
||||
```py
|
||||
def some_func(default_arg=[]):
|
||||
@ -2396,7 +2456,7 @@ def some_func(default_arg=[]):
|
||||
|
||||
**Результат:**
|
||||
```py
|
||||
>>> some_func.__defaults__ # Выражение выведет значения стандартных аргументов фукнции
|
||||
>>> some_func.__defaults__ # Выражение выведет значения стандартных аргументов функции
|
||||
([],)
|
||||
>>> some_func()
|
||||
>>> some_func.__defaults__
|
||||
@ -2580,7 +2640,7 @@ class SomeClass:
|
||||
#### 💡 Объяснение
|
||||
- Области видимости, вложенные внутрь определения класса, игнорируют имена, связанные на уровне класса.
|
||||
- Выражение-генератор имеет свою собственную область видимости.
|
||||
- Начиная с версии Python 3.X, списковые вычисления также имеют свою собственную область видимости.
|
||||
- Начиная с версии Python 3.X, списковые выражения (list comprehensions) также имеют свою собственную область видимости.
|
||||
|
||||
---
|
||||
|
||||
@ -2716,7 +2776,7 @@ b = "javascript"
|
||||
**Результат:**
|
||||
|
||||
```py
|
||||
# assert выражение с сообщением об ошиб
|
||||
# assert выражение с сообщением об ошибке
|
||||
>>> assert(a == b, "Both languages are different")
|
||||
# Исключение AssertionError не возникло
|
||||
```
|
||||
@ -2939,7 +2999,7 @@ False
|
||||
(tuple, list)
|
||||
```
|
||||
|
||||
- В отличие от метода `sorted, метод `reversed` возвращает итератор. Почему? Потому что сортировка требует, чтобы итератор либо изменялся на месте, либо использовал дополнительный контейнер (список), в то время как реверсирование может работать просто путем итерации от последнего индекса к первому.
|
||||
- В отличие от метода `sorted`, метод `reversed` возвращает итератор. Почему? Потому что сортировка требует, чтобы итератор либо изменялся на месте, либо использовал дополнительный контейнер (список), в то время как реверсирование может работать просто путем итерации от последнего индекса к первому.
|
||||
|
||||
- Поэтому при сравнении `sorted(y) == sorted(y)` первый вызов `sorted()` будет потреблять итератор `y`, а следующий вызов просто вернет пустой список.
|
||||
|
||||
@ -2992,7 +3052,7 @@ if noon_time:
|
||||
|
||||
Секция содержит менее известные интересные нюансы работы Python, которые неизвестны большинству новичков.
|
||||
|
||||
### ▶ Python, можешь ли ты помочь взлелеть?
|
||||
### ▶ Python, можешь ли ты помочь взлететь?
|
||||
<!-- Example ID: a92f3645-1899-4d50-9721-0031be4aec3f --->
|
||||
Что ж, поехали
|
||||
|
||||
@ -3007,7 +3067,7 @@ Sshh... It's a super-secret.
|
||||
|
||||
+ Модуль `antigravity` - одно из немногих пасхальных яиц, выпущенных разработчиками 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 --->
|
||||
**Ключевое слово `else` в связвке с циклом `for`.** Один из стандартных примеров:
|
||||
**Ключевое слово `else` в связке с циклом `for`.** Один из стандартных примеров:
|
||||
|
||||
```py
|
||||
def does_exists_num(l, to_find):
|
||||
@ -3239,7 +3299,7 @@ Ellipsis
|
||||
- Многоточие может использоваться в нескольких случаях,
|
||||
+ В качестве заполнителя для кода, который еще не написан (аналогично оператору `pass`)
|
||||
+ В синтаксисе срезов (slices) для представления полных срезов в оставшемся направлении
|
||||
``py
|
||||
```py
|
||||
>>> import numpy as np
|
||||
>>> three_dimensional_array = np.arange(8).reshape(2, 2, 2)
|
||||
array([
|
||||
@ -3264,7 +3324,7 @@ Ellipsis
|
||||
[5, 7]])
|
||||
```
|
||||
Примечание: это будет работать для любого количества измерений. Можно даже выбрать срез в первом и последнем измерении и игнорировать средние (`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` в качестве аргумента функции по умолчанию (в случаях, когда вы хотите провести различие между сценариями "аргумент не передан" и "значение не передано").
|
||||
|
||||
---
|
||||
@ -3483,7 +3543,7 @@ def square(x):
|
||||
## Секция: Разное
|
||||
|
||||
|
||||
### ▶ `+=` быстрее
|
||||
### ▶ `+=` быстрее `+`
|
||||
<!-- Example ID: bfd19c60-a807-4a26-9598-4912b86ddb36 --->
|
||||
|
||||
```py
|
||||
@ -3587,7 +3647,7 @@ def convert_list_to_string(l, iters):
|
||||
|
||||
>>> %timeit -n100 add_string_with_plus(1000)
|
||||
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)
|
||||
```
|
||||
|
||||
@ -3627,7 +3687,7 @@ KeyError: 1
|
||||
#### 💡 Объяснение:
|
||||
|
||||
+ В 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`, и ключ даже не обязательно должен существовать в словаре. Поэтому попытка неудачного поиска имеет тот же эффект.
|
||||
|
||||
@ -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`.
|
||||
|
||||
* Учитывая, что `a` - это число, `++a` и `--a` являются корректными утверждениями Python, но ведут себя не так, как аналогичные утверждения в таких языках, как C, C++ или Java.
|
||||
|
Loading…
Reference in New Issue
Block a user