2024-10-15 17:06:27 +03:00
< p align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " /images/logo_dark_theme.svg " >
< source media = " (prefers-color-scheme: light) " srcset = " /images/logo.svg " >
< img alt = " Логотип wtfpython " src = " /images/logo.svg " >
< / picture >
< / p >
2024-01-25 11:19:34 +03:00
< h1 align = " center " > What the f * ck Python ! 😱 < / h1 >
2024-04-27 12:21:12 +03:00
< p align = " center " > Изучение и понимание Python с помощью удивительных примеров поведения . < / p >
2024-01-25 11:19:34 +03:00
2024-05-04 19:58:02 +03:00
Переводы : [ 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 / master / translations / ru - russian ) | [ German Deutsch ] ( https : / / github . com / BenSt099 / wtfpython ) | [ Add translation ] ( https : / / github . com / satwikkansal / wtfpython / issues / new ? title = Add % 20 translation % 20 for % 20 [ LANGUAGE ] & body = Expected % 20 time % 20 to % 20 finish : % 20 [ X ] % 20 weeks . % 20 I % 27 ll % 20 start % 20 working % 20 on % 20 it % 20 from % 20 [ Y ] . )
2024-01-25 11:19:34 +03:00
2024-10-17 15:10:47 +03:00
Альтернативные способы : [ Интерактивный сайт ] ( https : / / wtfpython - interactive . vercel . app ) | [ Интерактивный Jupiter notebook ] ( https : / / colab . research . google . com / github / satwikkansal / wtfpython / blob / master / irrelevant / wtf . ipynb )
2024-01-25 11:19:34 +03:00
2024-04-27 12:21:12 +03:00
Python , будучи прекрасно спроектированным высокоуровневым языком программирования , предоставляет множество возможностей для удобства программиста . Н о иногда поведение Python кода могут показаться запутывающим на первый взгляд .
2024-01-25 11:19:34 +03:00
2024-04-27 12:21:12 +03:00
* * wtfpython * * задуман как проект , пытающийся объяснить , что именно происходит под капотом неочевидных фрагментов кода и малоизвестных возможностей Python .
2024-01-25 11:19:34 +03:00
2024-04-27 12:21:12 +03:00
Если вы опытный питонист , вы можете принять это как вызов и правильно объяснить WTF ситуации с первой попытки . Возможно , вы уже сталкивались с некоторыми из них раньше , и я смогу оживить ваши старые добрые воспоминания ! 😅
2024-01-25 11:19:34 +03:00
PS : Если вы уже читали * * wtfpython * * раньше , с изменениями можно ознакомиться [ здесь ] ( https : / / github . com / satwikkansal / wtfpython / releases / ) ( примеры , отмеченные звездочкой - это примеры , добавленные в последней основной редакции ) .
Н у что ж , приступим . . .
2024-01-25 16:34:40 +03:00
# Содержание
2024-04-27 12:21:12 +03:00
- [ Содержание ] ( #содержание)
- [ Структура примера ] ( #структура-примера)
- [ Применение ] ( #применение)
- [ 👀 Примеры ] ( #-примеры)
2024-04-29 06:43:47 +03:00
- [ Раздел : Напряги мозги ! ] ( #раздел-напряги-мозги)
2024-04-27 12:21:12 +03:00
- [ ▶ Первым делом ! ] ( #-первым-делом)
2024-05-04 19:58:02 +03:00
- [ 💡 Обьяснение ] ( #-обьяснение)
2024-04-27 12:21:12 +03:00
- [ ▶ Строки иногда ведут себя непредсказуемо ] ( #-строки-иногда-ведут-себя-непредсказуемо)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение)
2024-04-27 12:21:12 +03:00
- [ ▶ Осторожнее с цепочкой операций ] ( #-осторожнее-с -цепочкой-операций)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-1)
2024-04-27 12:21:12 +03:00
- [ ▶ Как не надо использовать оператор ` is ` ] ( #-как-не-надо-использовать-оператор-is)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-2)
2024-04-27 12:21:12 +03:00
- [ ▶ Мистическое хеширование ] ( #-мистическое-хеширование)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-3)
2024-04-27 12:21:12 +03:00
- [ ▶ В глубине души мы все одинаковы . ] ( #-в-глубине-души-мы-все-одинаковы)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-4)
2024-04-27 12:21:12 +03:00
- [ ▶ Беспорядок внутри порядка \* ] ( #-беспорядок-внутри-порядка-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-5)
2024-04-27 12:21:12 +03:00
- [ ▶ Продолжай пытаться . . . \* ] ( #-продолжай-пытаться-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-6)
2024-04-27 12:21:12 +03:00
- [ ▶ Для чего ? ] ( #-для-чего)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-7)
2024-04-27 12:21:12 +03:00
- [ ▶ Расхождение во времени исполнения ] ( #-расхождение-во-времени-исполнения)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-8)
2024-04-27 12:21:12 +03:00
- [ ▶ ` is not . . . ` не является ` is ( not . . . ) ` ] ( #-is-not--не-является-is-not-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-9)
2024-04-27 12:21:12 +03:00
- [ ▶ Крестики - нолики , где X побеждает с первой попытки ! ] ( #-крестики-нолики-где-x-побеждает-с -первой-попытки)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-10)
2024-04-27 12:21:12 +03:00
- [ ▶ Переменная Шредингера \* ] ( #-переменная-шредингера-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-11)
2024-04-27 12:21:12 +03:00
- [ ▶ Проблема курицы и яйца \* ] ( #-проблема-курицы-и-яйца-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-12)
2024-04-27 12:21:12 +03:00
- [ ▶ Отношения между подклассами ] ( #-отношения-между-подклассами)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-13)
2024-04-27 12:21:12 +03:00
- [ ▶ Равенство и тождество методов ] ( #-равенство-и-тождество-методов)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-14)
2024-04-27 12:21:12 +03:00
- [ ▶ All - true - ation ( непереводимая игра слов ) \* ] ( #-all-true-ation-непереводимая-игра-слов-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-15)
- [ 💡 Объяснение : ] ( #-объяснение-16)
2024-04-27 12:21:12 +03:00
- [ ▶ Строки и обратные слэши ] ( #-строки-и-обратные-слэши)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-17)
2024-04-27 12:21:12 +03:00
- [ ▶ Н е узел ! ( англ . not knot ! ) ] ( #-не-узел-англ-not-knot)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-18)
2024-04-27 12:21:12 +03:00
- [ ▶ Строки , наполовину обернутые в тройные кавычки ] ( #-строки-наполовину-обернутые-в-тройные-кавычки)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-19)
2024-04-27 12:21:12 +03:00
- [ ▶ Что не так с логическими значениями ? ] ( #-что-не-так-с -логическими-значениями)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-20)
2024-04-27 12:21:12 +03:00
- [ ▶ Атрибуты класса и экземпляра ] ( #-атрибуты-класса-и-экземпляра)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-21)
2024-04-27 12:21:12 +03:00
- [ ▶ Возврат None из генератора ] ( #-возврат-none-из-генератора)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-22)
2024-04-27 12:21:12 +03:00
- [ ▶ Yield from возвращает . . . \* ] ( #-yield-from-возвращает-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-23)
2024-04-27 12:21:12 +03:00
- [ ▶ Nan - рефлексивность \* ] ( #-nan-рефлексивность-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-24)
2024-04-27 12:21:12 +03:00
- [ ▶ Изменяем неизменяемое ! ] ( #-изменяем-неизменяемое)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-25)
2024-04-27 12:21:12 +03:00
- [ ▶ Исчезающая переменная из внешней области видимости ] ( #-исчезающая-переменная-из-внешней-области-видимости)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-26)
2024-04-27 12:21:12 +03:00
- [ ▶ Загадочное преобразование типов ключей ] ( #-загадочное-преобразование-типов-ключей)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-27)
2024-04-27 12:21:12 +03:00
- [ ▶ Посмотрим , сможете ли вы угадать что здесь ? ] ( #-посмотрим-сможете-ли-вы-угадать-что-здесь)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-28)
2024-04-27 12:21:12 +03:00
- [ ▶ Превышение предела целочисленного преобразования строк ] ( #-превышение-предела-целочисленного-преобразования-строк)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-29)
2024-04-29 06:43:47 +03:00
- [ Раздел : Скользкие склоны ] ( #раздел-скользкие-склоны)
2024-04-27 12:21:12 +03:00
- [ ▶ Изменение словаря во время прохода по нему ] ( #-изменение-словаря-во-время-прохода-по-нему)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-30)
2024-04-27 12:21:12 +03:00
- [ ▶ Упрямая операция ` del ` ] ( #-упрямая-операция-del)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-31)
2024-04-27 12:21:12 +03:00
- [ ▶ Переменная за пределами видимости ] ( #-переменная-за-пределами-видимости)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-32)
2024-04-27 12:21:12 +03:00
- [ ▶ Удаление элемента списка во время прохода по списку ] ( #-удаление-элемента-списка-во-время-прохода-по-списку)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-33)
2024-04-27 12:21:12 +03:00
- [ ▶ Сжатие итераторов с потерями \* ] ( #-сжатие-итераторов-с -потерями-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-34)
2024-04-27 12:21:12 +03:00
- [ ▶ Утечка переменных внутри цикла ] ( #-утечка-переменных-внутри-цикла)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-35)
2024-04-27 12:21:12 +03:00
- [ ▶ Остерегайтесь изменяемых аргументов по умолчанию ! ] ( #-остерегайтесь-изменяемых-аргументов-по-умолчанию)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-36)
2024-04-27 12:21:12 +03:00
- [ ▶ Ловля исключений ] ( #-ловля-исключений)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-37)
2024-04-27 12:21:12 +03:00
- [ ▶ Одни и те же операнды , разная история ! ] ( #-одни-и-те-же-операнды-разная-история)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-38)
2024-04-27 12:21:12 +03:00
- [ ▶ Разрешение имен игнорирует область видимости класса ] ( #-разрешение-имен-игнорирует-область-видимости-класса)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-39)
2024-04-27 12:21:12 +03:00
- [ ▶ Округляясь как банкир \* ] ( #-округляясь-как-банкир-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-40)
2024-04-27 12:21:12 +03:00
- [ ▶ Иголки в стоге сена \* ] ( #-иголки-в-стоге-сена-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-41)
2024-04-27 12:21:12 +03:00
- [ ▶ Сплиты ( splitsies ) \* ] ( #-сплиты-splitsies-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-42)
2024-04-27 12:21:12 +03:00
- [ ▶ Подстановочное импортирование ( wild imports ) \* ] ( #-подстановочное-импортирование-wild-imports-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-43)
2024-04-27 12:21:12 +03:00
- [ ▶ В с е ли отсортировано ? \* ] ( #-все-ли-отсортировано-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-44)
2024-04-27 12:21:12 +03:00
- [ ▶ Полночи не существует ? ] ( #-полночи-не-существует)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-45)
2024-04-29 06:43:47 +03:00
- [ Раздел : Скрытые сокровища ! ] ( #раздел-скрытые-сокровища)
2024-04-27 12:21:12 +03:00
- [ ▶ Python , можешь ли ты помочь взлететь ? ] ( #-python-можешь-ли-ты-помочь-взлететь)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-46)
2024-04-27 12:21:12 +03:00
- [ ▶ ` goto ` , но почему ? ] ( #-goto-но-почему)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-47)
2024-04-27 12:21:12 +03:00
- [ ▶ Держитесь ! ] ( #-держитесь)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-48)
2024-04-27 12:21:12 +03:00
- [ ▶ Давайте познакомимся с дружелюбным Дядей Барри ] ( #-давайте-познакомимся-с -дружелюбным-дядей-барри)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-49)
2024-04-27 12:21:12 +03:00
- [ ▶ Даже Python понимает , что любовь - это сложно . ] ( #-даже-python-понимает-что-любовь---это-сложно)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-50)
2024-04-27 12:21:12 +03:00
- [ ▶ Да , оно существует ! ] ( #-да-оно-существует)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-51)
2024-04-27 12:21:12 +03:00
- [ ▶ Многоточие \* ] ( #-многоточие-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-52)
2024-04-27 12:21:12 +03:00
- [ ▶ Писконечность ( Inpinity ) ] ( #-писконечность-inpinity)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-53)
2024-04-27 12:21:12 +03:00
- [ ▶ Давайте искажать ] ( #-давайте-искажать)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-54)
2024-04-29 06:43:47 +03:00
- [ Раздел : Внешность обманчива ! ] ( #раздел-внешность-обманчива)
2024-04-27 12:21:12 +03:00
- [ ▶ Пропускаем строки ? ] ( #-пропускаем-строки)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-55)
2024-04-27 12:21:12 +03:00
- [ ▶ Телепортация ] ( #-телепортация)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-56)
2024-04-27 12:21:12 +03:00
- [ ▶ Что - то не так . . . ] ( #-что-то-не-так)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-57)
2024-04-29 06:43:47 +03:00
- [ Раздел : Разное ] ( #раздел-разное)
2024-04-27 12:21:12 +03:00
- [ ▶ ` + = ` быстрее ` + ` ] ( #--быстрее-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-58)
2024-04-27 12:21:12 +03:00
- [ ▶ Сделаем гигантскую строку ! ] ( #-сделаем-гигантскую-строку)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение ] ( #-объяснение-59)
2024-04-27 12:21:12 +03:00
- [ ▶ Замедляем поиск по ` dict ` \* ] ( #-замедляем-поиск-по-dict-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-60)
2024-04-27 12:21:12 +03:00
- [ ▶ Раздуваем экземпляры словарей \* ] ( #-раздуваем-экземпляры-словарей-)
2024-05-04 19:58:02 +03:00
- [ 💡 Объяснение : ] ( #-объяснение-61)
2024-04-27 12:21:12 +03:00
- [ ▶ Минорное \* ] ( #-минорное-)
- [ Вклад в проект ] ( #вклад-в-проект)
- [ Благодарности ] ( #благодарности)
2024-05-04 19:58:02 +03:00
- [ Несколько хороших ссылок ! ] ( #несколько-хороших-ссылок)
2024-04-27 12:21:12 +03:00
- [ 🎓 Лицензия ] ( #-лицензия)
- [ Удиви своих друзей ! ] ( #удиви-своих-друзей)
- [ Нужна PDF версия ? ] ( #нужна-pdf-версия)
2024-01-25 16:34:40 +03:00
# Структура примера
В с е примеры имеют следующую структуру :
> ### ▶ Какой-то заголовок
>
> ` ` ` py
> # Неочевидный фрагмент кода
> # Подготовка к магии...
> ` ` `
>
> * * Вывод ( Python версия ) : * *
>
> ` ` ` py
> >> > triggering_statement
> Неожиданные результаты
> ` ` `
>
> ( Опционально ) : Краткое описание неожиданного результата
>
>
> #### 💡 Объяснение
>
> * Краткое объяснение того , что происходит и почему это происходит .
>
> ` ` ` py
> # Код
> # Дополнительные примеры для дальнейшего разъяснения (если необходимо)
> ` ` `
>
> * * Вывод ( Python версия ) : * *
>
> ` ` ` py
> >> > trigger # какой-нибудь пример, позволяющий легко раскрыть магию
> # обоснованный вывод
> ` ` `
* * Важно : * * В с е примеры протестированы на интерактивном интерпретаторе Python 3.5 .2 , и они должны работать для всех версий Python , если это явно не указано перед выводом .
2024-01-25 16:43:04 +03:00
# Применение
Хороший способ получить максимальную пользу от этих примеров - читать их последовательно , причем для каждого из них важно :
2024-04-27 12:21:12 +03:00
- Внимательно изучить исходный код . Если вы опытный Python программист , то в большинстве случаев сможете предугадать , что произойдет дальше .
2024-01-25 16:43:04 +03:00
- Прочитать фрагменты вывода и ,
- Проверить , совпадают ли выходные данные с вашими ожиданиями .
- Убедиться , что вы знаете точную причину , по которой вывод получился именно таким .
2024-04-27 12:21:12 +03:00
- Если ответ отрицательный ( что совершенно нормально ) , сделать глубокий вдох и прочитать объяснение ( а если пример все еще непонятен , и создайте [ issue ] ( https : / / github . com / satwikkansal / wtfpython / issues / new ) ) .
2024-01-25 16:43:04 +03:00
- Если " да " , ощутите мощь своих познаний в Python и переходите к следующему примеру .
2024-01-25 17:01:26 +03:00
# 👀 Примеры
2024-04-29 06:43:47 +03:00
## Раздел: Напряги мозги!
2024-01-25 17:01:26 +03:00
### ▶ Первым делом!
< ! - - Example ID : d3d73936 - 3 cf1 - 4632 - b5ab - 817981338863 - - >
< ! - - read - only - - >
По какой - то причине " моржовый оператор " ( англ . walrus ) ` := ` в Python 3.8 стал довольно популярным . Давайте проверим е г о ,
1 \.
` ` ` py
# Python version 3.8+
>> > a = " wtf_walrus "
>> > a
' wtf_walrus '
>> > a := " wtf_walrus "
File " <stdin> " , line 1
a := " wtf_walrus "
^
SyntaxError : invalid syntax
>> > ( a := " wtf_walrus " ) # А этот код работает
' wtf_walrus '
>> > a
' wtf_walrus '
` ` `
2 \.
` ` ` py
# Python version 3.8+
>> > a = 6 , 9
>> > a
( 6 , 9 )
>> > ( a := 6 , 9 )
( 6 , 9 )
>> > a
6
>> > a , b = 6 , 9 # Типичная распаковка
>> > a , b
( 6 , 9 )
>> > ( a , b = 16 , 19 ) # Упс
File " <stdin> " , line 1
( a , b = 16 , 19 )
^
SyntaxError : invalid syntax
>> > ( a , b := 16 , 19 ) # Н а выводе получаем странный кортеж из 3 элементов
( 6 , 16 , 19 )
>> > a # Значение переменной остается неизменной?
6
>> > b
16
` ` `
#### 💡 Обьяснение
* * Быстрый разбор что такое " моржовый оператор " * *
" Моржовый оператор " ( ` := ` ) был представлен в Python 3.8 , может быть полезен в ситуациях , когда вы хотите присвоить значения переменным в выражении .
` ` ` py
def some_func ( ) :
# Предположим, что здесь выполняются требовательные к ресурсам вычисления
# time.sleep(1000)
return 5
# Поэтому вместо,
if some_func ( ) :
print ( some_func ( ) ) # Плохая практика, поскольку вычисления происходят дважды.
# Или
a = some_func ( )
if a :
print ( a )
# Можно лаконично написать
if a := some_func ( ) :
print ( a )
` ` `
* * Вывод ( > 3.8 ) : * *
` ` ` py
5
5
5
` ` `
Использование ` := ` сэкономило одну строку кода и неявно предотвратило вызов ` some_func ` дважды .
- " выражение присваивания " , не обернутое в скобки , иначе говоря использование моржового оператора , ограничено на верхнем уровне , отсюда ` SyntaxError ` в выражении ` a := " wtf_walrus " ` в первом фрагменте . После оборачивания в скобки , ` a ` было присвоено значение , как и ожидалось .
- В то же время оборачивание скобками выражения , содержащего оператор ` = ` , не допускается . Отсюда синтаксическая ошибка в ` ( a , b = 6 , 9 ) ` .
- Синтаксис моржового оператора имеет вид ` NAME := expr ` , где ` NAME ` - допустимый идентификатор , а ` expr ` - допустимое выражение . Следовательно , упаковка и распаковка итерируемых объектов не поддерживается , что означает ,
- ` ( a := 6 , 9 ) ` эквивалентно ` ( ( a := 6 ) , 9 ) ` и в конечном итоге ` ( a , 9 ) ` ( где значение ` a ` равно ` 6 ` )
` ` ` py
>> > ( a := 6 , 9 ) == ( ( a := 6 ) , 9 )
True
>> > x = ( a := 696 , 9 )
>> > x
( 696 , 9 )
>> > x [ 0 ] is a # О б а ссылаются на одну и ту же ячейку памяти
True
` ` `
- Аналогично , ` ( a , b := 16 , 19 ) ` эквивалентно ` ( a , ( b := 16 ) , 19 ) ` , которое есть не что иное , как кортеж из 3 элементов .
- - -
2024-01-30 21:33:44 +03:00
### ▶ Строки иногда ведут себя непредсказуемо
< ! - - Example ID : 30 f1d3fc - e267 - 4 b30 - 84 ef - 4 d9e7091ac1a - - - >
1 \.
` ` ` py
>> > a = " some_string "
>> > id ( a )
140420665652016
>> > id ( " some " + " _ " + " string " ) # Обратите внимание, о б а идентификатора одинаковы
140420665652016
` ` `
2 \.
` ` ` py
>> > a = " wtf "
>> > b = " wtf "
>> > a is b
True
>> > a = " wtf! "
>> > b = " wtf! "
>> > a is b
False
` ` `
3 \.
` ` ` py
>> > a , b = " wtf! " , " wtf! "
>> > a is b # Актуально для версий Python, кроме 3.7.x
True
>> > a = " wtf! " ; b = " wtf! "
>> > a is b # Выражение вернет True или False в зависимости вызываемой среды (python shell / ipython / скрипт).
False
` ` `
` ` ` py
# Н а этот раз в файле
a = " wtf! "
b = " wtf! "
print ( a is b )
# Выводит True при запуске модуля
` ` `
4 \.
* * Output ( < Python3 .7 ) * *
` ` ` py
>> > ' a ' * 20 is ' aaaaaaaaaaaaaaaaaaaa '
True
>> > ' a ' * 21 is ' aaaaaaaaaaaaaaaaaaaaa '
False
` ` `
Логично , правда ?
#### 💡 Объяснение
- Поведение в первом и втором фрагментах связано с оптимизацией CPython ( называемой интернированием строк ( ( англ . string interning ) ) ) , которая пытается использовать существующие неизменяемые объекты в некоторых случаях вместо того , чтобы каждый раз создавать новый объект .
- После " интернирования " многие переменные могут ссылаться на один и тот же строковый объект в памяти ( тем самым экономя память ) .
- В приведенных выше фрагментах строки неявно интернированы . Решение о том , когда неявно интернировать строку , зависит от реализации . Правила для интернирования строк следующие :
- В с е строки длиной 0 или 1 символа интернируются .
2024-04-18 14:45:13 +03:00
- Строки интернируются во время компиляции ( ` ' wtf ' ` будет интернирована , но ` ' ' . join ( [ ' w ' ' , ' t ' , ' f ' ])` - нет)
2024-01-30 21:33:44 +03:00
- Строки , не состоящие из букв ASCII , цифр или знаков подчеркивания , не интернируются . В примере выше ` ' wtf! ' ` не интернируется из - за ` ! ` . Реализацию этого правила в CPython можно найти [ здесь ] ( https : / / github . com / python / cpython / blob / 3.6 / Objects / codeobject . c #L19)
2024-10-15 17:06:27 +03:00
< p align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " /images/string-intern/string_interning_dark_theme.svg " >
< source media = " (prefers-color-scheme: light) " srcset = " /images/string-intern/string_interning.svg " >
< img alt = " Процесс интернирования строк. " src = " /images/string-intern/string_interning.svg " >
< / picture >
< / p >
2024-04-27 12:21:12 +03:00
- Когда переменные ` a ` и ` b ` принимают значение ` " wtf! " ` в одной строке , интерпретатор Python создает новый объект , а затем одновременно ссылается на вторую переменную . Если это выполняется в отдельных строках , он не " знает " , что уже существует ` " wtf! " ` как объект ( потому что ` " wtf! " ` не является неявно интернированным в соответствии с фактами , упомянутыми выше ) . Это оптимизация во время компиляции , не применяется к версиям CPython 3.7 . x ( более подробное обсуждение смотрите [ здесь ] ( https : / / github . com / satwikkansal / wtfpython / issues / 100 ) ) .
2024-01-30 21:33:44 +03:00
- Единица компиляции в интерактивной среде 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 ) .
- - -
2024-04-18 14:45:13 +03:00
### ▶ Осторожнее с цепочкой операций
< ! - - Example ID : 07974979 - 9 c86 - 4720 - 80 bd - 467 aa19470d9 - - - >
` ` ` py
>> > ( False == False ) in [ False ] # логично
False
>> > False == ( False in [ False ] ) # все еще логично
False
>> > False == False in [ False ] # а теперь что?
True
>> > True is False == False
False
>> > False is False is False
True
>> > 1 > 0 < 1
True
>> > ( 1 > 0 ) < 1
False
>> > 1 > ( 0 < 1 )
False
` ` `
#### 💡 Объяснение:
2024-04-27 12:21:12 +03:00
Согласно [ документации ] ( https : / / docs . python . org / 3 / reference / expressions . html #comparisons)
2024-04-18 14:45:13 +03:00
> Формально , если 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 ` и ` 0 < = x < = 100 ` .
* ` False is False is False ` эквивалентно ` ( False is False ) и ( False is False ) ` .
* ` True is False == False ` эквивалентно ` ( True is False ) and ( False == False ) ` и так как первая часть высказывания ( ` True is False ` ) оценивается в ` False ` , то все выражение приводится к ` False ` .
* ` 1 > 0 < 1 ` эквивалентно ` ( 1 > 0 ) и ( 0 < 1 ) ` , которое приводится к ` True ` .
* Выражение ` ( 1 > 0 ) < 1 ` эквивалентно ` True < 1 ` и
` ` ` py
>> > int ( True )
1
>> > True + 1 # не относится к данному примеру, но просто для интереса
2
` ` `
В итоге , ` 1 < 1 ` выполняется и дает результат ` False `
- - -
2024-04-18 15:08:23 +03:00
### ▶ Как не надо использовать оператор `is`
< ! - - Example ID : 230 fa2ac - ab36 - 4 ad1 - b675 - 5 f5a1c1a6217 - - - >
Ниже приведен очень известный пример .
1 \.
` ` ` py
>> > a = 256
>> > b = 256
>> > a is b
True
>> > a = 257
>> > b = 257
>> > a is b
False
` ` `
2 \.
` ` ` py
>> > a = [ ]
>> > b = [ ]
>> > a is b
False
>> > a = tuple ( )
>> > b = tuple ( )
>> > a is b
True
` ` `
3 \.
* * Результат * *
` ` ` py
>> > a , b = 257 , 257
>> > a is b
True
` ` `
* * Вывод ( только для Python 3.7 . x ) * *
` ` ` py
>> > a , b = 257 , 257
>> > a is b
False
` ` `
#### 💡 Объяснение:
* * Разница между ` is ` и ` == ` * * .
* Оператор ` is ` проверяет , ссылаются ли о б а операнда на один и тот же объект ( т . е . проверяет , совпадают ли идентификаторы операндов или нет ) .
* Оператор ` == ` сравнивает значения обоих операндов и проверяет , одинаковы ли они .
* Таким образом , оператор ` is ` предназначен для равенства ссылок , а ` == ` - для равенства значений . Пример , чтобы прояснить ситуацию ,
` ` ` py
>> > class A : pass
>> > A ( ) is A ( ) # 2 пустых объекта в разных ячейках памяти
False
` ` `
* * ` 256 ` - существующий объект , а ` 257 ` - нет * * .
При запуске python числа от ` - 5 ` до ` 256 ` записываются в память . Эти числа используются часто , поэтому имеет смысл просто иметь их наготове .
Перевод цитаты из [ документации ] ( https : / / docs . python . org / 3 / c - api / long . html )
> Текущая реализация хранит массив целочисленных объектов для всех целых чисел от - 5 до 256 , когда вы создаете int в этом диапазоне , вы просто получаете обратно ссылку на существующий объект .
` ` ` py
>> > id ( 256 )
10922528
>> > a = 256
>> > b = 256
>> > id ( a )
10922528
>> > id ( b )
10922528
>> > id ( 257 )
140084850247312
>> > x = 257
>> > y = 257
>> > id ( x )
140084850247440
>> > id ( y )
140084850247344
` ` `
Интерпретатор не понимает , что до выполнения выражения ` y = 257 ` целое число с о значением ` 257 ` уже создано , и поэтому он продолжает создавать другой объект в памяти .
Подобная оптимизация применима и к другим * * изменяемым * * объектам , таким как пустые кортежи . Поскольку списки являются изменяемыми , поэтому ` [ ] is [ ] ` вернет ` False ` , а ` ( ) is ( ) ` вернет ` True ` . Это объясняет наш второй фрагмент . Перейдем к третьему ,
2024-04-27 12:21:12 +03:00
* * И ` a ` , и ` b ` ссылаются на один и тот же объект при инициализации одним и тем же значением в одной и той же строке * * .
2024-04-18 15:08:23 +03:00
* * Вывод * *
` ` ` py
>> > a , b = 257 , 257
>> > id ( a )
140640774013296
>> > id ( b )
140640774013296
>> > a = 257
>> > b = 257
>> > id ( a )
140640774013392
>> > id ( b )
140640774013488
` ` `
* Когда a и b инициализируются с о значением ` 257 ` в одной строке , интерпретатор Python создает новый объект , а затем одновременно ссылается на него во второй переменной . Если делать это в отдельных строках , интерпретатор не " знает " , что объект ` 257 ` уже существует .
2024-04-27 12:21:12 +03:00
* Эта оптимизация компилятора относится именно к интерактивной среде . Когда вы вводите две строки в интерпретаторе , они компилируются отдельно , поэтому оптимизируются отдельно . Если выполнить этот пример в файле ` . py ' , поведение будет отличаться, потому что файл компилируется целиком. Эта оптимизация не ограничивается целыми числами, она работает и для других неизменяемых типов данных, таких как строки (смотреть пример " Строки - это сложно " ) и плавающие числа,
2024-04-18 15:08:23 +03:00
` ` ` py
>> > a , b = 257.0 , 257.0
>> > a is b
True
` ` `
2024-04-27 12:21:12 +03:00
* Почему это не сработало в Python 3.7 ? Абстрактная причина в том , что такие оптимизации компилятора зависят от реализации ( т . е . могут меняться в зависимости от версии , О С и т . д . ) . Я все еще выясняю , какое именно изменение реализации вызвало проблему , вы можете следить за этим [ issue ] ( https : / / github . com / satwikkansal / wtfpython / issues / 100 ) для получения обновлений .
2024-04-18 15:08:23 +03:00
- - -
2024-04-19 12:10:22 +03:00
2024-04-27 12:21:12 +03:00
### ▶ Мистическое хеширование
2024-04-19 12:10:22 +03:00
< ! - - Example ID : eb17db53 - 49 fd - 4 b61 - 85 d6 - 345 c5ca213ff - - - >
1 \.
` ` ` py
some_dict = { }
some_dict [ 5.5 ] = " JavaScript "
some_dict [ 5.0 ] = " Ruby "
some_dict [ 5 ] = " Python "
` ` `
* * Вывод : * *
` ` ` py
>> > some_dict [ 5.5 ]
" JavaScript "
>> > some_dict [ 5.0 ] # "Python" уничтожил "Ruby"?
" Python "
>> > some_dict [ 5 ]
" Python "
>> > complex_five = 5 + 0 j
>> > type ( complex_five )
complex
>> > some_dict [ complex_five ]
" Python "
` ` `
Так почему же Python повсюду ?
#### 💡 Объяснение
2024-04-27 12:21:12 +03:00
* Уникальность ключей в словаре Python определяется * эквивалентностью * , а не тождеством . Поэтому , даже если ` 5 ` , ` 5.0 ` и ` 5 + 0 j ` являются различными объектами разных типов , поскольку они эквивалентны , они не могут находиться в одном и том же ` dict ` ( или ` set ` ) . Как только вы вставите любой из них , попытка поиска по любому другому , но эквивалентному ключу будет успешной с исходным сопоставленным значением ( а не завершится ошибкой ` KeyError ` ) :
2024-04-19 12:10:22 +03:00
` ` ` py
>> > 5 == 5.0 == 5 + 0 j
True
>> > 5 is not 5.0 is not 5 + 0 j
True
>> > some_dict = { }
>> > some_dict [ 5.0 ] = " Ruby "
>> > 5.0 in some_dict
True
>> > ( 5 in some_dict ) and ( 5 + 0 j in some_dict )
True
` ` `
2024-04-27 12:21:12 +03:00
* Это применимо и во время присваивания значения элементу . Поэтому , в выражении ` some_dict [ 5 ] = " Python " ` Python находит существующий элемент с эквивалентным ключом ` 5.0 - > " Ruby " ` , перезаписывает е г о значение на место , а исходный ключ оставляет в покое .
2024-04-19 12:10:22 +03:00
` ` ` py
>> > some_dict
{ 5.0 : ' Ruby ' }
>> > some_dict [ 5 ] = " Python "
>> > some_dict
{ 5.0 : ' Python ' }
` ` `
2024-04-27 12:21:12 +03:00
* Итак , как мы можем обновить ключ до ` 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` выполняют это условие.
2024-04-19 12:10:22 +03:00
` ` ` py
>> > 5 == 5.0 == 5 + 0 j
True
>> > hash ( 5 ) == hash ( 5.0 ) == hash ( 5 + 0 j )
True
` ` `
2024-04-27 12:21:12 +03:00
* * Примечание : * * Обратное не обязательно верно : Объекты с одинаковыми хэш - значениями сами могут быть неравными . ( Это вызывает так называемую [ хэш - коллизию ] ( https : / / en . wikipedia . org / wiki / Collision_ ( computer_science ) ) и ухудшает производительность постоянного времени , которую обычно обеспечивает хеширование ) .
2024-04-19 12:10:22 +03:00
- - -
### ▶ В глубине души мы все одинаковы.
< ! - - Example ID : 8 f99a35f - 1736 - 43e2 - 920 d - 3 b78ec35da9b - - - >
` ` ` py
class WTF :
pass
` ` `
* * Вывод : * *
` ` ` py
>> > WTF ( ) == WTF ( ) # разные экземпляры класса не могут быть равны
False
>> > WTF ( ) is WTF ( ) # идентификаторы также различаются
False
2024-04-27 12:21:12 +03:00
>> > hash ( WTF ( ) ) == hash ( WTF ( ) ) # хеши тоже должны отличаться
2024-04-19 12:10:22 +03:00
True
>> > id ( WTF ( ) ) == id ( WTF ( ) )
True
` ` `
#### 💡 Объяснение:
2024-04-27 12:21:12 +03:00
* При вызове ` id ` Python создал объект класса ` WTF ` и передал е г о функции ` id ` . Функция ` id ` забирает свой ` id ` ( расположение в памяти ) и выбрасывает объект . Объект уничтожается .
2024-04-19 12:10:22 +03:00
* Когда мы делаем это дважды подряд , Python выделяет ту же самую область памяти и для второго объекта . Поскольку ( в CPython ) ` id ` использует участок памяти в качестве идентификатора объекта , идентификатор двух объектов одинаков .
* Таким образом , id объекта уникален только во время жизни объекта . После уничтожения объекта или до е г о создания , другой объект может иметь такой же id .
* Н о почему выражение с оператором ` is ` равно ` False ` ? Давайте посмотрим с помощью этого фрагмента .
` ` ` py
class WTF ( object ) :
def __init__ ( self ) : print ( " I " )
def __del__ ( self ) : print ( " D " )
` ` `
* * Вывод : * *
` ` ` py
>> > WTF ( ) is WTF ( )
I
I
D
D
False
>> > id ( WTF ( ) ) == id ( WTF ( ) )
I
D
I
D
True
` ` `
Как вы можете заметить , все дело в порядке уничтожения объектов .
- - -
2024-04-19 12:28:37 +03:00
2024-04-27 12:21:12 +03:00
### ▶ Беспорядок внутри порядка *
2024-04-19 12:28:37 +03:00
< ! - - Example ID : 91 bff1f8 - 541 d - 455 a - 9 de4 - 6 cd8ff00ea66 - - - >
` ` ` py
from collections import OrderedDict
dictionary = dict ( )
dictionary [ 1 ] = ' a ' ; dictionary [ 2 ] = ' b ' ;
ordered_dict = OrderedDict ( )
ordered_dict [ 1 ] = ' a ' ; ordered_dict [ 2 ] = ' b ' ;
another_ordered_dict = OrderedDict ( )
another_ordered_dict [ 2 ] = ' b ' ; another_ordered_dict [ 1 ] = ' a ' ;
class DictWithHash ( dict ) :
"""
2024-04-27 12:21:12 +03:00
Словарь с реализованным методом __hash__ .
2024-04-19 12:28:37 +03:00
"""
__hash__ = lambda self : 0
class OrderedDictWithHash ( OrderedDict ) :
"""
2024-04-27 12:21:12 +03:00
OrderedDict с реализованным методом __hash__ .
2024-04-19 12:28:37 +03:00
"""
__hash__ = lambda self : 0
` ` `
* * Вывод * *
` ` ` py
>> > dictionary == ordered_dict # a == b
True
>> > dictionary == another_ordered_dict # b == c
True
>> > ordered_dict == another_ordered_dict # почему же c != a ??
False
2024-04-27 12:21:12 +03:00
# Мы все знаем, что множество состоит из уникальных элементов,
2024-04-19 12:28:37 +03:00
# давайте попробуем составить множество из этих словарей и посмотрим, что получится...
>> > len ( { dictionary , ordered_dict , another_ordered_dict } )
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
TypeError : unhashable type : ' dict '
# Логично, поскольку в словаре не реализовано магический метод __hash__, попробуем использовать
# наши классы-обертки.
>> > dictionary = DictWithHash ( )
>> > dictionary [ 1 ] = ' a ' ; dictionary [ 2 ] = ' b ' ;
>> > ordered_dict = OrderedDictWithHash ( )
>> > ordered_dict [ 1 ] = ' a ' ; ordered_dict [ 2 ] = ' b ' ;
>> > another_ordered_dict = OrderedDictWithHash ( )
>> > another_ordered_dict [ 2 ] = ' b ' ; another_ordered_dict [ 1 ] = ' a ' ;
>> > len ( { dictionary , ordered_dict , another_ordered_dict } )
1
2024-04-27 12:21:12 +03:00
>> > len ( { ordered_dict , another_ordered_dict , dictionary } ) # изменим порядок элементов
2024-04-19 12:28:37 +03:00
2
` ` `
Что здесь происходит ?
#### 💡 Объяснение:
2024-04-27 12:21:12 +03:00
- Переходное ( интранзитивное ) равенство между ` dictionary ` , ` ordered_dict ` и ` another_ordered_dict ` не выполняется из - за реализации магического метода ` __eq__ ` в классе ` OrderedDict ` . Перевод цитаты из [ документации ] ( https : / / docs . python . org / 3 / library / collections . html #ordereddict-objects)
2024-04-19 12:28:37 +03:00
> Тесты равенства между объектами OrderedDict чувствительны к порядку и реализуются как ` list ( od1 . items ( ) ) == list ( od2 . items ( ) ) ` . Тесты на равенство между объектами ` OrderedDict ` и другими объектами Mapping нечувствительны к порядку , как обычные словари .
- Причина такого поведения равенства в том , что оно позволяет напрямую подставлять объекты ` OrderedDict ` везде , где используется обычный словарь .
- Итак , почему изменение порядка влияет на длину генерируемого объекта ` set ` ? Ответ заключается только в отсутствии переходного равенства . Поскольку множества являются " неупорядоченными " коллекциями уникальных элементов , порядок вставки элементов не должен иметь значения . Н о в данном случае он имеет значение . Давайте немного разберемся в этом ,
` ` ` py
>> > some_set = set ( )
>> > some_set . add ( dictionary ) # используем объекты из фрагмента кода выше
>> > ordered_dict in some_set
True
>> > some_set . add ( ordered_dict )
>> > len ( some_set )
1
>> > another_ordered_dict in some_set
True
>> > some_set . add ( another_ordered_dict )
>> > len ( some_set )
1
>> > another_set = set ( )
>> > another_set . add ( ordered_dict )
>> > another_ordered_dict in another_set
False
>> > another_set . add ( another_ordered_dict )
>> > len ( another_set )
2
>> > dictionary in another_set
True
>> > another_set . add ( another_ordered_dict )
>> > len ( another_set )
2
` ` `
Таким образом , выражение ` another_ordered_dict ` в ` another_set ` равно ` False ` , потому что ` ordered_dict ` уже присутствовал в ` another_set ` и , как было замечено ранее , ` ordered_dict == another_ordered_dict ` равно ` False ` .
- - -
2024-04-19 12:36:33 +03:00
### ▶ Продолжай пытаться... *
< ! - - Example ID : b4349443 - e89f - 4 d25 - a109 - 82616 be9d41a - - - >
` ` ` py
def some_func ( ) :
try :
return ' from_try '
finally :
return ' from_finally '
def another_func ( ) :
for _ in range ( 3 ) :
try :
continue
finally :
print ( " Finally! " )
def one_more_func ( ) : # Попался!
try :
for i in range ( 3 ) :
try :
1 / i
except ZeroDivisionError :
# Вызовем исключение и обработаем е г о за пределами цикла
raise ZeroDivisionError ( " A trivial divide by zero error " )
finally :
print ( " Iteration " , i )
break
except ZeroDivisionError as e :
print ( " Zero division error occurred " , e )
` ` `
* * Результат : * *
` ` ` py
>> > some_func ( )
' from_finally '
>> > another_func ( )
Finally !
Finally !
Finally !
>> > 1 / 0
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
ZeroDivisionError : division by zero
>> > one_more_func ( )
Iteration 0
` ` `
#### 💡 Объяснение:
2024-04-27 12:21:12 +03:00
- Когда один из операторов ` return ` , ` break ` или ` continue ` выполняется в блоке ` try ` оператора " try...finally " , на выходе также выполняется блок ` finally ` .
2024-04-19 12:36:33 +03:00
- Возвращаемое значение функции определяется последним выполненным оператором ` return ` . Поскольку блок ` finally ` выполняется всегда , оператор ` return ` , выполненный в блоке ` finally ` , всегда будет последним .
- Предостережение - если в блоке ` finally ` выполняется оператор ` return ` или ` break ` , то временно сохраненное исключение отбрасывается .
- - -
2024-04-19 12:43:52 +03:00
### ▶ Для чего?
< ! - - Example ID : 64 a9dccf - 5083 - 4 bc9 - 98 aa - 8 aeecde4f210 - - - >
` ` ` py
some_string = " wtf "
some_dict = { }
for i , some_dict [ i ] in enumerate ( some_string ) :
i = 10
` ` `
* * Вывод : * *
` ` ` py
>> > some_dict # Словарь с индексами
{ 0 : ' w ' , 1 : ' t ' , 2 : ' f ' }
` ` `
#### 💡 Объяснение:
* Оператор ` for ` определяется в [ грамматике Python ] ( https : / / docs . python . org / 3 / reference / grammar . html ) как :
` ` `
for_stmt : ' for ' exprlist ' in ' testlist ' : ' suite [ ' else ' ' : ' suite ]
` ` `
Где ` exprlist ` - цель присваивания . Это означает , что эквивалент ` { exprlist } = { next_value } ` * * выполняется для каждого элемента * * в итерируемом объекте .
Интересный пример , иллюстрирующий это :
` ` ` py
for i in range ( 4 ) :
print ( i )
i = 10
` ` `
* * Результат : * *
` ` `
0
1
2
3
` ` `
Н е ожидали , что цикл будет запущен только один раз ?
* * 💡 Объяснение : * * .
- Оператор присваивания ` i = 10 ` никогда не влияет на итерации цикла из - за того , как циклы for работают в Python . Перед началом каждой итерации следующий элемент , предоставляемый итератором ( в данном случае ` range ( 4 ) ` ) , распаковывается и присваивается переменной целевого списка ( в данном случае ` i ` ) .
* Функция ` enumerate ( some_string ) ` на каждой итерации выдает новое значение ` i ` ( счетчик - инкремент ) и символ из ` some_string ` . Затем она устанавливает ( только что присвоенный ) ключ ` i ` словаря ` some_dict ` на этот символ . Развертывание цикла можно упростить следующим образом :
` ` ` py
>> > i , some_dict [ i ] = ( 0 , ' w ' )
>> > i , some_dict [ i ] = ( 1 , ' t ' )
>> > i , some_dict [ i ] = ( 2 , ' f ' )
>> > some_dict
` ` `
- - -
2024-04-19 14:27:26 +03:00
### ▶ Расхождение во времени исполнения
< ! - - Example ID : 6 aa11a4b - 4 cf1 - 467 a - b43a - 810731517e98 - - - >
1 \.
` ` ` py
array = [ 1 , 8 , 15 ]
# Типичный генератор
gen = ( x for x in array if array . count ( x ) > 0 )
array = [ 2 , 8 , 22 ]
` ` `
* * Вывод : * *
` ` ` py
>> > print ( list ( gen ) ) # Куда подевались остальные значения?
[ 8 ]
` ` `
2 \.
` ` ` py
array_1 = [ 1 , 2 , 3 , 4 ]
gen_1 = ( x for x in array_1 )
array_1 = [ 1 , 2 , 3 , 4 , 5 ]
array_2 = [ 1 , 2 , 3 , 4 ]
gen_2 = ( x for x in array_2 )
array_2 [ : ] = [ 1 , 2 , 3 , 4 , 5 ]
` ` `
* * Вывод : * *
` ` ` py
>> > print ( list ( gen_1 ) )
[ 1 , 2 , 3 , 4 ]
>> > print ( list ( gen_2 ) )
[ 1 , 2 , 3 , 4 , 5 ]
` ` `
3 \.
` ` ` py
array_3 = [ 1 , 2 , 3 ]
array_4 = [ 10 , 20 , 30 ]
gen = ( i + j for i in array_3 for j in array_4 )
array_3 = [ 4 , 5 , 6 ]
array_4 = [ 400 , 500 , 600 ]
` ` `
* * Вывод : * *
` ` ` py
>> > print ( list ( gen ) )
[ 401 , 501 , 601 , 402 , 502 , 602 , 403 , 503 , 603 ]
` ` `
2024-04-19 14:31:02 +03:00
#### 💡 Объяснение
2024-04-19 14:27:26 +03:00
- В выражении [ генераторе ] ( https : / / wiki . python . org / moin / Generators ) условие ` in ` оценивается во время объявления , но условие ` if ` оценивается во время выполнения .
- Перед выполнением кода , значение переменной ` array ` изменяется на список ` [ 2 , 8 , 22 ] ` , а поскольку из ` 1 ` , ` 8 ` и ` 15 ` только счетчик ` 8 ` больше ` 0 ` , генератор выдает только ` 8 ` .
- Различия в выводе ` g1 ` и ` g2 ` во второй части связаны с тем , как переменным ` array_1 ` и ` array_2 ` присваиваются новые значения .
- В первом случае ` array_1 ` привязывается к новому объекту ` [ 1 , 2 , 3 , 4 , 5 ] ` , а поскольку ` in ` выражение исполняется во время объявления , оно по - прежнему ссылается на старый объект ` [ 1 , 2 , 3 , 4 ] ` ( который не уничтожается ) .
- В о втором случае присвоение среза ` array_2 ` обновляет тот же старый объект ` [ 1 , 2 , 3 , 4 ] ` до ` [ 1 , 2 , 3 , 4 , 5 ] ` . Следовательно , и ` g2 ` , и ` array_2 ` по - прежнему имеют ссылку на один и тот же объект ( который теперь обновлен до ` [ 1 , 2 , 3 , 4 , 5 ] ` ) .
- Хорошо , следуя приведенной выше логике , не должно ли значение ` list ( gen ) ` в третьем фрагменте быть ` [ 11 , 21 , 31 , 12 , 22 , 32 , 13 , 23 , 33 ] ` ? ( потому что ` array_3 ` и ` array_4 ` будут вести себя так же , как ` array_1 ` ) . Причина , по которой ( только ) значения ` array_4 ` обновляются , объясняется в [ PEP - 289 ] ( https : / / www . python . org / dev / peps / pep - 0289 / #the-details)
> Только крайнее for - выражение исполняется немедленно , остальные выражения откладываются до запуска генератора .
- - -
2024-04-19 14:31:02 +03:00
### ▶ `is not ...` не является `is (not ...)`
< ! - - Example ID : b26fb1ed - 0 c7d - 4 b9c - 8 c6d - 94 a58a055c0d - - - >
` ` ` py
>> > ' something ' is not None
True
>> > ' something ' is ( not None )
False
` ` `
#### 💡 Объяснение
- ` is not ` является единым бинарным оператором , и е г о поведение отличается от раздельного использования ` is ` и ` not ` .
- ` is not ` имеет значение ` False ` , если переменные по о б е стороны оператора указывают на один и тот же объект , и ` True ` в противном случае .
- В примере ` ( not None ) ` оценивается в ` True ` , поскольку значение ` None ` является ` False ` в булевом контексте , поэтому выражение становится ` ' something ' is True ` .
- - -
2024-04-19 14:41:30 +03:00
### ▶ Крестики-нолики, где X побеждает с первой попытки!
< ! - - Example ID : 69329249 - bdcb - 424 f - bd09 - cca2e6705a7a - - - >
` ` ` py
# Инициализируем переменную row
row = [ " " ] * 3 #row i['', '', '']
# Инициализируем игровую сетку
board = [ row ] * 3
` ` `
* * Результат : * *
` ` ` py
>> > board
[ [ ' ' , ' ' , ' ' ] , [ ' ' , ' ' , ' ' ] , [ ' ' , ' ' , ' ' ] ]
>> > board [ 0 ]
[ ' ' , ' ' , ' ' ]
>> > board [ 0 ] [ 0 ]
' '
>> > board [ 0 ] [ 0 ] = " X "
>> > board
[ [ ' X ' , ' ' , ' ' ] , [ ' X ' , ' ' , ' ' ] , [ ' X ' , ' ' , ' ' ] ]
` ` `
2024-04-27 12:21:12 +03:00
Мы же не назначали три ` " Х " ` ?
2024-04-19 14:41:30 +03:00
#### 💡 Объяснение:
Когда мы инициализируем переменную ` row ` , эта визуализация объясняет , что происходит в памяти
2024-10-15 17:06:27 +03:00
< p align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " /images/tic-tac-toe/after_row_initialized_dark_theme.svg " >
< source media = " (prefers-color-scheme: light) " srcset = " /images/tic-tac-toe/after_row_initialized.svg " >
< img alt = " Ячейка памяти после того, как переменная row инициализирована. " src = " /images/tic-tac-toe/after_row_initialized.svg " >
< / picture >
< / p >
2024-04-19 14:41:30 +03:00
А когда переменная ` board ` инициализируется путем умножения ` row ` , вот что происходит в памяти ( каждый из элементов ` board [ 0 ] ` , ` board [ 1 ] ` и ` board [ 2 ] ` является ссылкой на тот же список , на который ссылается ` row ` )
2024-10-15 17:06:27 +03:00
< p align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " /images/tic-tac-toe/after_board_initialized_dark_theme.svg " >
< source media = " (prefers-color-scheme: light) " srcset = " /images/tic-tac-toe/after_board_initialized.svg " >
< img alt = " Ячейка памяти после того, как переменная board инициализирована. " src = " /images/tic-tac-toe/after_board_initialized.svg " >
< / picture >
< / p >
2024-04-19 14:41:30 +03:00
Мы можем избежать этого сценария , не используя переменную ` row ` для генерации ` board ` . ( Подробнее в [ issue ] ( https : / / github . com / satwikkansal / wtfpython / issues / 68 ) ) .
` ` ` py
>> > board = [ [ ' ' ] * 3 for _ in range ( 3 ) ]
>> > board [ 0 ] [ 0 ] = " X "
>> > board
[ [ ' X ' , ' ' , ' ' ] , [ ' ' , ' ' , ' ' ] , [ ' ' , ' ' , ' ' ] ]
` ` `
- - -
2024-04-19 15:02:10 +03:00
### ▶ Переменная Шредингера *
< ! - - Example ID : 4 dc42f77 - 94 cb - 4 eb5 - a120 - 8203 d3ed7604 - - - >
` ` ` py
funcs = [ ]
results = [ ]
for x in range ( 7 ) :
def some_func ( ) :
return x
funcs . append ( some_func )
results . append ( some_func ( ) ) # обратите внимание на вызов функции
funcs_results = [ func ( ) for func in funcs ]
` ` `
2024-04-27 12:21:12 +03:00
* * Вывод : * *
2024-04-19 15:02:10 +03:00
` ` ` py
>> > results
[ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
>> > funcs_results
[ 6 , 6 , 6 , 6 , 6 , 6 , 6 ]
` ` `
Значения ` x ` были разными в каждой итерации до добавления ` some_func ` к ` funcs ` , но все функции возвращают ` 6 ` , когда они исполняются после завершения цикла .
2.
` ` ` py
>> > powers_of_x = [ lambda x : x * * i for i in range ( 10 ) ]
>> > [ f ( 2 ) for f in powers_of_x ]
[ 512 , 512 , 512 , 512 , 512 , 512 , 512 , 512 , 512 , 512 ]
` ` `
#### 💡 Объяснение:
* При определении функции внутри цикла , которая использует переменную цикла в своем теле , цикл функции привязывается к * переменной * , а не к е е * значению * . Функция ищет ` x ` в окружающем контексте , а не использует значение ` x ` на момент создания функции . Таким образом , все функции используют для вычислений последнее значение , присвоенное переменной . Мы можем видеть , что используется ` x ` из глобального контекста ( т . е . * не * локальная переменная ) :
` ` ` py
>> > import inspect
>> > inspect . getclosurevars ( funcs [ 0 ] )
ClosureVars ( nonlocals = { } , globals = { ' x ' : 6 } , builtins = { } , unbound = set ( ) )
` ` `
Так как ` x ` - глобальная переменная , можно изменить е е значение , которое будет использовано и возвращено из ` funcs `
` ` ` py
>> > x = 42
>> > [ func ( ) for func in funcs ]
[ 42 , 42 , 42 , 42 , 42 , 42 , 42 ]
` ` `
2024-04-27 12:21:12 +03:00
* Чтобы получить желаемое поведение , вы можете передать переменную цикла как именованную аргумент в функцию . * * Почему это работает ? * * Потому что это определит переменную * внутри * области видимости функции . Она больше не будет обращаться к глобальной области видимости для поиска значения переменной , а создаст локальную переменную , которая будет хранить значение ` x ` в данный момент времени .
2024-04-19 15:02:10 +03:00
` ` ` py
funcs = [ ]
for x in range ( 7 ) :
def some_func ( x = x ) :
return x
funcs . append ( some_func )
` ` `
* * Вывод : * *
` ` ` py
>> > funcs_results = [ func ( ) for func in funcs ]
>> > funcs_results
[ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
` ` `
` x ` больше не используется в глобальной области видимости
` ` ` py
>> > inspect . getclosurevars ( funcs [ 0 ] )
ClosureVars ( nonlocals = { } , globals = { } , builtins = { } , unbound = set ( ) )
` ` `
- - -
2024-04-21 10:32:21 +03:00
### ▶ Проблема курицы и яйца *
< ! - - Example ID : 60730 dc2 - 0 d79 - 4416 - 8568 - 2 a63323b3ce8 - - - >
1 \.
` ` ` py
>> > isinstance ( 3 , int )
True
>> > isinstance ( type , object )
True
>> > isinstance ( object , type )
True
` ` `
2024-04-27 12:21:12 +03:00
Так какой же базовый класс является " родительским " ? Кстати , это еще не все ,
2024-04-21 10:32:21 +03:00
2 \.
` ` ` py
>> > class A : pass
>> > isinstance ( A , A )
False
>> > isinstance ( type , type )
True
>> > isinstance ( object , object )
True
` ` `
3 \.
` ` ` py
>> > issubclass ( int , object )
True
>> > issubclass ( type , object )
True
>> > issubclass ( object , type )
False
` ` `
#### 💡 Объяснение
- ` type ` - это [ метакласс ] ( https : / / realpython . com / python - metaclasses / ) в Python .
- * * В с е * * в Python является ` объектом ` , что включает в себя как классы , так и их объекты ( экземпляры ) .
- Класс ` type ` является метаклассом класса ` object ` , и каждый класс ( включая ` type ` ) наследуется прямо или косвенно от ` object ` .
- У ` object ` и ` type ` нет реального базового класса . Путаница в приведенных выше фрагментах возникает потому , что мы думаем о б этих отношениях ( ` issubclass ` и ` isinstance ` ) в терминах классов Python . Отношения между ` object ` и ` type ` не могут быть воспроизведены в чистом Python . Точнее говоря , следующие отношения не могут быть воспроизведены в чистом Python ,
+ класс A является экземпляром класса B , а класс B является экземпляром класса A .
+ класс A является экземпляром самого себя .
- Эти отношения между ` object ` и ` type ` ( о б а являются экземплярами друг друга , а также самих себя ) существуют в Python из - за " обмана " на уровне реализации .
- - -
2024-04-21 10:41:17 +03:00
### ▶ Отношения между подклассами
< ! - - Example ID : 9 f6d8cf0 - e1b5 - 42 d0 - 84 a0 - 4 cfab25a0bc0 - - - >
* * Вывод : * *
` ` ` py
>> > from collections import Hashable
>> > issubclass ( list , object )
True
>> > issubclass ( object , Hashable )
True
>> > issubclass ( list , Hashable )
False
` ` `
Предполагается , что отношения подклассов должны быть транзитивными , верно ? ( т . е . если ` A ` является подклассом ` B ` , а ` B ` является подклассом ` C ` , то ` A ` _до лже н_ быть подклассом ` C ` )
#### 💡 Объяснение
* Отношения подклассов не обязательно являются транзитивными в Python . Можно переопределить магический метод ` __subclasscheck__ ` в метаклассе .
* Когда вызывается ` issubclass ( cls , Hashable ) ` , он просто ищет не - фальшивый метод " `__hash__` " в ` cls ` или во всем , от чего он наследуется .
2024-04-27 12:21:12 +03:00
* Поскольку ` object ` является хэшируемым , а ` list ` - нет , это нарушает отношение транзитивности .
* Более подробное объяснение можно найти [ здесь ] ( https : / / www . naftaliharris . com / blog / python - subclass - intransitivity / ) .
2024-04-21 10:41:17 +03:00
- - -
2024-04-21 10:57:44 +03:00
### ▶ Равенство и тождество методов
< ! - - Example ID : 94802911 - 48 fe - 4242 - defa - 728 ae893fa32 - - - >
1.
` ` ` py
class SomeClass :
def method ( self ) :
pass
@classmethod
def classm ( cls ) :
pass
@staticmethod
def staticm ( ) :
pass
` ` `
* * Результат : * *
` ` ` py
>> > print ( SomeClass . method is SomeClass . method )
True
>> > print ( SomeClass . classm is SomeClass . classm )
False
>> > print ( SomeClass . classm == SomeClass . classm )
True
>> > print ( SomeClass . staticm is SomeClass . staticm )
True
` ` `
Обращаясь к ` classm ` дважды , мы получаем одинаковый объект , но не * тот же самый * ? Давайте посмотрим , что происходит
с экземплярами ` SomeClass ` :
2.
` ` ` py
o1 = SomeClass ( )
o2 = SomeClass ( )
` ` `
* * Вывод : * *
` ` ` py
>> > print ( o1 . method == o2 . method )
False
>> > print ( o1 . method == o1 . method )
True
>> > print ( o1 . method is o1 . method )
False
>> > print ( o1 . classm is o1 . classm )
False
>> > print ( o1 . classm == o1 . classm == o2 . classm == SomeClass . classm )
True
>> > print ( o1 . staticm is o1 . staticm is o2 . staticm is SomeClass . staticm )
True
` ` `
Повторный доступ к ` классу ` или ` методу ` создает одинаковые , но не * те же самые * объекты для одного и того же экземпляра ` какого - либо класса ` .
#### 💡 Объяснение
* Функции являются [ дескрипторами ] ( https : / / docs . python . org / 3 / howto / descriptor . html ) . Всякий раз , когда к функции обращаются как к
2024-04-27 12:21:12 +03:00
атрибуту , вызывается дескриптор , создавая объект метода , который " связывает " функцию с объектом , владеющим атрибутом . При вызове метод вызывает функцию , неявно передавая связанный объект в качестве первого аргумента
2024-04-21 10:57:44 +03:00
( именно так мы получаем ` self ` в качестве первого аргумента , несмотря на то , что не передаем е г о явно ) .
` ` ` py
>> > o1 . method
< bound method SomeClass . method of < __main__ . SomeClass object at . . . >>
` ` `
* При многократном обращении к атрибуту каждый раз создается объект метода ! Поэтому ` o1 . method is o1 . method ` всегда ложно . Однако доступ к функциям как к атрибутам класса ( в отличие от экземпляра ) не создает методов ; поэтому
` SomeClass . method is SomeClass . method ` является истинным .
` ` ` py
>> > SomeClass . method
< function SomeClass . method at . . . >
` ` `
* ` classmethod ` преобразует функции в методы класса . Методы класса - это дескрипторы , которые при обращении к ним создают
объект метода , который связывает * класс * ( тип ) объекта , а не сам объект .
` ` ` py
>> > o1 . classm
< bound method SomeClass . classm of < class ' __main__ . SomeClass ' >>
` ` `
* В отличие от функций , ` classmethod ` будет создавать метод и при обращении к нему как к атрибуту класса ( в этом случае они
привязываются к классу , а не к е г о типу ) . Поэтому ` SomeClass . classm is SomeClass . classm ` является ошибочным .
` ` ` py
>> > SomeClass . classm
< bound method SomeClass . classm of < class ' __main__ . SomeClass ' >>
` ` `
* Объект - метод равен , если о б е функции равны , а связанные объекты одинаковы . Поэтому
` o1 . method == o1 . method ` является истинным , хотя и не является одним и тем же объектом в памяти .
* ` staticmethod ` преобразует функции в дескриптор " no-op " , который возвращает функцию как есть . Методы - объекты
никогда не создается , поэтому сравнение с ` is ` является истинным .
` ` ` py
>> > o1 . staticm
< function SomeClass . staticm at . . . >
>> > SomeClass . staticm
< function SomeClass . staticm at . . . >
` ` `
* Необходимость создавать новые объекты " метод " каждый раз , когда Python вызывает методы экземпляра , и необходимость изменять аргументы
каждый раз , чтобы вставить ` self ` , сильно сказывается на производительности .
CPython 3.7 [ решил эту проблему ] ( https : / / bugs . python . org / issue26110 ) , введя новые опкоды , которые работают с вызовом методов
без создания временных объектов методов . Это используется только при фактическом вызове функции доступа , так что
приведенные здесь фрагменты не затронуты и по - прежнему генерируют методы : )
- - -
2024-04-22 12:02:32 +03:00
### ▶ All-true-ation (непереводимая игра слов) *
< ! - - Example ID : dfe6d845 - e452 - 48 fe - a2da - 0 ed3869a8042 - - >
` ` ` py
>> > all ( [ True , True , True ] )
True
>> > all ( [ True , True , False ] )
False
>> > all ( [ ] )
True
>> > all ( [ [ ] ] )
False
>> > all ( [ [ [ ] ] ] )
True
` ` `
Почему это изменение True - False ?
#### 💡 Объяснение:
- Реализация функции ` all ` :
- ` ` ` py
def all ( iterable ) :
for element in iterable :
if not element :
return False
return True
` ` `
- ` all ( [ ] ) ` возвращает ` True ` , поскольку итерируемый массив пуст .
- ` all ( [ [ ] ] ) ` возвращает ` False ` , поскольку переданный массив имеет один элемент , ` [ ] ` , а в python пустой список является ложным .
- ` all ( [ [ [ [ ] ] ] ) ` и более высокие рекурсивные варианты всегда ` True ` . Это происходит потому , что единственный элемент переданного массива ( ` [ [ . . . ] ] ` ) уже не пуст , а списки с о значениями являются истинными .
- - -
### ▶ Неожиданная запятая
< ! - - Example ID : 31 a819c8 - ed73 - 4 dcc - 84 eb - 91 bedbb51e58 - - - >
* * Вывод ( < 3.6 ) : * *
` ` ` py
>> > def f ( x , y , ) :
. . . print ( x , y )
. . .
>> > def g ( x = 4 , y = 5 , ) :
. . . print ( x , y )
. . .
>> > def h ( x , * * kwargs , ) :
File " <stdin> " , line 1
def h ( x , * * kwargs , ) :
^
SyntaxError : invalid syntax
>> > def h ( * args , ) :
File " <stdin> " , line 1
def h ( * args , ) :
^
SyntaxError : invalid syntax
` ` `
#### 💡 Объяснение:
- Запятая в конце списка аргументов функции Python не всегда законна .
- В Python список аргументов определяется частично с помощью ведущих запятых , а частично с помощью запятых в конце списка . Этот конфликт приводит к ситуациям , когда запятая оказывается в середине , и ни одно из правил не выполняется .
- * * Примечание : * * Проблема с запятыми в конце списка аргументов [ исправлена в Python 3.6 ] ( https : / / bugs . python . org / issue9232 ) . Варианты использования запятых в конце выражения приведены в [ обсуждении ] ( https : / / bugs . python . org / issue9232 #msg248399).
- - -
2024-04-22 12:08:53 +03:00
### ▶ Строки и обратные слэши
< ! - - Example ID : 6 ae622c3 - 6 d99 - 4041 - 9 b33 - 507 bd1a4407b - - - >
* * Вывод : * *
` ` ` py
>> > print ( " \" " )
"
>> > print ( r " \" " )
\"
>> > print ( r " \" )
File " <stdin> " , line 1
print ( r " \" )
^
SyntaxError : EOL while scanning string literal
>> > r ' \' ' == " \\ ' "
True
` ` `
#### 💡 Объяснение
2024-04-27 12:21:12 +03:00
- В обычной строке обратный слэш используется для экранирования символов , которые могут иметь специальное значение ( например , одинарная кавычка , двойная кавычка и сам обратный слэш ) .
2024-04-22 12:08:53 +03:00
` ` ` py
>> > " wt \" f "
' wt " f '
` ` `
- В необработанном строковом литерале ( на что указывает префикс ` r ` ) обратный слэш передается как есть , вместе с поведением экранирования следующего символа .
` ` ` py
>> > r ' wt \ " f ' == ' wt \\ " f '
True
>> > print ( repr ( r ' wt \ " f ' )
' wt \\ " f '
>> > print ( " \n " )
>> > print ( r " \\ n " )
' \\ n '
` ` `
2024-04-27 12:21:12 +03:00
- Это означает , что когда синтаксический анализатор встречает обратный слэш в необработанной строке , он ожидает , что за ней последует другой символ . А в нашем случае ( ` print ( r " \" )`) обратный слэш экранирует двойную кавычку, оставив синтаксический анализатор без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слэш не работает в конце необработанной строки.
2024-04-22 12:08:53 +03:00
2024-04-27 12:21:12 +03:00
- - -
2024-04-22 12:13:13 +03:00
2024-04-27 12:21:12 +03:00
### ▶ Н е узел! (англ. not knot!)
2024-04-22 12:13:13 +03:00
< ! - - Example ID : 7034 deb1 - 7443 - 417 d - 94 ee - 29 a800524de8 - - - >
` ` ` py
x = True
y = False
` ` `
* * Результат : * *
` ` ` py
>> > not x == y
True
>> > x == not y
File " <input> " , line 1
x == not y
^
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 ) ` , что можно было бы ожидать на первый взгляд .
2024-04-27 12:21:12 +03:00
* Синтаксический анализатор ( англ . parser ) ожидал , что ключевое слово ` not ` будет частью оператора ` not in ` ( потому что о б а оператора ` == ` и ` not in ` имеют одинаковый приоритет ) , но после того , как он не смог найти ключевое слово ` in ` , следующее за ` not ` , он выдает ` SyntaxError ` .
2024-04-22 12:13:13 +03:00
2024-04-22 12:08:53 +03:00
- - -
2024-04-22 12:19:28 +03:00
2024-04-27 12:21:12 +03:00
### ▶ Строки, наполовину обернутые в тройные кавычки
2024-04-22 12:19:28 +03:00
< ! - - Example ID : c55da3e2 - 1034 - 43 b9 - abeb - a7a970a2ad9e - - - >
* * Вывод : * *
` ` ` py
>> > print ( ' wtfpython ' ' ' )
wtfpython
>> > print ( " wtfpython " " " )
wtfpython
>> > # Выражения ниже приводят к `SyntaxError`
>> > # print('''wtfpython')
>> > # print("""wtfpython")
File " <input> " , line 3
print ( """ wtfpython " )
^
SyntaxError : EOF while scanning triple - quoted string literal
` ` `
#### 💡 Объяснение:
+ Python поддерживает неявную [ конкатенацию строковых литералов ] ( https : / / docs . python . org / 3 / reference / lexical_analysis . html #string-literal-concatenation), Пример,
` ` `
>> > print ( " wtf " " python " )
wtfpython
>> > print ( " wtf " " " ) # or "wtf"""
wtf
` ` `
+ ` ''' ` и ` " " " ` также являются разделителями строк в Python, что вызывает SyntaxError, поскольку интерпретатор Python ожидал завершающую тройную кавычку в качестве разделителя при сканировании текущего встреченного строкового литерала с тройной кавычкой.
- - -
2024-04-22 13:58:11 +03:00
### ▶ Что не так с логическими значениями?
< ! - - Example ID : 0 bba5fa7 - 9e6 d - 4 cd2 - 8 b94 - 952 d061af5dd - - - >
1 \.
` ` ` py
# Простой пример счетчика логических переменных и целых чисел
# в итерируемом объекте с о значениями разных типов данных
mixed_list = [ False , 1.0 , " some_string " , 3 , True , [ ] , False ]
integers_found_so_far = 0
booleans_found_so_far = 0
for item in mixed_list :
if isinstance ( item , int ) :
integers_found_so_far + = 1
elif isinstance ( item , bool ) :
booleans_found_so_far + = 1
` ` `
* * Результат : * *
` ` ` py
>> > integers_found_so_far
4
>> > booleans_found_so_far
0
` ` `
2 \.
` ` ` py
>> > some_bool = True
>> > " wtf " * some_bool
' wtf '
>> > some_bool = False
>> > " wtf " * some_bool
' '
` ` `
3 \.
` ` ` py
def tell_truth ( ) :
True = False
if True == False :
print ( " I have lost faith in truth! " )
` ` `
* * Результат ( < 3. x ) : * *
` ` ` py
>> > tell_truth ( )
I have lost faith in truth !
` ` `
#### 💡 Объяснение:
* ` bool ` это подкласс класса ` int ` в Python
` ` ` py
>> > issubclass ( bool , int )
True
>> > issubclass ( int , bool )
False
` ` `
* ` True ` и ` False ` - экземпляры класса ` int `
` ` ` py
>> > isinstance ( True , int )
True
>> > isinstance ( False , int )
True
` ` `
* Целочисленное значение ` True ` равно ` 1 ` , а ` False ` равно ` 0 ` .
` ` ` py
>> > int ( True )
1
>> > int ( False )
0
` ` `
* Объяснение на [ StackOverflow ] ( https : / / stackoverflow . com / a / 8169049 / 4354153 ) .
* Изначально в Python не было типа ` bool ` ( использовали 0 для false и ненулевое значение 1 для true ) . В версиях 2. x были добавлены ` True ` , ` False ` и тип ` bool ` , но для обратной совместимости ` True ` и ` False ` нельзя было сделать константами . Они просто были встроенными переменными , и их можно было переназначить .
2024-04-27 12:21:12 +03:00
* Python 3 несовместим с предыдущими версиями , эту проблему наконец - то исправили , и поэтому последний фрагмент не будет работать с Python 3. x !
2024-04-22 13:58:11 +03:00
- - -
2024-04-22 14:03:16 +03:00
### ▶ Атрибуты класса и экземпляра
< ! - - Example ID : 6 f332208 - 33 bd - 482 d - 8106 - 42863 b739ed9 - - - >
1 \.
` ` ` py
class A :
x = 1
class B ( A ) :
pass
class C ( A ) :
pass
` ` `
* * Результат : * *
` ` ` py
>> > A . x , B . x , C . x
( 1 , 1 , 1 )
>> > B . x = 2
>> > A . x , B . x , C . x
( 1 , 2 , 1 )
>> > A . x = 3
>> > A . x , B . x , C . x # Значение C.x изменилось , но B.x - нет
( 3 , 2 , 3 )
>> > a = A ( )
>> > a . x , A . x
( 3 , 3 )
>> > a . x + = 1
>> > a . x , A . x
( 4 , 3 )
` ` `
2 \.
` ` ` py
class SomeClass :
some_var = 15
some_list = [ 5 ]
another_list = [ 5 ]
def __init__ ( self , x ) :
self . some_var = x + 1
self . some_list = self . some_list + [ x ]
self . another_list + = [ x ]
` ` `
* * Результат : * *
` ` ` py
>> > some_obj = SomeClass ( 420 )
>> > some_obj . some_list
[ 5 , 420 ]
>> > some_obj . another_list
[ 5 , 420 ]
>> > another_obj = SomeClass ( 111 )
>> > another_obj . some_list
[ 5 , 111 ]
>> > another_obj . another_list
[ 5 , 420 , 111 ]
>> > another_obj . another_list is SomeClass . another_list
True
>> > another_obj . another_list is some_obj . another_list
True
` ` `
#### 💡 Объяснение:
* Переменные класса и переменные экземпляров класса внутренне обрабатываются как словари объекта класса . Если имя переменной не найдено в словаре текущего класса , оно ищется в родительских классах .
* Оператор + = изменяет объект на месте , не создавая новый объект . Таким образом , изменение атрибута одного экземпляра влияет на другие экземпляры и атрибут класса также .
- - -
2024-04-22 14:05:53 +03:00
### ▶ Возврат None из генератора
< ! - - Example ID : 5 a40c241 - 2 c30 - 40 d0 - 8 ba9 - cf7e097b3b53 - - - >
` ` ` py
some_iterable = ( ' a ' , ' b ' )
def some_func ( val ) :
return " something "
` ` `
* * Результат ( < = 3.7 . x ) : * *
` ` ` py
>> > [ x for x in some_iterable ]
[ ' a ' , ' b ' ]
>> > [ ( yield x ) for x in some_iterable ]
< generator object < listcomp > at 0x7f70b0a4ad58 >
>> > list ( [ ( yield x ) for x in some_iterable ] )
[ ' a ' , ' b ' ]
>> > list ( ( yield x ) for x in some_iterable )
[ ' a ' , None , ' b ' , None ]
>> > list ( some_func ( ( yield x ) ) for x in some_iterable )
[ ' a ' , ' something ' , ' b ' , ' something ' ]
` ` `
#### 💡 Объяснение:
- Это б а г в обработке yield в генераторах и списочных выражениях CPython .
- Исходный код и объяснение можно найти [ здесь ] ( https : / / stackoverflow . com / questions / 32139885 / yield - in - list - comprehensions - and - generator - expressions )
- Связанный [ отчет о б ошибке ] ( https : / / bugs . python . org / issue10544 )
- В Python 3.8 + yield внутри списочных выражений больше не допускается и выдает ` SyntaxError ` .
- - -
2024-04-22 14:13:11 +03:00
### ▶ Yield from возвращает... *
< ! - - Example ID : 5626 d8ef - 8802 - 49 c2 - adbc - 7 cda5c550816 - - - >
1 \.
` ` ` py
def some_func ( x ) :
if x == 3 :
return [ " wtf " ]
else :
yield from range ( x )
` ` `
* * Результат ( > 3.3 ) : * *
` ` ` py
>> > list ( some_func ( 3 ) )
[ ]
` ` `
Куда исчезло ` " wtf " ` ? Это связано с каким - то особым эффектом ` yield from ` ? Проверим это .
2 \.
` ` ` py
def some_func ( x ) :
if x == 3 :
return [ " wtf " ]
else :
for i in range ( x ) :
yield i
` ` `
* * Результат : * *
` ` ` py
>> > list ( some_func ( 3 ) )
[ ]
` ` `
2024-04-27 12:21:12 +03:00
Опять не сработало . Что происходит ?
2024-04-22 14:13:11 +03:00
#### 💡 Объяснение:
+ С Python 3.3 стало возможным использовать оператор ` return ` в генераторах с возвращением значения ( см . [ PEP380 ] ( https : / / www . python . org / dev / peps / pep - 0380 / ) ) . В [ официальной документации ] ( https : / / www . python . org / dev / peps / pep - 0380 / #enhancements-to-stopiteration) говорится, что
> " ... `return expr` в генераторе вызывает исключение `StopIteration(expr)` при выходе из генератора. "
2024-04-27 12:21:12 +03:00
+ В случае ` some_func ( 3 ) ` ` StopIteration ` возникает в начале из - за оператора ` return ` . Исключение ` StopIteration ` автоматически перехватывается внутри обертки ` list ( . . . ) ` и цикла ` for ` . Поэтому два вышеприведенных фрагмента возвращают пустой список .
2024-04-22 14:13:11 +03:00
+ Чтобы получить ` [ " wtf " ] ` из генератора ` some_func ` , нужно перехватить исключение ` StopIteration ` .
` ` ` py
try :
next ( some_func ( 3 ) )
except StopIteration as e :
some_string = e . value
` ` `
` ` ` py
>> > some_string
[ " wtf " ]
` ` `
- - -
2024-04-22 14:21:35 +03:00
### ▶ Nan-рефлексивность *
< ! - - Example ID : 59 bee91a - 36e0 - 47 a4 - 8 c7d - aa89bf1d3976 - - - >
1 \.
` ` ` py
a = float ( ' inf ' )
b = float ( ' nan ' )
c = float ( ' -iNf ' ) # Эти строки не чувствительны к регистру
d = float ( ' nan ' )
` ` `
* * Результат : * *
` ` ` py
>> > a
inf
>> > b
nan
>> > c
- inf
>> > float ( ' some_other_string ' )
ValueError : could not convert string to float : some_other_string
>> > a == - c # inf==inf
True
>> > None == None # None == None
True
>> > b == d # но nan!=nan
False
>> > 50 / a
0.0
>> > a / a
nan
>> > 23 + b
nan
` ` `
2 \.
` ` ` py
>> > x = float ( ' nan ' )
>> > y = x / x
2024-04-27 12:21:12 +03:00
>> > y is y # идентичность сохраняется
2024-04-22 14:21:35 +03:00
True
>> > y == y # сравнение ложно для y
False
>> > [ y ] == [ y ] # но сравнение истинно для списка, содержащего y
True
` ` `
#### 💡 Объяснение:
- ` ' inf ' ` и ` ' nan ' ` - это специальные строки ( без учета регистра ) , которые при явном приведении к типу ` float ` используются для представления математической " бесконечности " и " не число " соответственно .
2024-04-27 12:21:12 +03:00
- Согласно стандартам IEEE , ` NaN != NaN ` , но соблюдение этого правила нарушает предположение о рефлексивности элемента коллекции в Python , то есть если ` x ` является частью коллекции , такой как ` list ` , реализации методов сравнения предполагают , что ` x == x ` . Поэтому при сравнении элементов сначала сравниваются их идентификаторы ( так как это быстрее ) , а значения сравниваются только при несовпадении идентификаторов . Следующий фрагмент сделает вещи более ясными :
2024-04-22 14:21:35 +03:00
` ` ` py
>> > x = float ( ' nan ' )
>> > x == x , [ x ] == [ x ]
( False , True )
>> > y = float ( ' nan ' )
>> > y == y , [ y ] == [ y ]
( False , True )
>> > x == y , [ x ] == [ y ]
( False , False )
` ` `
Поскольку идентификаторы ` x ` и ` y ` разные , рассматриваются значения , которые также различаются ; следовательно , на этот раз сравнение возвращает ` False ` .
- Интересное чтение : [ Рефлексивность и другие основы цивилизации ] ( https : / / bertrandmeyer . com / 2010 / 02 / 06 / reflexivity - and - other - pillars - of - civilization / )
- - -
2024-04-22 14:33:23 +03:00
2024-04-27 12:21:12 +03:00
### ▶ Изменяем неизменяемое!
2024-04-22 14:33:23 +03:00
< ! - - Example ID : 15 a9e782 - 1695 - 43 ea - 817 a - a9208f6bb33d - - - >
Это может показаться тривиальным , если вы знаете , как работают ссылки в Python .
` ` ` py
some_tuple = ( " A " , " tuple " , " with " , " values " )
another_tuple = ( [ 1 , 2 ] , [ 3 , 4 ] , [ 5 , 6 ] )
` ` `
* * Результат : * *
` ` ` py
>> > some_tuple [ 2 ] = " change this "
TypeError : ' tuple ' object does not support item assignment
>> > another_tuple [ 2 ] . append ( 1000 ) # Н е приводит к исключениям
>> > another_tuple
( [ 1 , 2 ] , [ 3 , 4 ] , [ 5 , 6 , 1000 ] )
>> > another_tuple [ 2 ] + = [ 99 , 999 ]
TypeError : ' tuple ' object does not support item assignment
>> > another_tuple
( [ 1 , 2 ] , [ 3 , 4 ] , [ 5 , 6 , 1000 , 99 , 999 ] )
` ` `
Н о кортежи неизменяемы . . . Что происходит ?
#### 💡 Объяснение:
* Перевод цитаты из [ документации ] ( https : / / docs . python . org / 3 / reference / datamodel . html )
2024-04-27 12:21:12 +03:00
> Объект неизменяемого типа последовательности не может измениться после создания . ( Если объект содержит ссылки на другие объекты , эти объекты могут быть изменяемыми и могут быть изменены ; однако набор объектов , на которые непосредственно ссылается неизменяемый объект , не может изменяться . )
2024-04-22 14:33:23 +03:00
* Оператор ` + = ` изменяет список на месте . Присваивание элемента не работает , но когда возникает исключение , элемент уже был изменен на месте .
* Также есть объяснение в официальном [ Python FAQ ] ( https : / / docs . python . org / 3 / faq / programming . html #why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works).
- - -
2024-04-22 14:51:49 +03:00
### ▶ Исчезающая переменная из внешней области видимости
< ! - - Example ID : 7 f1e71b6 - cb3e - 44 fb - aa47 - 87 ef1b7decc8 - - - >
` ` ` py
e = 7
try :
raise Exception ( )
except Exception as e :
pass
` ` `
* * Результат ( Python 2. x ) : * *
` ` ` py
>> > print ( e )
# Ничего не выводит
` ` `
* * Результат ( Python 3. x ) : * *
` ` ` py
>> > print ( e )
NameError : name ' e ' is not defined
` ` `
#### 💡 Объяснение:
* [ Источник ] ( https : / / docs . python . org / 3 / reference / compound_stmts . html #except)
Когда исключение было назначено с помощью ключевого слова ` as ` , оно очищается в конце блока ` except ` . Это происходит так , как если бы
` ` ` py
except E as N :
foo
` ` `
разворачивалось до
` ` ` py
except E as N :
try :
foo
finally :
del N
` ` `
2024-04-27 12:21:12 +03:00
Это означает , что исключению должно быть присвоено другое имя , чтобы на него можно было ссылаться после завершения блока ` except ` . Исключения очищаются , потому что с прикрепленным к ним трейсбэком они образуют цикл ссылок с о стэком вызовов , сохраняя все локальные объекты в этой стэке до следующей сборки мусора .
2024-04-22 14:51:49 +03:00
* В Python clauses не имеют области видимости . В примере все объекты в одной области видимости , а переменная ` e ` была удалена из - за выполнения блока ` except ` . Этого нельзя сказать о функциях , которые имеют отдельные внутренние области видимости . Пример ниже иллюстрирует это :
2024-04-27 12:21:12 +03:00
` ` ` py
def f ( x ) :
del ( x )
print ( x )
x = 5
y = [ 5 , 4 , 3 ]
` ` `
* * Результат : * *
` ` ` py
>> > f ( x )
UnboundLocalError : local variable ' x ' referenced before assignment
>> > f ( y )
UnboundLocalError : local variable ' x ' referenced before assignment
>> > x
5
>> > y
[ 5 , 4 , 3 ]
` ` `
2024-04-22 14:51:49 +03:00
* В Python 2. x , имя переменной ` e ` назначается на экземпляр ` Exception ( ) ` , и при попытки вывести значение ` e ` ничего не выводится .
* * Результат ( Python 2. x ) : * *
` ` ` py
>> > e
Exception ( )
>> > print e
# Ничего не выводится!
` ` `
- - -
2024-04-22 15:08:54 +03:00
### ▶ Загадочное преобразование типов ключей
< ! - - Example ID : 00 f42dd0 - b9ef - 408 d - 9e39 - 1 bc209ce3f36 - - - >
` ` ` py
class SomeClass ( str ) :
pass
some_dict = { ' s ' : 42 }
` ` `
* * Результат : * *
` ` ` py
>> > type ( list ( some_dict . keys ( ) ) [ 0 ] )
str
>> > s = SomeClass ( ' s ' )
>> > some_dict [ s ] = 40
>> > some_dict # Ожидается 2 разные пары ключ-значение
{ ' s ' : 40 }
>> > type ( list ( some_dict . keys ( ) ) [ 0 ] )
str
` ` `
#### 💡 Объяснение:
* И объект ` s ` , и строка ` " s " ` хэшируются до одного и того же значения , потому что ` SomeClass ` наследует метод ` __hash__ ` класса ` str ` .
* Выражение ` SomeClass ( " s " ) == " s " ` эквивалентно ` True ` , потому что ` SomeClass ` также наследует метод ` __eq__ ` класса ` str ` .
* Поскольку о б а объекта хэшируются на одно и то же значение и равны , они представлены одним и тем же ключом в словаре .
* Чтобы добиться желаемого поведения , мы можем переопределить метод ` __eq__ ` в ` SomeClass ` .
` ` ` py
class SomeClass ( str ) :
def __eq__ ( self , other ) :
return (
type ( self ) is SomeClass
and type ( other ) is SomeClass
and super ( ) . __eq__ ( other )
)
# При переопределении метода __eq__, Python прекращает автоматическое наследование метода
# __hash__, поэтому е г о нужно вручную определить
__hash__ = str . __hash__
some_dict = { ' s ' : 42 }
` ` `
* * Результат : * *
` ` ` py
>> > s = SomeClass ( ' s ' )
>> > some_dict [ s ] = 40
>> > some_dict
{ ' s ' : 40 , ' s ' : 42 }
>> > keys = list ( some_dict . keys ( ) )
>> > type ( keys [ 0 ] ) , type ( keys [ 1 ] )
( __main__ . SomeClass , str )
` ` `
- - -
2024-04-22 15:19:58 +03:00
### ▶ Посмотрим, сможете ли вы угадать что здесь?
< ! - - Example ID : 81 aa9fbe - bd63 - 4283 - b56d - 6 fdd14c9105e - - - >
` ` ` py
a , b = a [ b ] = { } , 5
` ` `
* * Результат : * *
` ` ` py
>> > a
{ 5 : ( { . . . } , 5 ) }
` ` `
#### 💡 Объяснение:
* Согласно [ документации ] ( https : / / docs . python . org / 3 / reference / simple_stmts . html #assignment-statements), выражения присваивания имеют вид
` ` `
( target_list " = " ) + ( expression_list | yield_expression )
` ` `
и
> Оператор присваивания исполняет список выражений ( помните , что это может быть одно выражение или список , разделенный запятыми , в последнем случае получается кортеж ) и присваивает единственный результирующий объект каждому из целевых списков , слева направо .
* ` + ` в ` ( 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
>> > some_list
[ [ . . . ] ]
>> > some_list [ 0 ]
[ [ . . . ] ]
>> > some_list is some_list [ 0 ]
True
>> > some_list [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] == some_list
True
` ` `
Аналогичный случай в примере выше ( ` a [ b ] [ 0 ] ` - это тот же объект , что и ` a ` )
* Подводя итог , можно разбить пример на следующие пункты
` ` ` py
a , b = { } , 5
a [ b ] = a , b
` ` `
А циклическая ссылка может быть оправдана тем , что ` a [ b ] [ 0 ] ` - тот же объект , что и ` a `
` ` ` py
>> > a [ b ] [ 0 ] is a
True
` ` `
- - -
2024-04-22 15:24:31 +03:00
### ▶ Превышение предела целочисленного преобразования строк
` ` ` py
>> > # Python 3.10.6
>> > int ( " 2 " * 5432 )
>> > # Python 3.10.8
>> > int ( " 2 " * 5432 )
` ` `
* * Вывод : * *
` ` ` py
>> > # Python 3.10.6
222222222222222222222222222222222222222222222222222222222222222. . .
>> > # Python 3.10.8
Traceback ( most recent call last ) :
. . .
ValueError : Exceeds the limit ( 4300 ) for integer string conversion :
value has 5432 digits ; use sys . set_int_max_str_digits ( )
to increase the limit .
` ` `
#### 💡 Объяснение:
Этот вызов ` int ( ) ` прекрасно работает в Python 3.10 .6 и вызывает ошибку ` ValueError ` в Python 3.10 .8 , 3.11 . Обратите внимание , что Python все еще может работать с большими целыми числами . Ошибка возникает только при преобразовании между целыми числами и строками .
К счастью , вы можете увеличить предел допустимого количества цифр . Для этого можно воспользоваться одним из следующих способов :
2024-04-27 12:21:12 +03:00
- ` - X int_max_str_digits ` - флаг командной строки
2024-04-22 15:24:31 +03:00
- ` set_int_max_str_digits ( ) ` - функция из модуля ` sys `
- ` PYTHONINTMAXSTRDIGITS ` - переменная окружения
[ Смотри документацию ] ( https : / / docs . python . org / 3 / library / stdtypes . html #int-max-str-digits) для получения более подробной информации о б изменении лимита по умолчанию, если вы ожидаете, что ваш код превысит это значение.
- - -
2024-04-22 15:37:59 +03:00
2024-04-29 06:43:47 +03:00
## Раздел: Скользкие склоны
2024-04-22 15:37:59 +03:00
### ▶ Изменение словаря во время прохода по нему
< ! - - Example ID : b4e5cdfb - c3a8 - 4112 - bd38 - e2356d801c41 - - - >
` ` ` py
x = { 0 : None }
for i in x :
del x [ i ]
x [ i + 1 ] = None
print ( i )
` ` `
* * Результат ( Python 2.7 - Python 3.5 ) : * *
` ` `
0
1
2
3
4
5
6
7
` ` `
Да , цикл выполняет ровно * * восемь * * итераций и завершается .
#### 💡 Объяснение:
* Проход по словарю и е г о одновременное редактирование не поддерживается .
* Выполняется восемь проходов , потому что именно в этот момент словарь изменяет размер , чтобы вместить больше ключей ( у нас есть восемь записей о б удалении , поэтому необходимо изменить размер ) . Н а самом деле это деталь реализации .
* Т о , как обрабатываются удаленные ключи и когда происходит изменение размера , может отличаться в разных реализациях Python .
* Так что для версий Python , отличных от Python 2.7 - Python 3.5 , количество записей может отличаться от 8 ( но каким бы ни было количество записей , оно будет одинаковым при каждом запуске ) . Обсуждения по этому поводу имеются в [ issue ] ( https : / / github . com / satwikkansal / wtfpython / issues / 53 ) и на [ StackOverflow ] ( https : / / stackoverflow . com / questions / 44763802 / bug - in - python - dict ) .
* В Python 3.7 .6 и выше при попытке запустить пример вызывается исключение ` RuntimeError : dictionary keys changed during iteration ` .
- - -
2024-04-23 08:53:40 +03:00
### ▶ Упрямая операция `del`
< ! - - Example ID : 777 ed4fd - 3 a2d - 466 f - 95e7 - c4058e61d78e - - - >
< ! - - read - only - - >
` ` ` py
class SomeClass :
def __del__ ( self ) :
print ( " Deleted! " )
` ` `
* * Результат : * *
1 \.
` ` ` py
>> > x = SomeClass ( )
>> > y = x
>> > del x # должно быть выведено "Deleted!"
>> > del y
Deleted !
` ` `
Фух , наконец - то удалили . Вы , наверное , догадались , что спасло ` __del__ ` от вызова в нашей первой попытке удалить ` x ` . Давайте добавим в пример еще больше изюминок .
2 \.
` ` ` py
>> > x = SomeClass ( )
>> > y = x
>> > del x
>> > y # проверяем, существует ли y
< __main__ . SomeClass instance at 0x7f98a1a67fc8 >
>> > del y # Как и в прошлом примере, вывод должен содержать "Deleted!"
>> > globals ( ) # но вывод пуст. Проверим все глобальные переменные
Deleted !
{ ' __builtins__ ' : < module ' __builtin__ ' ( built - in ) > , ' SomeClass ' : < class __main__ . SomeClass at 0x7f98a1a5f668 > , ' __package__ ' : None , ' __name__ ' : ' __main__ ' , ' __doc__ ' : None }
` ` `
Вот сейчас переменная ` y ` удалена : confused :
#### 💡 Объяснение:
+ ` del x ` не вызывает напрямую ` x . __del__ ( ) ` .
+ Когда встречается ` del x ` , Python удаляет имя ` x ` из текущей области видимости и уменьшает на 1 количество ссылок на объект , на который ссылается ` x ` . ` __del__ ( ) ` вызывается только тогда , когда счетчик ссылок объекта достигает нуля .
+ В о втором фрагменте вывода ` __del__ ( ) ` не была вызвана , потому что предыдущий оператор ( ` >> > y ` ) в интерактивном интерпретаторе создал еще одну ссылку на тот же объект ( в частности , магическую переменную ` _ ` , которая ссылается на значение результата последнего не ` None ` выражения в REPL ) , тем самым не позволив счетчику ссылок достичь нуля , когда было встречено ` del y ` .
+ Вызов ` globals ` ( или вообще выполнение чего - либо , что будет иметь результат , отличный от ` None ` ) заставил ` _ ` сослаться на новый результат , отбросив существующую ссылку . Теперь количество ссылок достигло 0 , и мы можем видеть , как выводится " Deleted! " ( наконец - то ! ) .
- - -
2024-04-23 09:02:25 +03:00
### ▶ Переменная за пределами видимости
< ! - - Example ID : 75 c03015 - 7 be9 - 4289 - 9e22 - 4 f5fdda056f7 - - - >
1 \.
` ` ` py
a = 1
def some_func ( ) :
return a
def another_func ( ) :
a + = 1
return a
` ` `
2 \.
` ` ` py
def some_closure_func ( ) :
a = 1
def some_inner_func ( ) :
return a
return some_inner_func ( )
def another_closure_func ( ) :
a = 1
def another_inner_func ( ) :
a + = 1
return a
return another_inner_func ( )
` ` `
* * Результат : * *
` ` ` py
>> > some_func ( )
1
>> > another_func ( )
UnboundLocalError : local variable ' a ' referenced before assignment
>> > some_closure_func ( )
1
>> > another_closure_func ( )
UnboundLocalError : local variable ' a ' referenced before assignment
` ` `
#### 💡 Объяснение:
* Когда вы делаете присваивание переменной в области видимости , она становится локальной для этой области . Так ` a ` становится локальной для области видимости ` another_func ` , но она не была инициализирована ранее в той же области видимости , что приводит к ошибке .
* Для изменения переменной ` a ` из внешней области видимости внутри функции ` another_func ` , необходимо использовать ключевое слово ` global ` .
` ` ` py
def another_func ( )
global a
a + = 1
return a
` ` `
* * Результат : * *
` ` ` py
>> > another_func ( )
2
` ` `
* В ` another_closure_func ` переменная ` a ` становится локальной для области видимости ` another_inner_func ` , но она не была инициализирована ранее в той же области видимости , поэтому выдает ошибку .
* Чтобы изменить переменную внешней области видимости ` a ` в ` another_inner_func ` , используйте ключевое слово ` nonlocal ` . Утверждение nonlocal используется для обращения к переменным , определенным в ближайшей внешней ( за исключением глобальной ) области видимости .
` ` ` py
def another_func ( ) :
a = 1
def another_inner_func ( ) :
nonlocal a
a + = 1
return a
return another_inner_func ( )
` ` `
* * Результат : * *
` ` ` py
>> > another_func ( )
2
` ` `
* Ключевые слова ` global ` и ` nonlocal ` указывают интерпретатору python не объявлять новые переменные и искать их в соответствующих внешних областях видимости .
* Прочитайте [ это ] ( https : / / sebastianraschka . com / Articles / 2014 _python_scope_and_namespaces . html ) короткое , но потрясающее руководство , чтобы узнать больше о том , как работают пространства имен и разрешение областей видимости в Python .
- - -
2024-04-23 10:58:11 +03:00
### ▶ Удаление элемента списка во время прохода по списку
< ! - - Example ID : 4 cc52d4e - d42b - 4e09 - b25f - fbf5699b7d4e - - - >
` ` ` py
list_1 = [ 1 , 2 , 3 , 4 ]
list_2 = [ 1 , 2 , 3 , 4 ]
list_3 = [ 1 , 2 , 3 , 4 ]
list_4 = [ 1 , 2 , 3 , 4 ]
for idx , item in enumerate ( list_1 ) :
del item
for idx , item in enumerate ( list_2 ) :
list_2 . remove ( item )
for idx , item in enumerate ( list_3 [ : ] ) :
list_3 . remove ( item )
for idx , item in enumerate ( list_4 ) :
list_4 . pop ( idx )
` ` `
* * Результат : * *
` ` ` py
>> > list_1
[ 1 , 2 , 3 , 4 ]
>> > list_2
[ 2 , 4 ]
>> > list_3
[ ]
>> > list_4
[ 2 , 4 ]
` ` `
Есть предположения , почему вывод ` [ 2 , 4 ] ` ?
#### 💡 Объяснение:
* Никогда не стоит изменять объект , над которым выполняется итерация . Правильным способом будет итерация по копии объекта , и ` list_3 [ : ] ` делает именно это .
` ` ` py
>> > some_list = [ 1 , 2 , 3 , 4 ]
>> > id ( some_list )
139798789457608
2024-04-27 12:21:12 +03:00
>> > id ( some_list [ : ] ) # Обратите внимание, создается новый объект из среза списка
2024-04-23 10:58:11 +03:00
139798779601192
` ` `
* * Разница между ` del ` , ` remove ` и ` pop ` : * *
* ` del var_name ` просто удаляет привязку ` var_name ` из локального или глобального пространства имен ( поэтому ` list_1 ` не затрагивается ) .
* ` remove ` удаляет первое подходящее значение , а не конкретный индекс , вызывает ` ValueError ` , если значение не найдено .
* ` pop ` удаляет элемент по определенному индексу и возвращает е г о , вызывает ` IndexError ` , если указан неверный индекс .
2024-04-27 12:21:12 +03:00
* * Почему на выходе получается ` [ 2 , 4 ] ` ? * *
2024-04-23 10:58:11 +03:00
- Проход по списку выполняется индекс за индексом , и когда мы удаляем ` 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 / 45877614 / how - to - change - all - the - dictionary - keys - in - a - for - loop - with - d - items ) , связанный с о словарями .
- - -
2024-04-23 11:07:40 +03:00
### ▶ Сжатие итераторов с потерями *
< ! - - Example ID : c28ed154 - e59f - 4070 - 8 eb6 - 8967 a4acac6d - - - >
` ` ` py
>> > numbers = list ( range ( 7 ) )
>> > numbers
[ 0 , 1 , 2 , 3 , 4 , 5 , 6 ]
>> > first_three , remaining = numbers [ : 3 ] , numbers [ 3 : ]
>> > first_three , remaining
( [ 0 , 1 , 2 ] , [ 3 , 4 , 5 , 6 ] )
>> > numbers_iter = iter ( numbers )
>> > list ( zip ( numbers_iter , first_three ) )
[ ( 0 , 0 ) , ( 1 , 1 ) , ( 2 , 2 ) ]
# пока все хорошо, сожмем оставшуюся часть итератора
>> > list ( zip ( numbers_iter , remaining ) )
[ ( 4 , 3 ) , ( 5 , 4 ) , ( 6 , 5 ) ]
` ` `
Куда пропал элемент ` 3 ` из списка ` numbers ` ?
#### 💡 Объяснение:
- Согласно [ документации ] ( https : / / docs . python . org / 3.12 / library / functions . html #zip), примерная реализация функции `zip` выглядит так,
` ` ` py
def zip ( * iterables ) :
sentinel = object ( )
iterators = [ iter ( it ) for it in iterables ]
while iterators :
result = [ ]
for it in iterators :
elem = next ( it , sentinel )
if elem is sentinel : return
result . append ( elem )
yield tuple ( result )
` ` `
- Таким образом , функция принимает произвольное количество итерируемых объектов , добавляет каждый из их элементов в список ` result ` , вызывая для них функцию ` next ` , и останавливается всякий раз , когда любой из итерируемых объектов исчерпывается .
- Нюанс заключается в том , что при исчерпании любого итерируемого объекта существующие элементы в списке ` result ` отбрасываются . Именно это произошло с ` 3 ` в ` numbers_iter ` .
- Правильный способ выполнения вышеописанных действий с помощью ` zip ` будет следующим ,
` ` ` py
>> > numbers = list ( range ( 7 ) )
>> > numbers_iter = iter ( numbers )
>> > list ( zip ( first_three , numbers_iter ) )
[ ( 0 , 0 ) , ( 1 , 1 ) , ( 2 , 2 ) ]
>> > list ( zip ( remaining , numbers_iter ) )
[ ( 3 , 3 ) , ( 4 , 4 ) , ( 5 , 5 ) , ( 6 , 6 ) ]
` ` `
Первый аргумент сжатия должен иметь наименьшее число элементов
- - -
2024-04-23 11:23:47 +03:00
### ▶ Утечка переменных внутри цикла
< ! - - Example ID : ccec7bf6 - 7679 - 4963 - 907 a - 1 cd8587be9ea - - - >
1 \.
` ` ` py
for x in range ( 7 ) :
if x == 6 :
print ( x , ' : for x inside loop ' )
print ( x , ' : x in global ' )
` ` `
* * Вывод : * *
` ` ` py
6 : for x inside loop
6 : x in global
` ` `
Н о ` x ` не была определена за пределами цикла ` for ` . . .
2 \.
` ` ` py
# В этот раз определим x до цикла
x = - 1
for x in range ( 7 ) :
if x == 6 :
print ( x , ' : for x inside loop ' )
print ( x , ' : x in global ' )
` ` `
* * Вывод : * *
` ` ` py
6 : for x inside loop
6 : x in global
` ` `
3 \.
* * Вывод ( Python 2. x ) : * *
` ` ` py
>> > x = 1
>> > print ( [ x for x in range ( 5 ) ] )
[ 0 , 1 , 2 , 3 , 4 ]
>> > print ( x )
4
` ` `
* * Вывод ( Python 3. x ) : * *
` ` ` py
>> > x = 1
>> > print ( [ x for x in range ( 5 ) ] )
[ 0 , 1 , 2 , 3 , 4 ]
>> > print ( x )
1
` ` `
#### 💡 Объяснение:
2024-04-27 12:21:12 +03:00
- В Python циклы for используют область видимости , в которой они существуют , и оставляют свою определенную переменную цикла после завершения . Это также относится к случаям , когда мы явно определили переменную цикла for в глобальном пространстве имен . В этом случае будет произведена повторная привязка существующей переменной .
2024-04-23 11:23:47 +03:00
- Различия в выводе интерпретаторов Python 2. x и Python 3. x для примера с пониманием списков можно объяснить следующим изменением , задокументированным в журнале изменений [ What ' s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html):
> " Генераторы списков ( " list comprehensions " ) больше не поддерживает синтаксическую форму `[... for var in item1, item2, ...]`. Вместо этого используйте `[... for var in (item1, item2, ...)]`. Кроме того, обратите внимание, что генераторы списков имеют другую семантику: они ближе к синтаксическому с а х а р у для генераторного выражения внутри конструктора `list()`, и, в частности, управляющие переменные цикла больше не просачиваются в окружающую область видимости. "
- - -
2024-04-23 11:39:15 +03:00
### ▶ Остерегайтесь изменяемых аргументов по умолчанию!
< ! - - Example ID : 7 d42dade - e20d - 4 a7b - 9 ed7 - 16 fb58505fe9 - - - >
` ` ` py
def some_func ( default_arg = [ ] ) :
default_arg . append ( " some_string " )
return default_arg
` ` `
* * Результат : * *
` ` ` py
>> > some_func ( )
[ ' some_string ' ]
>> > some_func ( )
[ ' some_string ' , ' some_string ' ]
>> > some_func ( [ ] )
[ ' some_string ' ]
>> > some_func ( )
[ ' some_string ' , ' some_string ' , ' some_string ' ]
` ` `
#### 💡 Объяснение:
2024-04-27 12:21:12 +03:00
- Изменяемые аргументы функций по умолчанию в Python на самом деле не инициализируются каждый раз , когда вы вызываете функцию . Вместо этого в качестве значения по умолчанию используется недавно присвоенное им значение . Когда мы явно передали ` [ ] ` в ` some_func ` в качестве аргумента , значение по умолчанию переменной ` default_arg ` не было использовано , поэтому функция вернулась , как и ожидалось .
2024-04-23 11:39:15 +03:00
` ` ` py
def some_func ( default_arg = [ ] ) :
default_arg . append ( " some_string " )
return default_arg
` ` `
* * Результат : * *
` ` ` py
2024-04-27 12:21:12 +03:00
>> > some_func . __defaults__ # Выражение выведет значения стандартных аргументов функции
2024-04-23 11:39:15 +03:00
( [ ] , )
>> > some_func ( )
>> > some_func . __defaults__
( [ ' some_string ' ] , )
>> > some_func ( )
>> > some_func . __defaults__
( [ ' some_string ' , ' some_string ' ] , )
>> > some_func ( [ ] )
>> > some_func . __defaults__
( [ ' some_string ' , ' some_string ' ] , )
` ` `
- Чтобы избежать ошибок , связанных с изменяемыми аргументами , принято использовать ` None ` в качестве значения по умолчанию , а затем проверять , передано ли какое - либо значение в функцию , соответствующую этому аргументу . Пример :
` ` ` py
def some_func ( default_arg = None ) :
if default_arg is None :
default_arg = [ ]
default_arg . append ( " some_string " )
return default_arg
` ` `
- - -
2024-04-23 11:45:32 +03:00
### ▶ Ловля исключений
< ! - - Example ID : b5ca5e6a - 47 b9 - 4 f69 - 9375 - cda0f8c6755d - - - >
` ` ` py
some_list = [ 1 , 2 , 3 ]
try :
# Должно вернуться ``IndexError``
print ( some_list [ 4 ] )
except IndexError , ValueError :
print ( " Caught! " )
try :
# Должно вернуться ``ValueError``
some_list . remove ( 4 )
except IndexError , ValueError :
print ( " Caught again! " )
` ` `
* * Результат ( Python 2. x ) : * *
` ` ` py
Caught !
ValueError : list . remove ( x ) : x not in list
` ` `
* * Результат ( Python 3. x ) : * *
` ` ` py
File " <input> " , line 3
except IndexError , ValueError :
^
SyntaxError : invalid syntax
` ` `
#### 💡 Объяснение
* Чтобы добавить несколько Исключений в блок ` except ` , необходимо передать их в виде кортежа с круглыми скобками в качестве первого аргумента . Второй аргумент - это необязательное имя , которое при передаче свяжет экземпляр исключения , который был пойман . Пример ,
` ` ` py
some_list = [ 1 , 2 , 3 ]
try :
# Должно возникнуть ``ValueError``
some_list . remove ( 4 )
except ( IndexError , ValueError ) , e :
print ( " Caught again! " )
print ( e )
` ` `
* * Результат ( Python 2. x ) : * *
` ` `
Caught again !
list . remove ( x ) : x not in list
` ` `
* * Результат ( Python 3. x ) : * *
` ` ` py
File " <input> " , line 4
except ( IndexError , ValueError ) , e :
^
IndentationError : unindent does not match any outer indentation level
` ` `
* Отделение исключения от переменной запятой является устаревшим и не работает в Python 3 ; правильнее использовать ` as ` . Пример ,
` ` ` py
some_list = [ 1 , 2 , 3 ]
try :
some_list . remove ( 4 )
except ( IndexError , ValueError ) as e :
print ( " Caught again! " )
print ( e )
` ` `
* * Результат : * *
` ` `
Caught again !
list . remove ( x ) : x not in list
` ` `
- - -
2024-04-23 12:02:54 +03:00
### ▶ Одни и те же операнды, разная история!
< ! - - Example ID : ca052cdf - dd2d - 4105 - b936 - 65 c28adc18a0 - - - >
1 \.
` ` ` py
a = [ 1 , 2 , 3 , 4 ]
b = a
a = a + [ 5 , 6 , 7 , 8 ]
` ` `
* * Результат : * *
` ` ` py
>> > a
[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ]
>> > b
[ 1 , 2 , 3 , 4 ]
` ` `
2 \.
` ` ` py
a = [ 1 , 2 , 3 , 4 ]
b = a
a + = [ 5 , 6 , 7 , 8 ]
` ` `
* * Результат : * *
` ` ` py
>> > a
[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ]
>> > b
[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ]
` ` `
#### 💡 Объяснение:
* Выражение ` a + = b ` не всегда ведет себя так же , как и ` a = a + b ` . Классы * могут * по - разному реализовывать операторы * ` op = ` * , а списки ведут себя так .
* Выражение ` a = a + [ 5 , 6 , 7 , 8 ] ` создает новый список и устанавливает ссылку ` a ` на этот новый список , оставляя ` b ` неизменным .
* Выражение ` a + = [ 5 , 6 , 7 , 8 ] ` фактически отображается на функцию " extend " , которая работает с о списком так , что ` a ` и ` b ` по - прежнему указывают на тот же самый список , который был изменен на месте .
- - -
2024-04-23 12:07:47 +03:00
### ▶ Разрешение имен игнорирует область видимости класса
< ! - - Example ID : 03 f73d96 - 151 c - 4929 - b0a8 - f74430788324 - - - >
1 \.
` ` ` py
x = 5
class SomeClass :
x = 17
y = ( x for i in range ( 10 ) )
` ` `
* * Результат : * *
` ` ` py
>> > list ( SomeClass . y ) [ 0 ]
5
` ` `
2 \.
` ` ` py
x = 5
class SomeClass :
x = 17
y = [ x for i in range ( 10 ) ]
` ` `
* * Результат ( Python 2. x ) : * *
` ` ` py
>> > SomeClass . y [ 0 ]
17
` ` `
* * Результат ( Python 3. x ) : * *
` ` ` py
>> > SomeClass . y [ 0 ]
5
` ` `
#### 💡 Объяснение
- Области видимости , вложенные внутрь определения класса , игнорируют имена , связанные на уровне класса .
- Выражение - генератор имеет свою собственную область видимости .
2024-04-27 12:21:12 +03:00
- Начиная с версии Python 3. X , списковые выражения ( list comprehensions ) также имеют свою собственную область видимости .
2024-04-23 12:07:47 +03:00
- - -
2024-04-23 12:18:36 +03:00
### ▶ Округляясь как банкир *
Реализуем простейшую функцию по получению среднего элемента списка :
` ` ` py
def get_middle ( some_list ) :
mid_index = round ( len ( some_list ) / 2 )
return some_list [ mid_index - 1 ]
` ` `
* * Python 3. x : * *
` ` ` py
>> > get_middle ( [ 1 ] ) # вроде неплохо
1
>> > get_middle ( [ 1 , 2 , 3 ] ) # все еще хорошо
2
>> > get_middle ( [ 1 , 2 , 3 , 4 , 5 ] ) # что-то не то?
2
>> > len ( [ 1 , 2 , 3 , 4 , 5 ] ) / 2 # хорошо
2.5
>> > round ( len ( [ 1 , 2 , 3 , 4 , 5 ] ) / 2 ) # почему снова так?
2
` ` `
Кажется , Python округлил 2.5 до 2.
#### 💡 Объяснение:
- Это не ошибка округления float , на самом деле такое поведение намеренно . Начиная с Python 3.0 , ` round ( ) ` использует [ округление банкира ] ( https : / / en . wikipedia . org / wiki / Rounding #Round_half_to_even), где дроби .5 округляются до ближайшего **четного** числа.
` ` ` py
>> > round ( 0.5 )
0
>> > round ( 1.5 )
2
>> > round ( 2.5 )
2
>> > import numpy # поведение numpy аналогично
>> > numpy . round ( 0.5 )
0.0
>> > numpy . round ( 1.5 )
2.0
>> > numpy . round ( 2.5 )
2.0
` ` `
- Это рекомендуемый способ округления дробей до .5 , описанный в [ IEEE 754 ] ( https : / / en . wikipedia . org / wiki / IEEE_754 #Rounding_rules). Однако в школах чаще всего преподают другой способ (округление от нуля), поэтому округление банкира, скорее всего, не так хорошо известно. Более того, некоторые из самых популярных языков программирования (например, JavaScript, Java, C/C++, Ruby, Rust) также не используют округление банкира. Таким образом, для Python это все еще довольно специфично и может привести к путанице при округлении дробей.
- Дополнительную информацию можно найти в [ документации ] ( https : / / docs . python . org / 3 / library / functions . html #round) функции `round` или на [StackOverflow](https://stackoverflow.com/questions/10825926/python-3-x-rounding-behavior).
- - -
2024-04-23 12:32:24 +03:00
### ▶ Иголки в стоге сена *
< ! - - Example ID : 52 a199b1 - 989 a - 4 b28 - 8910 - dff562cebba9 - - - >
Я не встречал ни одного питониста на данный момент , который не встречался с одним из следующих сценариев ,
1 \.
` ` ` py
x , y = ( 0 , 1 ) if True else None , None
` ` `
* * Результат : * *
` ` ` py
>> > x , y # ожидается (0, 1)
( ( 0 , 1 ) , None )
` ` `
2 \.
` ` ` py
t = ( ' one ' , ' two ' )
for i in t :
print ( i )
t = ( ' one ' )
for i in t :
print ( i )
t = ( )
print ( t )
` ` `
* * Результат : * *
` ` ` py
one
two
o
n
e
tuple ( )
` ` `
3 \.
` ` ` py
ten_words_list = [
" some " ,
" very " ,
" big " ,
" list " ,
" that "
" consists " ,
" of " ,
" exactly " ,
" ten " ,
" words "
]
` ` `
* * Результат * *
` ` ` py
>> > len ( ten_words_list )
9
` ` `
4 \. Недостаточно твердое утверждение
` ` ` py
a = " python "
b = " javascript "
` ` `
* * Результат : * *
` ` ` py
2024-04-27 12:21:12 +03:00
# assert выражение с сообщением о б ошибке
2024-04-23 12:32:24 +03:00
>> > assert ( a == b , " Both languages are different " )
# Исключение AssertionError не возникло
` ` `
5 \.
` ` ` py
some_list = [ 1 , 2 , 3 ]
some_dict = {
" key_1 " : 1 ,
" key_2 " : 2 ,
" key_3 " : 3
}
some_list = some_list . append ( 4 )
some_dict = some_dict . update ( { " key_4 " : 4 } )
` ` `
* * Результат : * *
` ` ` py
>> > print ( some_list )
None
>> > print ( some_dict )
None
` ` `
6 \.
` ` ` py
def some_recursive_func ( a ) :
if a [ 0 ] == 0 :
return
a [ 0 ] - = 1
some_recursive_func ( a )
return a
def similar_recursive_func ( a ) :
if a == 0 :
return a
a - = 1
similar_recursive_func ( a )
return a
` ` `
* * Результат : * *
` ` ` py
>> > some_recursive_func ( [ 5 , 0 ] )
[ 0 , 0 ]
>> > similar_recursive_func ( 5 )
4
` ` `
#### 💡 Объяснение:
* Для 1 примера правильным выражением для ожидаемого поведения является ` x , y = ( 0 , 1 ) if True else ( None , None ) ` .
* Для 2 примера правильным выражением для ожидаемого поведения будет ` t = ( ' one ' , ) ` или ` t = ' one ' , ` ( пропущена запятая ) , иначе интерпретатор рассматривает ` t ` как ` str ` и перебирает е г о символ за символом .
* ` ( ) ` - специальное выражение , обозначающая пустой ` tuple ` .
* В 3 примере , как вы , возможно , уже поняли , пропущена запятая после 5 - г о элемента ( ` " that " ` ) в списке . Таким образом , неявная конкатенация строковых литералов ,
` ` ` py
>> > ten_words_list
[ ' some ' , ' very ' , ' big ' , ' list ' , ' thatconsists ' , ' of ' , ' exactly ' , ' ten ' , ' words ' ]
` ` `
* В 4 - ом фрагменте не возникло ` AssertionError ` , потому что вместо " проверки " отдельного выражения ` a == b ` , мы " проверяем " весь кортеж . Следующий фрагмент прояснит ситуацию ,
` ` ` py
>> > a = " python "
>> > b = " javascript "
>> > assert a == b
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
AssertionError
>> > assert ( a == b , " Values are not equal " )
< stdin > : 1 : SyntaxWarning : assertion is always true , perhaps remove parentheses ?
>> > assert a == b , " Values are not equal "
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
AssertionError : Values are not equal
` ` `
* Что касается пятого фрагмента , то большинство методов , изменяющих элементы последовательности / маппингов , такие как ` list . append ` , ` dict . update ` , ` list . sort ` и т . д . , изменяют объекты на месте и возвращают ` None ` . Это делается для того , чтобы повысить производительность , избегая создания копии объекта , если операция может быть выполнена на месте ( подробнее в [ документации ] ( https : / / docs . python . org / 3 / faq / design . html #why-doesn-t-list-sort-return-the-sorted-list)).
* Последнее должно быть достаточно очевидным , изменяемый объект ( например , ` list ` ) может быть изменен в функции , а переназначение неизменяемого ( ` a - = 1 ` ) не является изменением значения .
* Знание этих тонкостей может сэкономить вам часы отладки в долгосрочной перспективе .
- - -
2024-04-24 11:27:46 +03:00
### ▶ Сплиты (splitsies) *
< ! - - example id : ec3168ba - a81a - 4482 - afb0 - 691 f1cc8d65a - - - >
` ` ` py
>> > ' a ' . split ( )
[ ' a ' ]
# эквивалентно
>> > ' a ' . split ( ' ' )
[ ' a ' ]
# но
>> > len ( ' ' . split ( ) )
0
# не эквивалентно
>> > len ( ' ' . split ( ' ' ) )
1
` ` `
#### 💡 Объяснение
- Может показаться , что разделителем по умолчанию для split является одиночный пробел ` ' ' ` , но согласно [ документации ] ( https : / / docs . python . org / 3 / library / stdtypes . html #str.split)
> если sep не указан или равен ` none ` , применяется другой алгоритм разбиения : последовательные пробельные символы рассматриваются как один разделитель , и результат не будет содержать пустых строк в начале или конце , если в строке есть ведущие или завершающие пробелы . Следовательно , разбиение пустой строки или строки , состоящей только из пробельных символов , с разделителем none возвращает ` [ ] ` .
> если задан sep , то последовательные разделители не группируются вместе и считаются разделителями пустых строк ( например , ` ' 1,,2 ' . split ( ' , ' ) ` возвращает ` [ ' 1 ' , ' ' , ' 2 ' ] ` ) . Разделение пустой строки с указанным разделителем возвращает ` [ ' ' ] ` .
- Обратите внимание , как обрабатываются ведущие и завершающие пробелы в следующем фрагменте ,
` ` ` py
>> > ' a ' . split ( ' ' )
[ ' ' , ' a ' , ' ' ]
>> > ' a ' . split ( )
[ ' a ' ]
>> > ' ' . split ( ' ' )
[ ' ' ]
` ` `
- - -
2024-04-24 11:35:57 +03:00
### ▶ Подстановочное импортирование (wild imports) *
< ! - - Example ID : 83 deb561 - bd55 - 4461 - bb5e - 77 dd7f411e1c - - - >
< ! - - read - only - - >
` ` ` py
# File: module.py
def some_weird_name_func_ ( ) :
print ( " works! " )
def _another_weird_name_func ( ) :
print ( " works! " )
` ` `
* * Результат * *
` ` ` py
>> > from module import *
>> > some_weird_name_func_ ( )
" works! "
>> > _another_weird_name_func ( )
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
NameError : name ' _another_weird_name_func ' is not defined
` ` `
#### 💡 Объяснение:
- Часто рекомендуется не использовать импорт с подстановочными знаками ( wildcard import ) . Первая очевидная причина заключается в том , что при импорте с подстановочным знаком имена с ведущим подчеркиванием не импортируются . Это может привести к ошибкам во время выполнения .
- Если бы мы использовали синтаксис ` from . . . import a , b , c ` , приведенная выше ` NameError ` не возникла бы .
` ` ` py
>> > from module import some_weird_name_func_ , _another_weird_name_func
>> > _another_weird_name_func ( )
works !
` ` `
- Если вы действительно хотите использовать импорт с подстановочными знаками , то нужно определить список ` __all__ ` в вашем модуле , который будет содержать публичные объекты , доступные при wildcard импортировании .
` ` ` py
__all__ = [ ' _another_weird_name_func ' ]
def some_weird_name_func_ ( ) :
print ( " works! " )
def _another_weird_name_func ( ) :
print ( " works! " )
` ` `
* * Результат * *
` ` ` py
>> > _another_weird_name_func ( )
" works! "
>> > some_weird_name_func_ ( )
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
NameError : name ' some_weird_name_func_ ' is not defined
` ` `
- - -
2024-04-24 11:39:29 +03:00
### ▶ В с е ли отсортировано? *
< ! - - Example ID : e5ff1eaf - 8823 - 4738 - b4ce - b73f7c9d5511 - - >
` ` ` py
>> > x = 7 , 8 , 9
>> > sorted ( x ) == x
False
>> > sorted ( x ) == sorted ( x )
True
>> > y = reversed ( x )
>> > sorted ( y ) == sorted ( y )
False
` ` `
#### 💡 Объяснение:
- Метод ` sorted ` всегда возвращает список , а сравнение списка и кортежа всегда возвращает ` False ` .
- ` ` ` py
>> > [ ] == tuple ( )
False
>> > x = 7 , 8 , 9
>> > type ( x ) , type ( sorted ( x ) )
( tuple , list )
` ` `
2024-04-27 12:21:12 +03:00
- В отличие от метода ` sorted ` , метод ` reversed ` возвращает итератор . Почему ? Потому что сортировка требует , чтобы итератор либо изменялся на месте , либо использовал дополнительный контейнер ( список ) , в то время как реверсирование может работать просто путем итерации от последнего индекса к первому .
2024-04-24 11:39:29 +03:00
- Поэтому при сравнении ` sorted ( y ) == sorted ( y ) ` первый вызов ` sorted ( ) ` будет потреблять итератор ` y ` , а следующий вызов просто вернет пустой список .
` ` ` py
>> > x = 7 , 8 , 9
>> > y = reversed ( x )
>> > sorted ( y ) , sorted ( y )
( [ 7 , 8 , 9 ] , [ ] )
` ` `
- - -
2024-04-24 11:43:00 +03:00
### ▶ Полночи не существует?
< ! - - Example ID : 1 bce8294 - 5619 - 4 d70 - 8 ce3 - fe0bade690d1 - - - >
` ` ` py
from datetime import datetime
midnight = datetime ( 2018 , 1 , 1 , 0 , 0 )
midnight_time = midnight . time ( )
noon = datetime ( 2018 , 1 , 1 , 12 , 0 )
noon_time = noon . time ( )
if midnight_time :
print ( " Time at midnight is " , midnight_time )
if noon_time :
print ( " Time at noon is " , noon_time )
` ` `
* * Результат ( < 3.5 ) : * *
` ` ` py
( ' Time at noon is ' , datetime . time ( 12 , 0 ) )
` ` `
Полночное время не выведено .
#### 💡 Объяснение:
До Python 3.5 булево значение для объекта ` datetime . time ` считалось ` False ` , если оно представляло полночь по UTC . При использовании синтаксиса ` if obj : ` для проверки того , что ` obj ` является null или эквивалентом " пусто " , возникает ошибка .
- - -
- - -
2024-04-24 11:47:58 +03:00
2024-04-29 06:43:47 +03:00
## Раздел: Скрытые сокровища!
2024-04-24 11:47:58 +03:00
2024-04-29 06:43:47 +03:00
Раздел содержит менее известные интересные нюансы работы Python , которые неизвестны большинству новичков .
2024-04-24 11:47:58 +03:00
2024-04-27 12:21:12 +03:00
### ▶ Python, можешь ли ты помочь взлететь?
2024-04-24 11:47:58 +03:00
< ! - - Example ID : a92f3645 - 1899 - 4 d50 - 9721 - 0031 be4aec3f - - - >
Что ж , поехали
` ` ` py
import antigravity
` ` `
* * Результат : * *
Sshh . . . It ' s a super-secret.
#### 💡 Объяснение:
+ Модуль ` antigravity ` - одно из немногих пасхальных яиц , выпущенных разработчиками Python .
+ ` import antigravity ` открывает веб - браузер , указывающий на [ классический комикс XKCD ] ( https : / / xkcd . com / 353 / ) о Python .
2024-04-27 12:21:12 +03:00
+ Это еще не все . Внутри пасхального яйца находится * * еще одно пасхальное яйцо * * . Если вы посмотрите на [ код ] ( https : / / github . com / python / cpython / blob / master / Lib / antigravity . py #L7-L17), там определена функция, которая якобы реализует алгоритм [XKCD](https://xkcd.com/426/).
2024-04-24 11:47:58 +03:00
- - -
2024-04-24 11:58:51 +03:00
### ▶ `goto`, но почему?
< ! - - Example ID : 2 aff961e - 7 fa5 - 4986 - a18a - 9e5894 bd89fe - - - >
` ` ` py
from goto import goto , label
for i in range ( 9 ) :
for j in range ( 9 ) :
for k in range ( 9 ) :
print ( " I am trapped, please rescue! " )
if k == 2 :
goto . breakout # выход из глубоко вложенного цикла
label . breakout
print ( " Freedom! " )
` ` `
* * Результат ( Python 2.3 ) : * *
` ` ` py
I am trapped , please rescue !
I am trapped , please rescue !
Freedom !
` ` `
#### 💡 Объяснение:
- Рабочая версия ` goto ` в Python была [ анонсирована ] ( https : / / mail . python . org / pipermail / python - announce - list / 2004 - April / 002982. html ) в качестве первоапрельской шутки 1 апреля 2004 года .
- В текущих версиях Python этот модуль отсутствует .
- Хотя он работает , но , пожалуйста , не используйте е г о . Вот [ причина ] ( https : / / docs . python . org / 3 / faq / design . html #why-is-there-no-goto) того, почему `goto` отсутствует в Python.
- - -
2024-04-24 12:02:09 +03:00
### ▶ Держитесь!
< ! - - Example ID : 5 c0c75f2 - ddd9 - 4 da3 - ba49 - c4be7ec39acf - - - >
Если вы относитесь к тем людям , которым не нравится использование пробелов в Python для обозначения диапазонов , вы можете использовать C - стиль { } импортировав это ,
` ` ` py
from __future__ import braces
` ` `
* * Результат : * *
` ` ` py
File " some_file.py " , line 1
from __future__ import braces
SyntaxError : not a chance
` ` `
Скобочки ? Ни за что ! Если это разочаровывало вас , используйте Java . Хорошо , еще одна удивительная вещь , можете ли вы найти ошибку
` SyntaxError ` которая вызвана в модуле ` __future__ ` [ код ] ( https : / / github . com / python / cpython / blob / master / Lib / __future__ . py ) ?
#### 💡 Объяснение:
+ Модуль ` __future__ ` обычно используется для предоставления возможностей из будущих версий Python . Однако " будущее " в данном конкретном контексте - это ирония .
+ Это пасхальное яйцо , связанное с мнением сообщества по этому вопросу .
+ Код на самом деле присутствует [ здесь ] ( https : / / github . com / python / cpython / blob / 025 eb98dc0c1dc27404df6c544fc2944e0fa9f3a / Python / future . c #L49) в файле `future.c`.
+ Когда компилятор CPython встречает оператор [ future ] ( https : / / docs . python . org / 3.3 / reference / simple_stmts . html #future-statements), он сначала запускает соответствующий код в `future.c`, а затем рассматривает е г о как обычный оператор импорта.
- - -
2024-04-24 12:09:26 +03:00
### ▶ Давайте познакомимся с дружелюбным Дядей Барри
< ! - - Example ID : 6427 fae6 - e959 - 462 d - 85 da - ce4c94ce41be - - - >
Непереводимая игра слов : Friendly Language Uncle For Life ( FLUFL )
* * Результат ( Python 3. x ) * *
` ` ` py
>> > from __future__ import barry_as_FLUFL
>> > " Ruby " != " Python " # в этом нет сомнений
File " some_file.py " , line 1
" Ruby " != " Python "
^
SyntaxError : invalid syntax
>> > " Ruby " < > " Python "
True
` ` `
Вот так просто .
#### 💡 Объяснение:
- Это относится к [ PEP - 401 ] ( https : / / www . python . org / dev / peps / pep - 0401 / ) , выпущенному 1 Апреля 2009 ( вы знаете , о чем это говорит ) .
- Цитата из PEP - 401
> Признав , что оператор неравенства ` != ` в Python 3.0 был ужасной , вызывающей боль ошибкой , FLUFL восстанавливает оператор ` < > ` ( ромб ) в качестве единственного написания .
- У Дяди Барри было еще много чего рассказать в PEP ; вы можете прочитать их [ здесь ] ( https : / / www . python . org / dev / peps / pep - 0401 / ) .
- Это работает хорошо в интерактивной среде , но при запуске через файл python вызывает ` SyntaxError ` ( смотри этот [ issue ] ( https : / / github . com / satwikkansal / wtfpython / issues / 94 ) ) . Однако вы можете обернуть оператор внутри ` eval ` или ` compile ` , чтобы заставить е г о работать ( но зачем ? )
` ` ` py
from __future__ import barry_as_FLUFL
print ( eval ( ' " Ruby " <> " Python " ' ) )
` ` `
- - -
2024-04-24 12:12:47 +03:00
### ▶ Даже Python понимает, что любовь - это сложно.
< ! - - Example ID : b93cad9e - d341 - 45 d1 - 999 c - fcdce65bed25 - - - >
` ` ` py
import this
` ` `
Подождите , что * * это * * ( this ) такое ? Это любовь ! : heart :
* * Результат : * *
` ` `
Дзен Python , от Тима Петерса
Красивое лучше , чем уродливое .
Явное лучше , чем неявное .
Простое лучше , чем сложное .
Сложное лучше , чем запутанное .
Плоское лучше , чем вложенное .
Разреженное лучше , чем плотное .
Читаемость имеет значение .
Особые случаи не настолько особые , чтобы нарушать правила .
При этом практичность важнее безупречности .
Ошибки никогда не должны замалчиваться .
Если они не замалчиваются явно .
Встретив двусмысленность , отбрось искушение угадать .
Должен существовать один и , желательно , только один очевидный способ сделать это .
Хотя он поначалу может быть и не очевиден , если вы не голландец [ ^ 1 ] .
Сейчас лучше , чем никогда .
Хотя никогда зачастую лучше , чем прямо сейчас .
Если реализацию сложно объяснить — идея плоха .
Если реализацию легко объяснить — идея , возможно , хороша .
Пространства имён — отличная штука ! Будем делать их больше !
` ` `
Это Дзен Python !
` ` ` py
>> > love = this
>> > this is love
True
>> > love is True
False
>> > love is False
False
>> > love is not True or False
True
>> > love is not True or False ; love is love # Love is complicated
True
` ` `
#### 💡 Объяснение:
* Модуль ` this ` в Python - это пасхальное яйцо для The Zen Of Python ( [ PEP 20 ] ( https : / / www . python . org / dev / peps / pep - 0020 ) ) .
* И если вы думаете , что это уже достаточно интересно , посмотрите реализацию [ this . py ] ( https : / / hg . python . org / cpython / file / c3896275c0f6 / Lib / this . py ) . Забавный факт - * * код для дзена нарушает сам себя * * ( и это , вероятно , единственное место , где это происходит , но это не точно ) .
* Что касается утверждения ` любовь не является истиной или ложью ; любовь - это любовь ` , иронично , но описательно ( если нет , пожалуйста , посмотрите примеры , связанные с операторами ` is ` и ` is not ` ) .
- - -
2024-04-24 12:17:37 +03:00
### ▶ Да, оно существует!
< ! - - Example ID : 4286 db3d - 1 ea7 - 47 c9 - 8 fb6 - a9a04cac6e49 - - - >
2024-04-27 12:21:12 +03:00
* * Ключевое слово ` else ` в связке с циклом ` for ` . * * Один из стандартных примеров :
2024-04-24 12:17:37 +03:00
` ` ` py
def does_exists_num ( l , to_find ) :
for num in l :
if num == to_find :
print ( " Exists! " )
break
else :
print ( " Does not exist " )
` ` `
* * Результат : * *
` ` ` py
>> > some_list = [ 1 , 2 , 3 , 4 , 5 ]
>> > does_exists_num ( some_list , 4 )
Exists !
>> > does_exists_num ( some_list , - 1 )
Does not exist
` ` `
* * Использование ` else ` блока во время обработки исключения . * * Пример ,
` ` ` py
try :
pass
except :
print ( " Exception occurred!!! " )
else :
print ( " Try block executed successfully... " )
` ` `
* * Результат : * *
` ` ` py
Try block executed successfully . . .
` ` `
#### 💡 Объяснение:
- Блок ` else ` после цикла выполняется только тогда , когда нет явного ` break ` после всех итераций . Вы можете думать о б этом как о блоке " nobreak " .
- Блок ` else ` после блока ` try ` также называется " блоком завершения " , поскольку достижение ` else ` в операторе ` try ` означает , что блок попыток действительно успешно завершен .
- - -
2024-04-24 12:24:34 +03:00
### ▶ Многоточие *
< ! - - Example ID : 969 b7100 - ab3d - 4 a7d - ad7d - a6be16181b2b - - - >
` ` ` py
def some_func ( ) :
Ellipsis
` ` `
* * Результат * *
` ` ` py
>> > some_func ( )
# Ни вывода, ни ошибки
>> > SomeRandomString
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
NameError : name ' SomeRandomString ' is not defined
>> > Ellipsis
Ellipsis
` ` `
#### 💡 Объяснение
- В Python , ` Ellipsis ` - глобальный встроенный объект , эквивалентный ` . . . ` .
` ` ` py
>> > . . .
Ellipsis
` ` `
- Многоточие может использоваться в нескольких случаях ,
+ В качестве заполнителя для кода , который еще не написан ( аналогично оператору ` pass ` )
+ В синтаксисе срезов ( slices ) для представления полных срезов в оставшемся направлении
2024-04-27 12:21:12 +03:00
` ` ` py
2024-04-24 12:24:34 +03:00
>> > import numpy as np
>> > three_dimensional_array = np . arange ( 8 ) . reshape ( 2 , 2 , 2 )
array ( [
[
[ 0 , 1 ] ,
[ 2 , 3 ]
] ,
[
[ 4 , 5 ] ,
[ 6 , 7 ]
]
] )
` ` `
Таким образом , наш ` тр е х ме р ный_ма с с ив ` представляет собой массив массивов массивов . Допустим , мы хотим вывести второй элемент ( индекс ` 1 ` ) всех внутренних массивов , мы можем использовать ` Ellipsis ` , чтобы обойти все предыдущие измерения
2024-04-24 15:29:06 +03:00
` ` ` py
2024-04-24 12:24:34 +03:00
>> > three_dimensional_array [ : , : : , 1 ]
array ( [ [ 1 , 3 ] ,
[ 5 , 7 ] ] )
>> > three_dimensional_array [ . . . , 1 ] # использование Ellipsis.
array ( [ [ 1 , 3 ] ,
[ 5 , 7 ] ] )
` ` `
Примечание : это будет работать для любого количества измерений . Можно даже выбрать срез в первом и последнем измерении и игнорировать средние ( ` n_dimensional_array [ firs_dim_slice , . . . , last_dim_slice ] ` )
2024-04-27 12:21:12 +03:00
+ В [ подсказках типов ] ( https : / / docs . python . org / 3 / library / typing . html ) для указания только части типа ( например , ` Callable [ . . . , int ] ` или ` Tuple [ str , . . . ] ` )
2024-04-24 12:24:34 +03:00
+ Вы также можете использовать ` Ellipsis ` в качестве аргумента функции по умолчанию ( в случаях , когда вы хотите провести различие между сценариями " аргумент не передан " и " значение не передано " ) .
- - -
2024-04-24 15:29:06 +03:00
### ▶ Писконечность (Inpinity)
< ! - - Example ID : ff473ea8 - a3b1 - 4876 - a6f0 - 4378 aff790c1 - - - >
В заголовке нет ошибки , так и задумано , пожалуйста , не создавайте issue или pull request с изменением .
* * Результат ( Python 3. x ) : * *
` ` ` py
>> > infinity = float ( ' infinity ' )
>> > hash ( infinity )
314159
>> > hash ( float ( ' -inf ' ) )
- 314159
` ` `
#### 💡 Объяснение:
- Хэш бесконечности - 10 ⁵ x π .
- Интересно , что хэш ` float ( ' -inf ' ) ` - " -10⁵ x π " в Python 3 , тогда как в Python 2 - " -10⁵ x e " .
- - -
2024-04-24 15:39:50 +03:00
### ▶ Давайте искажать
< ! - - Example ID : 37146 d2d - 9e67 - 43 a9 - 8729 - 3 c17934b910c - - - >
1 \.
` ` ` py
class Yo ( object ) :
def __init__ ( self ) :
self . __honey = True
self . bro = True
` ` `
* * Результат : * *
` ` ` py
>> > Yo ( ) . bro
True
>> > Yo ( ) . __honey
AttributeError : ' Yo ' object has no attribute ' __honey '
>> > Yo ( ) . _Yo__honey
True
` ` `
2 \.
` ` ` py
class Yo ( object ) :
def __init__ ( self ) :
# Попробуем симметричные двойные подчеркивания в названии атрибута
self . __honey__ = True
self . bro = True
` ` `
* * Результат : * *
` ` ` py
>> > Yo ( ) . bro
True
>> > Yo ( ) . _Yo__honey__
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
AttributeError : ' Yo ' object has no attribute ' _Yo__honey__ '
` ` `
Почему обращение к ` Yo ( ) . _Yo__honey ` сработало ?
3 \.
` ` ` py
_A__variable = " Some value "
class A ( object ) :
def some_func ( self ) :
return __variable # переменная еще не инициализирована
` ` `
* * Результат : * *
` ` ` py
>> > A ( ) . __variable
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
AttributeError : ' A ' object has no attribute ' __variable '
>> > A ( ) . some_func ( )
' Some value '
` ` `
#### 💡 Объяснение:
* [ Искажение имени ] ( https : / / en . wikipedia . org / wiki / Name_mangling ) используется для предотвращения коллизий имен между различными пространствами имен .
* В Python интерпретатор изменяет ( mangles ) имена членов класса , начинающиеся с ` __ ` ( двойное подчеркивание , оно же " дундер " ) и не заканчивающиеся более чем одним подчеркиванием в конце , добавляя перед ними ` _NameOfTheClass ` .
* Таким образом , чтобы получить доступ к атрибуту ` __honey ` в первом фрагменте , мы должны были добавить ` _Yo ` спереди , что предотвратило бы конфликты с тем же атрибутом ` name ` , определенным в любом другом классе .
* Н о почему тогда это не сработало во втором фрагменте ? Потому что при манипулировании именами исключаются имена , заканчивающиеся двойным подчеркиванием .
* Третий фрагмент также является следствием манипулирования именами . Имя ` __variable ` в операторе ` return __variable ` было искажено до ` _A__variable ` , что также является именем переменной , которую мы объявили во внешней области видимости .
* Кроме того , если длина искаженного имени превышает 255 символов , произойдет усечение ( truncation ) .
- - -
- - -
2024-04-24 15:47:58 +03:00
2024-04-29 06:43:47 +03:00
## Раздел: Внешность обманчива!
2024-04-24 15:47:58 +03:00
### ▶ Пропускаем строки?
< ! - - Example ID : d50bbde1 - fb9d - 4735 - 9633 - 3444 b9d2f417 - - - >
* * Результат : * *
` ` ` py
>> > value = 11
>> > valuе = 32
>> > value
11
` ` `
Что за дела ?
* * Заметка : * * самый простой способ воспроизвести это - просто скопировать утверждения из приведенного выше фрагмента и вставить их в свой файл / оболочку .
#### 💡 Объяснение
Некоторые незападные символы выглядят идентично буквам английского алфавита , но интерпретатор считает их разными .
` ` ` py
>> > ord ( ' е ' ) # кириллическое 'е ' (ye)
1077
>> > ord ( ' e ' ) # латинское 'e', используемое в английском языке и набираемое с помощью стандартной клавиатуры
101
>> > ' е ' == ' е '
false
>> > value = 42 # латинское "е
>> > valuе = 23 # кириллическое "е ", интерпретатор python 2.x вызовет здесь `syntaxerror`
>> > value
42
` ` `
Встроенная функция ` ord ( ) ` возвращает юникод [ кодовую точку символа ] ( https : / / en . wikipedia . org / wiki / code_point ) , и разные кодовые позиции кириллического ' e ' и латинского ' e ' оправдывают поведение приведенного выше примера .
- - -
2024-04-24 15:52:39 +03:00
### ▶ Телепортация
< ! - - Example ID : edafe923 - 0 c20 - 4315 - b6e1 - 0 c31abfc38f5 - - - >
` ` ` py
# Прежде всего выполним `pip install numpy`.
import numpy as np
def energy_send ( x ) :
# Инициализация numpy массива
np . array ( [ float ( x ) ] )
def energy_receive ( ) :
# Возвращаем пустой numpy массив
return np . empty ( ( ) , dtype = np . float ) . tolist ( )
` ` `
* * Результат : * *
` ` ` py
>> > energy_send ( 123.456 )
>> > energy_receive ( )
123.456
` ` `
Где моя Нобелевская премия ?
#### 💡 Объяснение:
* Обратите внимание , что массив ` numpy ` , созданный в функции ` energy_send ` , не возвращается , так что место в памяти свободно для перераспределения .
* ` numpy . empty ( ) ` возвращает следующий свободный участок памяти без е г о повторной инициализации . Этот участок памяти просто оказывается тем же самым , который был только что освобожден ( обычно , но не всегда ) .
- - -
2024-04-24 16:02:55 +03:00
### ▶ Что-то не так...
< ! - - Example ID : cb6a37c5 - 74 f7 - 44 ca - b58c - 3 b902419b362 - - - >
` ` ` py
def square ( x ) :
"""
Простая функция по вычислению квадрата числа путем суммирования .
"""
sum_so_far = 0
for counter in range ( x ) :
sum_so_far = sum_so_far + x
return sum_so_far
` ` `
* * Результат ( Python 2. x ) : * *
` ` ` py
>> > square ( 10 )
10
` ` `
Разве не должно быть 100 ?
* * Заметка : * * Если у вас не получается воспроизвести это , попробуйте запустить файл [ mixed_tabs_and_spaces . py ] ( / mixed_tabs_and_spaces . py ) через оболочку .
#### 💡 Объяснение
* * * Н е смешивайте табы и пробелы ! * * Символ , непосредственно предшествующий return , является " табом " , а код в других местах примера имеет отступ в 4 пробела .
* Вот как Python обрабатывает табы :
> Сначала табы заменяются ( слева направо ) на пробелы от одного до восьми так , чтобы общее количество символов до замены включительно было кратно восьми < . . . > .
* Таким образом , " табы " в последней строке функции ` square ` заменяется восемью пробелами , и она попадает в цикл .
* Python 3 достаточно любезен , чтобы автоматически выдавать ошибку для таких случаев .
* * Результат ( Python 3. x ) : * *
` ` ` py
TabError : inconsistent use of tabs and spaces in indentation
` ` `
- - -
- - -
2024-04-24 16:06:24 +03:00
2024-04-29 06:43:47 +03:00
## Раздел: Разное
2024-04-24 16:06:24 +03:00
2024-04-27 12:21:12 +03:00
### ▶ `+=` быстрее `+`
2024-04-24 16:06:24 +03:00
< ! - - Example ID : bfd19c60 - a807 - 4 a26 - 9598 - 4912 b86ddb36 - - - >
` ` ` py
# Использование "+", 3 строки:
>> > timeit . timeit ( " s1 = s1 + s2 + s3 " , setup = " s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000 " , number = 100 )
0.25748300552368164
# Использование "+=", 3 строки:
>> > timeit . timeit ( " s1 += s2 + s3 " , setup = " s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000 " , number = 100 )
0.012188911437988281
` ` `
#### 💡 Объяснение:
2024-04-24 16:16:10 +03:00
+ Операнд ` + = ` быстрее ` + ` для " сложения " 2 и более строк , так как первая строка ( например , ` s1 ` for ` s1 + = s2 + s3 ` ) не уничтожается во время формирования финальной строки .
- - -
### ▶ Сделаем гигантскую строку!
< ! - - Example ID : c7a07424 - 63 fe - 4504 - 9842 - 8 f3d334f28fc - - - >
` ` ` py
def add_string_with_plus ( iters ) :
s = " "
for i in range ( iters ) :
s + = " xyz "
assert len ( s ) == 3 * iters
def add_bytes_with_plus ( iters ) :
s = b " "
for i in range ( iters ) :
s + = b " xyz "
assert len ( s ) == 3 * iters
def add_string_with_format ( iters ) :
fs = " {} " * iters
s = fs . format ( * ( [ " xyz " ] * iters ) )
assert len ( s ) == 3 * iters
def add_string_with_join ( iters ) :
l = [ ]
for i in range ( iters ) :
l . append ( " xyz " )
s = " " . join ( l )
assert len ( s ) == 3 * iters
def convert_list_to_string ( l , iters ) :
s = " " . join ( l )
assert len ( s ) == 3 * iters
` ` `
* * Результат : * *
` ` ` py
# Фрагменты выполняются в оболочке `ipython` с использованием `%timeit` для лучшей читаемости результатов.
# Вы также можете использовать модуль timeit в обычной оболочке python shell/scriptm=, пример использования ниже
# timeit.timeit('add_string_with_plus(10000)', number=1000, globals=globals())
>> > NUM_ITERS = 1000
>> > % timeit - n1000 add_string_with_plus ( NUM_ITERS )
124 µs ± 4.73 µs per loop ( mean ± std . dev . of 7 runs , 100 loops each )
>> > % timeit - n1000 add_bytes_with_plus ( NUM_ITERS )
211 µs ± 10.5 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
>> > % timeit - n1000 add_string_with_format ( NUM_ITERS )
61 µs ± 2.18 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
>> > % timeit - n1000 add_string_with_join ( NUM_ITERS )
117 µs ± 3.21 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
>> > l = [ " xyz " ] * NUM_ITERS
>> > % timeit - n1000 convert_list_to_string ( l , NUM_ITERS )
10.1 µs ± 1.06 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
` ` `
Увеличим число итераций в 10 раз .
` ` ` py
>> > NUM_ITERS = 10000
>> > % timeit - n1000 add_string_with_plus ( NUM_ITERS ) # Линейное увеличение времени выполнения
1.26 ms ± 76.8 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
>> > % timeit - n1000 add_bytes_with_plus ( NUM_ITERS ) # Квадратичное увеличение
6.82 ms ± 134 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
>> > % timeit - n1000 add_string_with_format ( NUM_ITERS ) # Линейное увеличение
645 µs ± 24.5 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
>> > % timeit - n1000 add_string_with_join ( NUM_ITERS ) # Линейное увеличение
1.17 ms ± 7.25 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
>> > l = [ " xyz " ] * NUM_ITERS
>> > % timeit - n1000 convert_list_to_string ( l , NUM_ITERS ) # Линейное увеличение
86.3 µs ± 2 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
` ` `
#### 💡 Объяснение
- Подробнее о [ timeit ] ( https : / / docs . python . org / 3 / library / timeit . html ) или [ % timeit ] ( https : / / ipython . org / ipython - doc / dev / interactive / magics . html #magic-timeit) вы можете прочитать по этим ссылкам. Они используются для измерения времени выполнения фрагментов кода.
- Н е используйте ` + ` для генерации длинных строк - В Python ` str ` неизменяема , поэтому левая и правая строки должны быть скопированы в новую строку для каждой пары конкатенаций . Если вы конкатенируете четыре строки длины 10 , то вместо 40 символов вы скопируете ( 10 + 10 ) + ( ( 10 + 10 ) + 10 ) + ( ( ( 10 + 10 ) + 10 ) + 10 ) = 90 символов . С увеличением количества и размера строки ситуация ухудшается в квадратичной прогрессии ( что подтверждается временем выполнения функции ` add_bytes_with_plus ` ) .
- Поэтому рекомендуется использовать синтаксис ` . format . ` или ` % ` ( правда , для очень коротких строк они немного медленнее , чем ` + ` ) .
- Или лучше , если у вас уже есть содержимое в виде итерируемого объекта , тогда используйте ` ' ' . join ( iterable_object ) ` , что гораздо быстрее .
- В отличие от ` add_bytes_with_plus ` из - за оптимизаций ` + = ` , рассмотренных в предыдущем примере , ` add_string_with_plus ` не показало квадратичного увеличения времени выполнения . Если бы оператор был ` s = s + " x " + " y " + " z " ` вместо ` s + = " xyz " ` , увеличение было бы квадратичным .
` ` ` py
def add_string_with_plus ( iters ) :
s = " "
for i in range ( iters ) :
s = s + " x " + " y " + " z "
assert len ( s ) == 3 * iters
>> > % timeit - n100 add_string_with_plus ( 1000 )
388 µs ± 22.4 µs per loop ( mean ± std . dev . of 7 runs , 1000 loops each )
2024-04-27 12:21:12 +03:00
>> > % timeit - n100 add_string_with_plus ( 10000 ) # Квадратичное увеличение времени выполнения
2024-04-24 16:16:10 +03:00
9 ms ± 298 µs per loop ( mean ± std . dev . of 7 runs , 100 loops each )
` ` `
- Такое число способов форматирования и создания гигантской строки несколько противоречит [ Zen of Python ] ( https : / / www . python . org / dev / peps / pep - 0020 / ) , согласно которому ,
> должен быть один - и желательно только один - очевидный способ сделать это .
2024-04-24 16:06:24 +03:00
- - -
2024-04-24 16:21:51 +03:00
### ▶ Замедляем поиск по `dict` *
< ! - - Example ID : c9c26ce6 - df0c - 47 f7 - af0b - 966 b9386d4c3 - - - >
` ` ` py
some_dict = { str ( i ) : 1 for i in range ( 1_000_000 ) }
another_dict = { str ( i ) : 1 for i in range ( 1_000_000 ) }
` ` `
* * Результат : * *
` ` ` py
>> > % timeit some_dict [ ' 5 ' ]
28.6 ns ± 0.115 ns per loop ( mean ± std . dev . of 7 runs , 10000000 loops each )
>> > some_dict [ 1 ] = 1
>> > % timeit some_dict [ ' 5 ' ]
37.2 ns ± 0.265 ns per loop ( mean ± std . dev . of 7 runs , 10000000 loops each )
>> > % timeit another_dict [ ' 5 ' ]
28.5 ns ± 0.142 ns per loop ( mean ± std . dev . of 7 runs , 10000000 loops each )
>> > another_dict [ 1 ] # Пытаемся получить значение по несуществующему ключу
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
KeyError : 1
>> > % timeit another_dict [ ' 5 ' ]
38.5 ns ± 0.0913 ns per loop ( mean ± std . dev . of 7 runs , 10000000 loops each )
` ` `
Почему одни и те же выражения становятся медленнее ?
#### 💡 Объяснение:
+ В CPython есть общая функция поиска по словарю , которая работает с о всеми типами ключей ( ` str ` , ` int ` , любой объект . . . ) , и специализированная для распространенного случая словарей , состоящих только из ` str ` - ключей .
2024-04-27 12:21:12 +03:00
+ Специализированная функция ( названная ` lookdict_unicode ` в [ CPython ] ( https : / / github . com / python / cpython / blob / 522691 c46e2ae51faaad5bbbce7d959dd61770df / Objects / dictobject . c #L841)) знает, что все существующие ключи (включая искомый ключ) являются строками, и использует более быстрое и простое сравнение строк для сравнения ключей, вместо вызова метода `__eq__`.
2024-04-24 16:21:51 +03:00
+ При первом обращении к экземпляру ` dict ` с ключом , не являющимся ` str ` , он модифицируется , чтобы в дальнейшем для поиска использовалась общая функция .
+ Этот процесс не обратим для конкретного экземпляра ` dict ` , и ключ даже не обязательно должен существовать в словаре . Поэтому попытка неудачного поиска имеет тот же эффект .
- - -
2024-04-24 16:28:57 +03:00
### ▶ Раздуваем экземпляры словарей *
< ! - - Example ID : fe706ab4 - 1615 - c0ba - a078 - 76 c98cbe3f48 - - - >
` ` ` py
import sys
class SomeClass :
def __init__ ( self ) :
self . some_attr1 = 1
self . some_attr2 = 2
self . some_attr3 = 3
self . some_attr4 = 4
def dict_size ( o ) :
return sys . getsizeof ( o . __dict__ )
` ` `
* * Результат : * * ( Python 3.8 , другие версии Python 3 могут немного отличаться )
` ` ` py
>> > o1 = SomeClass ( )
>> > o2 = SomeClass ( )
>> > dict_size ( o1 )
104
>> > dict_size ( o2 )
104
>> > del o1 . some_attr1
>> > o3 = SomeClass ( )
>> > dict_size ( o3 )
232
>> > dict_size ( o1 )
232
` ` `
Попробуем снова . . . В новом сессии интерпретатора :
` ` ` py
>> > o1 = SomeClass ( )
>> > o2 = SomeClass ( )
>> > dict_size ( o1 )
104 # как ожидается
>> > o1 . some_attr5 = 5
>> > o1 . some_attr6 = 6
>> > dict_size ( o1 )
360
>> > dict_size ( o2 )
272
>> > o3 = SomeClass ( )
>> > dict_size ( o3 )
232
` ` `
Что заставляет эти словари раздуваться ? И почему только созданные объекты также раздуваются ?
#### 💡 Объяснение:
+ CPython может повторно использовать один и тот же объект " keys " в нескольких словарях . Это было добавлено в [ PEP 412 ] ( https : / / www . python . org / dev / peps / pep - 0412 / ) с целью сокращения использования памяти , особенно в экземплярах словарей - где ключи ( атрибуты экземпляра ) , как правило , общие для всех экземпляров .
+ Эта оптимизация совершенно беспроблемна для экземпляров словарей , но она не работает , если нарушены некоторые условия .
+ Словари с общим доступом к ключам не поддерживают удаление ; если атрибут экземпляра удаляется , словарь становится " не общим " , и общий доступ к ключам отключается для всех последующих экземпляров того же класса .
+ Кроме того , если размер ключей словаря был изменен ( из - за вставки новых ключей ) , они остаются общими * только * если они используются только одним словарем ( это позволяет добавить много атрибутов в ` __init__ ` самого первого созданного экземпляра , не вызывая " unshare " ) . Если на момент изменения размера существует несколько экземпляров , совместное использование ключей отключается для всех последующих экземпляров одного класса : CPython не может определить , используют ли ваши экземпляры один и тот же набор атрибутов , и решает отказаться от попытки поделиться ключами .
+ Небольшой совет , если вы стремитесь уменьшить занимаемый программой объем памяти : не удаляйте атрибуты экземпляров и обязательно инициализируйте все атрибуты в ` __init__ ` !
- - -
2024-04-24 17:00:05 +03:00
### ▶ Минорное *
< ! - - Example ID : f885cb82 - f1e4 - 4 daa - 9 ff3 - 972 b14cb1324 - - - >
* ` join ( ) ` - строковая операция вместо списочной . ( может показаться неочевидным при первом использовании )
* * 💡 Объяснение : * * Если ` join ( ) ` - это строковый метод , то он может работать с любым итеруемыми объектами ( список , кортеж , итераторы ) . Если бы это был списковый метод , то е г о пришлось бы реализовывать отдельно для каждого типа . Кроме того , нет о с о б о г о смысла помещать метод , специфичный для строки , в общий API объекта ` list ` .
* Несколько странных , но семантически правильных утверждений :
+ ` [ ] = ( ) ` - семантически корректное утверждение ( распаковка пустого ` кортежа ` в пустой ` список ` )
2024-04-27 12:21:12 +03:00
+ ` ' a ' [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] ` также является семантически корректным утверждением , поскольку в Python строки являются [ последовательностями ] ( https : / / docs . python . org / 3 / glossary . html #term-sequence) (итерируемыми объектами, поддерживающими доступ к элементам с использованием целочисленных индексов).
2024-04-24 17:00:05 +03:00
+ ` 3 - - 0 - - 5 == 8 ` и ` - - 5 == 5 ` - о б а семантически корректные утверждения и имеют значение ` True ` .
* Учитывая , что ` a ` - это число , ` + + a ` и ` - - a ` являются корректными утверждениями Python , но ведут себя не так , как аналогичные утверждения в таких языках , как C , C + + или Java .
` ` ` py
>> > a = 5
>> > a
5
>> > + + a
5
>> > - - a
5
` ` `
* * 💡 Объяснение : * *
+ В грамматике Python нет оператора ` + + ` . Н а самом деле это два оператора ` + ` .
+ ` + + a ` преобразуется в ` + ( + a ) ` , а затем в ` a ` . Аналогично для утверждения ` - - a ` .
+ Н а [ StackOverflow ] ( https : / / stackoverflow . com / questions / 3654830 / why - are - there - no - and - operators - in - python ) обсуждается обоснование отсутствия операторов инкремента и декремента в Python .
* Вы наверняка знаете о б операторе Walrus в Python . Н о слышали ли вы когда - нибудь о б операторе * пространственного инкремента * ?
` ` ` py
>> > a = 42
>> > a - = - 1
>> > a
43
` ` `
Он используется как альтернативный оператор инкрементации , вместе с другим оператором
` ` ` py
>> > a + = + 1
>> > a
>> > 44
` ` `
* * 💡 Объяснение : * * Этот розыгрыш взят из твита [ Raymond Hettinger ] ( https : / / twitter . com / raymondh / status / 1131103570856632321 ? lang = en ) . Н а самом деле оператор захвата пространства - это просто неправильно отформатированное ` a - = ( - 1 ) ` . Что эквивалентно ` a = a - ( - 1 ) ` . Аналогично для случая ` a + = ( + 1 ) ` .
* В Python есть недокументированный оператор [ обратная импликация ] ( https : / / en . wikipedia . org / wiki / Converse_implication ) .
` ` ` py
>> > False * * False == True
True
>> > False * * True == False
True
>> > True * * False == True
True
>> > True * * True == True
True
` ` `
* * 💡 Объяснение : * * Если заменить ` False ` и ` True ` на 0 и 1 и произвести математические вычисления , то таблица истинности будет эквивалентна оператору обратной импликации . ( [ Источник ] ( https : / / github . com / cosmologicon / pywat / blob / master / explanation . md #the-undocumented-converse-implication-operator))
* Раз уж мы заговорили о б операторах , есть еще оператор ` @ ` для умножения матриц ( не волнуйтесь , на этот раз он настоящий ) .
` ` ` py
>> > import numpy as np
>> > np . array ( [ 2 , 2 , 2 ] ) @ np . array ( [ 7 , 8 , 8 ] )
46
` ` `
* * 💡 Объяснение : * * Оператор ` @ ` был добавлен в Python 3.5 с учетом пожеланий научного сообщества . Любой объект может перегрузить магический метод ` __matmul__ ` , чтобы определить поведение этого оператора .
* Начиная с Python 3.8 для быстрой отладки можно использовать типичный синтаксис f - строк , например ` f ' { some_var =} `. Пример,
` ` ` py
>> > some_string = " wtfpython "
>> > f ' { some_string =} '
" some_string= ' wtfpython ' "
` ` `
* Python использует 2 байта для хранения локальных переменных в функциях . Теоретически это означает , что в функции может быть определено только 65536 переменных . Однако в python есть удобное решение , которое можно использовать для хранения более 2 ^ 16 имен переменных . Следующий код демонстрирует , что происходит в стеке , когда определено более 65536 локальных переменных ( Внимание : этот код печатает около 2 ^ 18 строк текста , так что будьте готовы ! ) :
` ` ` py
import dis
exec ( """
def f ( ) :
""" + """
""" .join([ " X " + str(x) + " = " + str(x) for x in range(65539)]))
f ( )
print ( dis . dis ( f ) )
` ` `
* Несколько потоков Python не смогут выполнять ваш * Python - код * одновременно ( да , вы не ослышались ! ) . Может показаться интуитивно понятным породить несколько потоков и позволить им выполнять ваш Python код одновременно , но из - за [ Global Interpreter Lock ] ( https : / / wiki . python . org / moin / GlobalInterpreterLock ) в Python , все , что вы делаете , это заставляете ваши потоки выполняться на одном и том же ядре по очереди . Потоки Python хороши для задач , связанных с IO , но чтобы добиться реального распараллеливания в Python для задач , связанных с процессором , вы можете использовать модуль Python [ multiprocessing ] ( https : / / docs . python . org / 3 / library / multiprocessing . html ) .
* Иногда метод ` print ` может выводить значения с задержкой . Например ,
` ` ` py
# Файл some_file.py
import time
print ( " wtfpython " , end = " _ " )
time . sleep ( 3 )
` ` `
Это выведет ` wtfpython ` через 3 секунды из - за аргумента ` end ` , потому что выходной буфер очищается либо при появлении ` \n ` , либо когда программа завершает выполнение . Мы можем принудительно отчистить буфер , передав аргумент ` flush = True ` .
* Срез списка индексом , превышающим длину списка , не приводит к ошибкам
` ` ` py
>> > some_list = [ 1 , 2 , 3 , 4 , 5 ]
>> > some_list [ 111 : ]
[ ]
` ` `
* При срезе итерируемого объекта не всегда создается новый объект . Например ,
` ` ` py
>> > some_str = " wtfpython "
>> > some_list = [ ' w ' , ' t ' , ' f ' , ' p ' , ' y ' , ' t ' , ' h ' , ' o ' , ' n ' ]
>> > some_list is some_list [ : ] # Ожидается False, так как создан новый объект.
False
>> > some_str is some_str [ : ] # Возвращается True, потому что строки неизменны, создание нового объекта ничего не меняет
True
` ` `
* ` int ( ' ١٢٣٤٥٦٧٨٩ ' ) ` возвращает ` 123456789 ` в Python 3. В Python десятичные символы включают в себя символы цифр и все символы , которые могут быть использованы для формирования десятично - радиксных чисел , например U + 0660 , ARABIC - INDIC DIGIT ZERO . Вот [ интересная история ] ( https : / / chris . improbable . org / 2014 / 8 / 25 / adventures - in - unicode - digits / ) , связанная с таким поведением Python .
* Начиная с Python 3 вы можете разделять числовые литералы символами подчеркивания ( для лучшей читаемости ) .
` ` ` py
>> > six_million = 6_000_000
>> > six_million
6000000
>> > hex_address = 0xF00D_CAFE
>> > hex_address
4027435774
` ` `
* ` ' abc ' . count ( ' ' ) == 4 ` . Вот примерная реализация метода ` count ` , которая немного разъяснит ситуацию
` ` ` py
def count ( s , sub ) :
result = 0
for i in range ( len ( s ) + 1 - len ( sub ) ) :
result + = ( s [ i : i + len ( sub ) ] == sub )
return result
` ` `
Такое поведение связано с совпадением пустой подстроки ( ` ' ' ` ) с о срезами длины 0 в исходной строке .
- - -
- - -
2024-04-25 11:00:05 +03:00
# Вклад в проект
Как можно внести свой вклад в развитие wtfpython ,
- Предложить новые примеры
- Помочь в переводе ( См . [ issues labeled translation ] ( https : / / github . com / satwikkansal / wtfpython / issues ? q = is % 3 Aissue + is % 3 Aopen + label % 3 Atranslation ) )
- Мелкие исправления , такие как указание на устаревшие фрагменты , опечатки , ошибки форматирования и т . д .
- Выявление пробелов ( таких как недостаточное объяснение , избыточные примеры и т . д . )
- Любые творческие предложения , чтобы сделать этот проект более интересным и полезным .
Пожалуйста , смотрите [ CONTRIBUTING . md ] ( / CONTRIBUTING . md ) для более подробной информации . Н е стесняйтесь создать новый [ issue ] ( https : / / github . com / satwikkansal / wtfpython / issues / new ) для обсуждения .
PS : Пожалуйста , не обращайтесь к нам с просьбами о б обратной ссылке , ссылки не будут добавлены , если они не имеют отношения к проекту .
2024-04-25 11:04:25 +03:00
# Благодарности
Идея и дизайн этой коллекции были изначально вдохновлены потрясающим проектом Дениса Дована [ wtfjs ] ( https : / / github . com / denysdovhan / wtfjs ) . Подавляющая поддержка с о стороны питонистов придала проекту ту форму , в которой он находится сейчас .
#### Несколько хороших ссылок!
* https : / / www . youtube . com / watch ? v = sH4XF6pKKmk
* https : / / www . reddit . com / r / Python / comments / 3 cu6ej / what_are_some_wtf_things_about_python
* https : / / sopython . com / wiki / Common_Gotchas_In_Python
* https : / / stackoverflow . com / questions / 530530 / python - 2 - x - gotchas - and - landmines
* https : / / stackoverflow . com / questions / 1011431 / common - pitfalls - in - python
* https : / / www . python . org / doc / humor /
* https : / / github . com / cosmologicon / pywat #the-undocumented-converse-implication-operator
* https : / / www . codementor . io / satwikkansal / python - practices - for - efficient - code - performance - memory - and - usability - aze6oiq65
* https : / / github . com / wemake - services / wemake - python - styleguide / search ? q = wtfpython & type = Issues
* Ветки обсуждения WFTPython на [ Hacker News ] ( https : / / news . ycombinator . com / item ? id = 21862073 ) и [ Reddit ] ( https : / / www . reddit . com / r / programming / comments / edsh3q / what_the_fck_python_30_exploring_and / ) .
2024-04-25 11:08:22 +03:00
# 🎓 Лицензия
[ ! [ WTFPL 2.0 ] [ license - image ] ] [ license - url ]
& copy ; [ Satwik Kansal ] ( https : / / satwikkansal . xyz )
[ license - url ] : http : / / www . wtfpl . net
[ license - image ] : https : / / img . shields . io / badge / License - WTFPL % 202.0 - lightgrey . svg ? style = flat - square
## Удиви своих друзей!
Если вам нравится ` wtfpython ` , вы можете поделиться проектом , используя быстрые ссылки ,
[ Twitter ] ( https : / / twitter . com / intent / tweet ? url = https : / / github . com / satwikkansal / wtfpython & text = If % 20 you % 20 really % 20 think % 20 you % 20 know % 20 Python , % 20 think % 20 once % 20 more ! % 20 Check % 20 out % 20 wtfpython & hashtags = python , wtfpython ) | [ Linkedin ] ( https : / / www . linkedin . com / shareArticle ? url = https : / / github . com / satwikkansal & title = What % 20 the % 20 f * ck % 20 Python ! & summary = If % 20 you % 20 really % 20 thing % 20 you % 20 know % 20 Python , % 20 think % 20 once % 20 more ! ) | [ Facebook ] ( https : / / www . facebook . com / dialog / share ? app_id = 536779657179021 & display = page & href = https % 3 A % 2 F % 2 Fgithub . com % 2 Fsatwikkansal % 2 Fwtfpython & quote = If % 20 you % 20 really % 20 think % 20 you % 20 know % 20 Python % 2 C % 20 think % 20 once % 20 more ! )
### Нужна PDF версия?
Я получил несколько запросов на pdf ( и epub ) версию wtfpython . Вы можете добавить свои данные [ здесь ] ( https : / / form . jotform . com / 221593245656057 ) , чтобы получить их , как только они будут готовы .
* * Вот и все , друзья ! * * Для получения новых материалов , подобных этому , вы можете добавить свой email [ сюда ] ( https : / / form . jotform . com / 221593598380062 ) .