From 57987cc9d58fbcc2d58ffb713c289b38a5b566ab Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:19:34 +0300 Subject: [PATCH 01/83] Translate header to russian - As discussed with maintainer, create folder for storing translations It will give more control, everything will be stored in 1 repository and it eliminates possible deletion or making translation private --- translations/README-ru.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 translations/README-ru.md diff --git a/translations/README-ru.md b/translations/README-ru.md new file mode 100644 index 0000000..897f658 --- /dev/null +++ b/translations/README-ru.md @@ -0,0 +1,17 @@ +

+

What the f*ck Python! 😱

+

Изучение и понимание Python с помощью нестандартного поведения и "магического" поведения.

+ +Переводы: [English Original](https://github.com/satwikkansal/wtfpython) [Chinese 中文](https://github.com/robertparley/wtfpython-cn) | [Vietnamese Tiếng Việt](https://github.com/vuduclyunitn/wtfptyhon-vi) | [Spanish Español](https://web.archive.org/web/20220511161045/https://github.com/JoseDeFreitas/wtfpython-es) | [Korean 한국어](https://github.com/buttercrab/wtfpython-ko) | [Russian Русский](https://github.com/nifadyev/wtfpython/tree/main/translations/README-ru.md) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) + +Альтернативные способы: [Интерактивный сайт](https://wtfpython-interactive.vercel.app) | [Интерактивный Jupiter notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) + +Python, будучи прекрасно спроектированным высокоуровневым языком программирования, предоставляет множество возможностей для удобства программиста. Но иногда результаты работы Python кода могут показаться неочевидными на первый взгляд. + +**wtfpython** задуман как проект, пытающийся объяснить, что именно происходит под капотом некоторых неочевидных фрагментов кода и менее известных возможностей Python. + +Если вы опытный программист на Python, вы можете принять это как вызов и правильно объяснить WTF ситуации с первой попытки. Возможно, вы уже сталкивались с некоторыми из них раньше, и я смогу оживить ваши старые добрые воспоминания! 😅 + +PS: Если вы уже читали **wtfpython** раньше, с изменениями можно ознакомиться [здесь](https://github.com/satwikkansal/wtfpython/releases/) (примеры, отмеченные звездочкой - это примеры, добавленные в последней основной редакции). + +Ну что ж, приступим... From 489ccb18a7f51ba027a9563fcfb9a1e502652b5a Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:34:40 +0300 Subject: [PATCH 02/83] Translate Structure of the Examples to russian --- translations/README-ru.md | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 897f658..4278ba5 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -15,3 +15,48 @@ Python, будучи прекрасно спроектированным выс PS: Если вы уже читали **wtfpython** раньше, с изменениями можно ознакомиться [здесь](https://github.com/satwikkansal/wtfpython/releases/) (примеры, отмеченные звездочкой - это примеры, добавленные в последней основной редакции). Ну что ж, приступим... + +# Содержание + +- [Содержание](#содержание) +- [Структура примера](#структура-примера) + + +# Структура примера + +Все примеры имеют следующую структуру: + +> ### ▶ Какой-то заголовок +> +> ```py +> # Неочевидный фрагмент кода +> # Подготовка к магии... +> ``` +> +> **Вывод (Python версия):** +> +> ```py +> >>> triggering_statement +> Неожиданные результаты +> ``` +> +> (Опционально): Краткое описание неожиданного результата +> +> +> #### 💡 Объяснение +> +> * Краткое объяснение того, что происходит и почему это происходит. +> +> ```py +> # Код +> # Дополнительные примеры для дальнейшего разъяснения (если необходимо) +> ``` +> +> **Вывод (Python версия):** +> +> ```py +> >>> trigger # какой-нибудь пример, позволяющий легко раскрыть магию +> # обоснованный вывод +> ``` + +**Важно:** Все примеры протестированы на интерактивном интерпретаторе Python 3.5.2, и они должны работать для всех версий Python, если это явно не указано перед выводом. From b5b8b83c0a8b2a175a81bbfe375804f3130e9b25 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:43:04 +0300 Subject: [PATCH 03/83] Translate usage to russian --- translations/README-ru.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index 4278ba5..9f50533 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -20,7 +20,7 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [Содержание](#содержание) - [Структура примера](#структура-примера) - +- [Применение](#применение) # Структура примера @@ -60,3 +60,21 @@ PS: Если вы уже читали **wtfpython** раньше, с измен > ``` **Важно:** Все примеры протестированы на интерактивном интерпретаторе Python 3.5.2, и они должны работать для всех версий Python, если это явно не указано перед выводом. + +# Применение + +Хороший способ получить максимальную пользу от этих примеров - читать их последовательно, причем для каждого из них важно: + +- Внимательно изучить исходный код. Если вы опытный программист на Python, то в большинстве случаев сможете предугадать, что произойдет дальше. +- Прочитать фрагменты вывода и, + - Проверить, совпадают ли выходные данные с вашими ожиданиями. + - Убедиться, что вы знаете точную причину, по которой вывод получился именно таким. + - Если ответ отрицательный (что совершенно нормально), сделать глубокий вдох и прочитать объяснение (а если пример все еще непонятен, и создайте issue [здесь](https://github.com/satwikkansal/wtfpython/issues/new)). + - Если "да", ощутите мощь своих познаний в Python и переходите к следующему примеру. + +PS: Вы также можете читать WTFPython в командной строке, используя [pypi package](https://pypi.python.org/pypi/wtfpython), + +```sh +pip install wtfpython -U +wtfpython +``` From 86140390adcaece9fd84ece152af4c8a0701557f Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:01:26 +0300 Subject: [PATCH 04/83] Translate First things first! example to russian --- translations/README-ru.md | 127 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 9f50533..325980a 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -21,6 +21,10 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [Содержание](#содержание) - [Структура примера](#структура-примера) - [Применение](#применение) +- [👀 Примеры](#-примеры) + - [Секция: Напряги мозги!](#секция-напряги-мозги) + - [▶ Первым делом!](#-первым-делом) + - [💡 Обьяснение](#-обьяснение) # Структура примера @@ -78,3 +82,126 @@ PS: Вы также можете читать WTFPython в командной с pip install wtfpython -U wtfpython ``` + +# 👀 Примеры + +## Секция: Напряги мозги! + +### ▶ Первым делом! + + + + +По какой-то причине "моржовый оператор" (англ. walrus) `:=` в Python 3.8 стал довольно популярным. Давайте проверим его, + +1\. + +```py +# Python version 3.8+ + +>>> a = "wtf_walrus" +>>> a +'wtf_walrus' + +>>> a := "wtf_walrus" +File "", 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 "", 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 элементов. + +--- From c91a6073fbf0916a0c003b48e4903c3f53213889 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:33:44 +0300 Subject: [PATCH 05/83] Translate Strings can be tricky sometimes example to russian --- translations/README-ru.md | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 325980a..3e7170b 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -25,6 +25,8 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [Секция: Напряги мозги!](#секция-напряги-мозги) - [▶ Первым делом!](#-первым-делом) - [💡 Обьяснение](#-обьяснение) + - [▶ Строки иногда ведут себя непредсказуемо](#-строки-иногда-ведут-себя-непредсказуемо) + - [💡 Объяснение](#-объяснение) # Структура примера @@ -205,3 +207,80 @@ if a := some_func(): - Аналогично, `(a, b := 16, 19)` эквивалентно `(a, (b := 16), 19)`, которое есть не что иное, как кортеж из 3 элементов. --- + +### ▶ Строки иногда ведут себя непредсказуемо + + +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 символа интернируются. + - Строки интернируются во время компиляции (`'wtf'` будет интернирована, но `''.join(['w'', 't'', 'f'])` - нет) + - Строки, не состоящие из букв ASCII, цифр или знаков подчеркивания, не интернируются. В примере выше `'wtf!'` не интернируется из-за `!`. Реализацию этого правила в CPython можно найти [здесь](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19) + ![image](/images/string-intern/string_intern.png) +- Когда переменные `a` и `b` принимают значение `"wtf!"` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на вторую переменную. Если это выполняется в отдельных строках, он не "знает", что уже существует `"wtf!"` как объект (потому что `"wtf!"` не является неявно интернированным в соответствии с фактами, упомянутыми выше). Это оптимизация во время компиляции, не применяется к версиям CPython 3.7.x (более подробное обсуждение смотрите здесь [issue](https://github.com/satwikkansal/wtfpython/issues/100)). +- Единица компиляции в интерактивной среде 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). + +--- From e2d6ee66ccd58ebfe0a188b2ea73cf7c961aa01c Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 18 Apr 2024 14:45:13 +0300 Subject: [PATCH 06/83] Translate Be careful with chained operations example --- translations/README-ru.md | 49 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index 3e7170b..92b9e82 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -275,7 +275,7 @@ False - После "интернирования" многие переменные могут ссылаться на один и тот же строковый объект в памяти (тем самым экономя память). - В приведенных выше фрагментах строки неявно интернированы. Решение о том, когда неявно интернировать строку, зависит от реализации. Правила для интернирования строк следующие: - Все строки длиной 0 или 1 символа интернируются. - - Строки интернируются во время компиляции (`'wtf'` будет интернирована, но `''.join(['w'', 't'', 'f'])` - нет) + - Строки интернируются во время компиляции (`'wtf'` будет интернирована, но `''.join(['w'', 't', 'f'])` - нет) - Строки, не состоящие из букв ASCII, цифр или знаков подчеркивания, не интернируются. В примере выше `'wtf!'` не интернируется из-за `!`. Реализацию этого правила в CPython можно найти [здесь](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19) ![image](/images/string-intern/string_intern.png) - Когда переменные `a` и `b` принимают значение `"wtf!"` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на вторую переменную. Если это выполняется в отдельных строках, он не "знает", что уже существует `"wtf!"` как объект (потому что `"wtf!"` не является неявно интернированным в соответствии с фактами, упомянутыми выше). Это оптимизация во время компиляции, не применяется к версиям CPython 3.7.x (более подробное обсуждение смотрите здесь [issue](https://github.com/satwikkansal/wtfpython/issues/100)). @@ -284,3 +284,50 @@ False - Примечание: В Python 3.7 складывание констант было перенесено из оптимизатора peephole в новый оптимизатор AST с некоторыми изменениями в логике, поэтому четвертый фрагмент не работает в Python 3.7. Подробнее об изменении можно прочитать [здесь](https://bugs.python.org/issue11549). --- + + +### ▶ Осторожнее с цепочкой операций + +```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 +``` + +#### 💡 Объяснение: + +Согласно https://docs.python.org/3/reference/expressions.html#comparisons + +> Формально, если a, b, c, ..., y, z - выражения, а op1, op2, ..., opN - операторы сравнения, то a op1 b op2 c ... y opN z эквивалентно a op1 b и b op2 c и ... y opN z, за исключением того, что каждое выражение оценивается не более одного раза. + +Хотя такое поведение может показаться глупым в приведенных выше примерах, оно просто фантастично для таких вещей, как `a == b == c` и `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` + +--- From a7985b9edc4a17165d2715126d6a806612511f46 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:08:23 +0300 Subject: [PATCH 07/83] Translate How not to use is operator example --- translations/README-ru.md | 125 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 92b9e82..f1d9cf9 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -331,3 +331,128 @@ False В итоге, `1 < 1` выполняется и дает результат `False` --- + + +### ▶ Как не надо использовать оператор `is` + +Ниже приведен очень известный пример. + +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`. Это объясняет наш второй фрагмент. Перейдем к третьему, + +**И `a`, и `b` ссылаются на один и тот же объект при инициализации одним и тем же значением в одной и той же строкеi**. + +**Вывод** + +```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` уже существует. + +* Это оптимизация компилятора и относится именно к интерактивной среде. Когда вы вводите две строки в интерпретаторе, они компилируются отдельно, поэтому оптимизируются отдельно. Если выполнить этот пример в файле `.py', поведение будет отличаться, потому что файл компилируется весь сразу. Эта оптимизация не ограничивается целыми числами, она работает и для других неизменяемых типов данных, таких как строки (проверьте пример "Строки - это сложно") и плавающие числа, + + ```py + >>> a, b = 257.0, 257.0 + >>> a is b + True + ``` + +* Почему это не сработало в Python 3.7? Абстрактная причина в том, что такие оптимизации компилятора зависят от реализации (т.е. могут меняться в зависимости от версии, ОС и т.д.). Я все еще выясняю, какое именно изменение реализации вызвало проблему, вы можете проверить этот [issue](https://github.com/satwikkansal/wtfpython/issues/100) для получения обновлений. + +--- From 2840050acb1dbd6f3b67faf7b676c441bdd3e9a1 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:10:22 +0300 Subject: [PATCH 08/83] Translate Hash brownies and Deep down, we're all the same examples --- translations/README-ru.md | 117 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index f1d9cf9..358317c 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -456,3 +456,120 @@ False * Почему это не сработало в Python 3.7? Абстрактная причина в том, что такие оптимизации компилятора зависят от реализации (т.е. могут меняться в зависимости от версии, ОС и т.д.). Я все еще выясняю, какое именно изменение реализации вызвало проблему, вы можете проверить этот [issue](https://github.com/satwikkansal/wtfpython/issues/100) для получения обновлений. --- + + +### ▶ Мистическое хэширование + +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 + 0j +>>> type(complex_five) +complex +>>> some_dict[complex_five] +"Python" +``` + +Так почему же Python повсюду? + + +#### 💡 Объяснение + +* Уникальность ключей в словаре Python определяется *эквивалентностью*, а не тождеством. Поэтому, даже если `5`, `5.0` и `5 + 0j` являются различными объектами разных типов, поскольку они равны, они не могут находиться в одном и том же `dict` (или `set`). Как только вы вставите любой из них, попытка поиска по любому другому, но эквивалентному ключу будет успешной с исходным сопоставленным значением (а не завершится ошибкой `KeyError`): + ```py + >>> 5 == 5.0 == 5 + 0j + True + >>> 5 is not 5.0 is not 5 + 0j + True + >>> some_dict = {} + >>> some_dict[5.0] = "Ruby" + >>> 5.0 in some_dict + True + >>> (5 in some_dict) and (5 + 0j in some_dict) + True + ``` +* Это применимо и во время присваения значения элементу. Поэтому, в выражении `some_dict[5] = "Python"` Python находит существующий элемент с эквивалентным ключом `5.0 -> "Ruby"`, перезаписывает его значение на место, а исходный ключ оставляет в покое. + ```py + >>> some_dict + {5.0: 'Ruby'} + >>> some_dict[5] = "Python" + >>> some_dict + {5.0: 'Python'} + ``` +* Итак, как мы можем обновить ключ до `5` (вместо `5.0`)? На самом деле мы не можем сделать это обновление на месте, но что мы можем сделать, так это сначала удалить ключ (`del some_dict[5.0]`), а затем установить его (`some_dict[5]`), чтобы получить целое число `5` в качестве ключа вместо плавающего `5.0`, хотя это нужно в редких случаях. + +* Как Python нашел `5` в словаре, содержащем `5.0`? Python делает это за постоянное время без необходимости сканирования каждого элемента, используя хэш-функции. Когда Python ищет ключ `foo` в словаре, он сначала вычисляет `hash(foo)` (что выполняется в постоянном времени). Поскольку в Python требуется, чтобы объекты, которые сравниваются одинаково, имели одинаковое хэш-значение ([docs](https://docs.python.org/3/reference/datamodel.html#object.__hash__) здесь), `5`, `5.0` и `5 + 0j` имеют одинаковое хэш-значение. + ```py + >>> 5 == 5.0 == 5 + 0j + True + >>> hash(5) == hash(5.0) == hash(5 + 0j) + True + ``` + **Примечание:** Обратное не обязательно верно: Объекты с одинаковыми хэш-значениями сами могут быть неравными. (Это вызывает так называемую [хэш-коллизию](https://en.wikipedia.org/wiki/Collision_(computer_science)) и ухудшает производительность постоянного времени, которую обычно обеспечивает хэширование). + +--- + + +### ▶ В глубине души мы все одинаковы. + +```py +class WTF: + pass +``` + +**Вывод:** +```py +>>> WTF() == WTF() # разные экземпляры класса не могут быть равны +False +>>> WTF() is WTF() # идентификаторы также различаются +False +>>> hash(WTF()) == hash(WTF()) # хэши тоже должны отличаться +True +>>> id(WTF()) == id(WTF()) +True +``` +#### 💡 Объяснение: + +* При вызове `id` Python создал объект класса `WTF` и передал его функции `id`. Функция `id` забирает свой `id` (местоположение в памяти) и выбрасывает объект. Объект уничтожается. +* Когда мы делаем это дважды подряд, 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 + ``` + Как вы можете заметить, все дело в порядке уничтожения объектов. + +--- From 47fa96c31a1ba190dcea437ccc957896c26597d2 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:28:37 +0300 Subject: [PATCH 09/83] Translate Disorder within order example --- translations/README-ru.md | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 358317c..a683577 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -573,3 +573,102 @@ True Как вы можете заметить, все дело в порядке уничтожения объектов. --- + + +### ▶ Беспорядок внутри порядка * + +```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): + """ + A dict that also implements __hash__ magic. + """ + __hash__ = lambda self: 0 + +class OrderedDictWithHash(OrderedDict): + """ + An OrderedDict that also implements __hash__ magic. + """ + __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 + +# Мы все знаем, что множество состоит только из уникальных элементов, +# давайте попробуем составить множество из этих словарей и посмотрим, что получится... + +>>> len({dictionary, ordered_dict, another_ordered_dict}) +Traceback (most recent call last): + File "", line 1, in +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 +>>> len({ordered_dict, another_ordered_dict, dictionary}) # changing the order +2 +``` + +Что здесь происходит? + +#### 💡 Объяснение: + +- Переходное (интрантизивное) равенство между `dictionary`, `ordered_dict` и `another_ordered_dict` не выполняется из-за реализации магического метода `__eq__` в классе `OrderedDict`. Перевод цитаты из [документации](https://docs.python.org/3/library/collections.html#ordereddict-objects) + + > Тесты равенства между объектами OrderedDict чувствительны к порядку и реализуются как `list(od1.items())==list(od2.items())`. Тесты на равенство между объектами `OrderedDict` и другими объектами Mapping нечувствительны к порядку, как обычные словари. +- Причина такого поведения равенства в том, что оно позволяет напрямую подставлять объекты `OrderedDict` везде, где используется обычный словарь. +- Итак, почему изменение порядка влияет на длину генерируемого объекта `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`. + +--- From 83bdff8e3379aa046bb60346b91b163785be6506 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:36:33 +0300 Subject: [PATCH 10/83] Translate Keep trying example --- translations/README-ru.md | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index a683577..d164aaf 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -672,3 +672,64 @@ TypeError: unhashable type: 'dict' Таким образом, выражение `another_ordered_dict` в `another_set` равно `False`, потому что `ordered_dict` уже присутствовал в `another_set` и, как было замечено ранее, `ordered_dict == another_ordered_dict` равно `False`. --- + + +### ▶ Продолжай пытаться... * + +```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 "", line 1, in +ZeroDivisionError: division by zero + +>>> one_more_func() +Iteration 0 + +``` + +#### 💡 Объяснение: + +- Когда один из операторов `return`, `break` или `continue` выполняется в блоке `try` оператора "try...finally", на выходе также выполняется пункт `finally`. +- Возвращаемое значение функции определяется последним выполненным оператором `return`. Поскольку блок `finally` выполняется всегда, оператор `return`, выполненный в блоке `finally`, всегда будет последним. +- Предостережение - если в блоке `finally` выполняется оператор `return` или `break`, то временно сохраненное исключение отбрасывается. + +--- From 654da92e887babdec7994b64b819e93c33e7859b Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:43:52 +0300 Subject: [PATCH 11/83] Translate For what? example --- translations/README-ru.md | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index d164aaf..5b584ed 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -733,3 +733,57 @@ Iteration 0 - Предостережение - если в блоке `finally` выполняется оператор `return` или `break`, то временно сохраненное исключение отбрасывается. --- + + +### ▶ Для чего? + +```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 + ``` + +--- From 259fb23c7b0fd3ab6b32d809c7fa051eddc8f16b Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:27:26 +0300 Subject: [PATCH 12/83] Translate Evaluation time discrepancy example --- translations/README-ru.md | 69 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 5b584ed..d89a3ce 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -787,3 +787,72 @@ for i, some_dict[i] in enumerate(some_string): ``` --- + + +### ▶ Расхождение во времени исполнения + +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] +``` + +#### 💡 Пояснение + +- В выражении [генераторе](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-выражение исполняется немедленно, остальные выражения откладываются до запуска генератора. + +--- From 497b9de72b073a38c071f4170073b513e5c3f7b2 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:31:02 +0300 Subject: [PATCH 13/83] Translate is not ...is (not ...) example --- translations/README-ru.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index d89a3ce..0f4387d 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -844,7 +844,7 @@ array_4 = [400, 500, 600] [401, 501, 601, 402, 502, 602, 403, 503, 603] ``` -#### 💡 Пояснение +#### 💡 Объяснение - В выражении [генераторе](https://wiki.python.org/moin/Generators) условие `in` оценивается во время объявления, но условие `if` оценивается во время выполнения. - Перед выполнением кода, значение переменной `array` изменяется на список `[2, 8, 22]`, а поскольку из `1`, `8` и `15` только счетчик `8` больше `0`, генератор выдает только `8`. @@ -856,3 +856,21 @@ array_4 = [400, 500, 600] > Только крайнее for-выражение исполняется немедленно, остальные выражения откладываются до запуска генератора. --- + + +### ▶ `is not ...` не является `is (not ...)` + +```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`. + +--- From 361ac5f49ba590b3d33697a28d23eb2e9be1b74e Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:41:30 +0300 Subject: [PATCH 14/83] Translate A tic-tac-toe where X wins in the first attempt! example --- translations/README-ru.md | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 0f4387d..6e39080 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -874,3 +874,51 @@ False - В примере `(not None)` оценивается в `True`, поскольку значение `None` является `False` в булевом контексте, поэтому выражение становится `'something' is True`. --- + + +### ▶ Крестики-нолики, где X побеждает с первой попытки! + + +```py +# Инициализируем переменную row +row = [""] * 3 #row i['', '', ''] +# Инициализируем игровую сетку +board = [row] * 3 +``` + +**Результат:** + +```py +>>> board +[['', '', ''], ['', '', ''], ['', '', '']] +>>> board[0] +['', '', ''] +>>> board[0][0] +'' +>>> board[0][0] = "X" +>>> board +[['X', '', ''], ['X', '', ''], ['X', '', '']] +``` + +Мы же не назначили три `"Х"`? + +#### 💡 Объяснение: + +Когда мы инициализируем переменную `row`, эта визуализация объясняет, что происходит в памяти + +![image](/images/tic-tac-toe/after_row_initialized.png) + +А когда переменная `board` инициализируется путем умножения `row`, вот что происходит в памяти (каждый из элементов `board[0]`, `board[1]` и `board[2]` является ссылкой на тот же список, на который ссылается `row`) + +![image](/images/tic-tac-toe/after_board_initialized.png) + +Мы можем избежать этого сценария, не используя переменную `row` для генерации `board`. (Подробнее в [issue](https://github.com/satwikkansal/wtfpython/issues/68)). + +```py +>>> board = [['']*3 for _ in range(3)] +>>> board[0][0] = "X" +>>> board +[['X', '', ''], ['', '', ''], ['', '', '']] +``` + +--- From 4576463fccebbf9cfabd9f904bde94e1dc013795 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 19 Apr 2024 15:02:10 +0300 Subject: [PATCH 15/83] =?UTF-8?q?Translate=20=20Schr=C3=B6dinger's=20varia?= =?UTF-8?q?ble=20*=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- translations/README-ru.md | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 6e39080..09df51c 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -922,3 +922,80 @@ board = [row] * 3 ``` --- + + +### ▶ Переменная Шредингера * + + + +```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] +``` + +**Вывод (Python version):** +```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] +``` + +* Чтобы получить желаемое поведение, вы можете передать переменную цикла как именованную переменную в функцию. **Почему это работает?** Потому что это определит переменную *внутри* области видимости функции. Она больше не будет обращаться к глобальной области видимости для поиска значения переменной, а создаст локальную переменную, которая будет хранить значение `x` в данный момент времени. + +```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()) +``` + +--- From 446a3a09bb04556dc5d2423339b1e8845ec18b0e Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sun, 21 Apr 2024 10:32:21 +0300 Subject: [PATCH 16/83] Translate Chicken egg problem example --- translations/README-ru.md | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 09df51c..3d299f3 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -999,3 +999,54 @@ ClosureVars(nonlocals={}, globals={}, builtins={}, unbound=set()) ``` --- + + +### ▶ Проблема курицы и яйца * + +1\. +```py +>>> isinstance(3, int) +True +>>> isinstance(type, object) +True +>>> isinstance(object, type) +True +``` + +Так какой же базовый класс является "окончательным"? Кстати, это еще не все, + +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 из-за "обмана" на уровне реализации. + +--- From a32eaca58f2129ecf5976aec912577ad35d81b82 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sun, 21 Apr 2024 10:41:17 +0300 Subject: [PATCH 17/83] Translate Sublass relationships example --- translations/README-ru.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 3d299f3..e79facc 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1050,3 +1050,28 @@ False - Эти отношения между `object` и `type` (оба являются экземплярами друг друга, а также самих себя) существуют в Python из-за "обмана" на уровне реализации. --- + + +### ▶ Отношения между подклассами + +**Вывод:** +```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` или во всем, от чего он наследуется. +* Поскольку `object` является хэшируемым, а `list` - нехэшируемым, это нарушает отношение транзитивности. +* Более подробное объяснение можно найти [здесь] (https://www.naftaliharris.com/blog/python-subclass-intransitivity/). + +--- From 6e246d1487c6e1700aa1d0a16c2bc98b18c83649 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sun, 21 Apr 2024 10:57:44 +0300 Subject: [PATCH 18/83] Translate Methods equality and identity example --- translations/README-ru.md | 102 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index e79facc..b5627b6 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1075,3 +1075,105 @@ False * Более подробное объяснение можно найти [здесь] (https://www.naftaliharris.com/blog/python-subclass-intransitivity/). --- + + +### ▶ Равенство и тождество методов + + +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). Всякий раз, когда к функции обращаются как к +атрибута, вызывается дескриптор, создавая объект метода, который "связывает" функцию с объектом, владеющим атрибутом. При вызове метод вызывает функцию, неявно передавая связанный объект в качестве первого аргумента +(именно так мы получаем `self` в качестве первого аргумента, несмотря на то, что не передаем его явно). +```py +>>> o1.method +> +``` +* При многократном обращении к атрибуту каждый раз создается объект метода! Поэтому `o1.method is o1.method` всегда ложно. Однако доступ к функциям как к атрибутам класса (в отличие от экземпляра) не создает методов; поэтому +`SomeClass.method is SomeClass.method` является истинным. +```py +>>> SomeClass.method + +``` +* `classmethod` преобразует функции в методы класса. Методы класса - это дескрипторы, которые при обращении к ним создают +объект метода, который связывает *класс* (тип) объекта, а не сам объект. +```py +>>> o1.classm +> +``` +* В отличие от функций, `classmethod` будет создавать метод и при обращении к нему как к атрибуту класса (в этом случае они +привязываются к классу, а не к его типу). Поэтому `SomeClass.classm is SomeClass.classm` является ошибочным. +```py +>>> SomeClass.classm +> +``` +* Объект-метод равен, если обе функции равны, а связанные объекты одинаковы. Поэтому +`o1.method == o1.method` является истинным, хотя и не является одним и тем же объектом в памяти. +* `staticmethod` преобразует функции в дескриптор "no-op", который возвращает функцию как есть. Методы-объекты +никогда не создается, поэтому сравнение с `is` является истинным. +```py +>>> o1.staticm + +>>> SomeClass.staticm + +``` +* Необходимость создавать новые объекты "метод" каждый раз, когда Python вызывает методы экземпляра, и необходимость изменять аргументы +каждый раз, чтобы вставить `self`, сильно сказывается на производительности. +CPython 3.7 [решил эту проблему](https://bugs.python.org/issue26110), введя новые опкоды, которые работают с вызовом методов +без создания временных объектов методов. Это используется только при фактическом вызове функции доступа, так что +приведенные здесь фрагменты не затронуты и по-прежнему генерируют методы :) + +--- From 191ea8343bffe58765fd16f2f43d1acec7fd75e8 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 12:02:32 +0300 Subject: [PATCH 19/83] Translate The surprising comma example --- translations/README-ru.md | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index b5627b6..c191aff 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1177,3 +1177,74 @@ CPython 3.7 [решил эту проблему](https://bugs.python.org/issue26 приведенные здесь фрагменты не затронуты и по-прежнему генерируют методы :) --- + + +### ▶ All-true-ation (непереводимая игра слов) * + + +```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`. Это происходит потому, что единственный элемент переданного массива (`[[...]]`) уже не пуст, а списки со значениями являются истинными. + +--- + + +### ▶ Неожиданная запятая + +**Вывод (< 3.6):** + +```py +>>> def f(x, y,): +... print(x, y) +... +>>> def g(x=4, y=5,): +... print(x, y) +... +>>> def h(x, **kwargs,): + File "", line 1 + def h(x, **kwargs,): + ^ +SyntaxError: invalid syntax + +>>> def h(*args,): + File "", line 1 + def h(*args,): + ^ +SyntaxError: invalid syntax +``` + +#### 💡 Объяснение: + +- Запятая в конце списка аргументов функции Python не всегда законна. +- В Python список аргументов определяется частично с помощью ведущих запятых, а частично с помощью запятых в конце списка. Этот конфликт приводит к ситуациям, когда запятая оказывается в середине, и ни одно из правил не выполняется. +- **Примечание:** Проблема с запятыми в конце списка аргументов [исправлена в Python 3.6](https://bugs.python.org/issue9232). Варианты использования запятых в конце выражения приведены в [обсуждении](https://bugs.python.org/issue9232#msg248399). + +--- From 293575b7c44cb3c1dac6eead794ab15cc492a0d1 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 12:08:53 +0300 Subject: [PATCH 20/83] Translate String and backslashes example --- translations/README-ru.md | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index c191aff..387f8d7 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1248,3 +1248,47 @@ SyntaxError: invalid syntax - **Примечание:** Проблема с запятыми в конце списка аргументов [исправлена в Python 3.6](https://bugs.python.org/issue9232). Варианты использования запятых в конце выражения приведены в [обсуждении](https://bugs.python.org/issue9232#msg248399). --- + + +### ▶ Строки и обратные слэши + +**Вывод:** +```py +>>> print("\"") +" + +>>> print(r"\"") +\" + +>>> print(r"\") +File "", line 1 + print(r"\") + ^ +SyntaxError: EOL while scanning string literal + +>>> r'\'' == "\\'" +True +``` + +#### 💡 Объяснение + +- В обычной строке обратная слэш используется для экранирования символов, которые могут иметь специальное значение (например, одинарная кавычка, двойная кавычка и сам обратный слэш). + ```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' + ``` +- Это означает, что когда синтаксический анализатор встречает обратный слэш в необработанной строке, он ожидает, что за ней последует другой символ. А в нашем случае (`print(r"\")`) обратная слэш экранирует двойную кавычку, оставив парсер без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слеш не работает в конце необработанной строки. + +--- From 5eeb1053aaeaa72e7b052c569eeb52638e21a661 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 12:13:13 +0300 Subject: [PATCH 21/83] Translate Not knot example --- translations/README-ru.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 387f8d7..0af0e51 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1291,4 +1291,32 @@ True ``` - Это означает, что когда синтаксический анализатор встречает обратный слэш в необработанной строке, он ожидает, что за ней последует другой символ. А в нашем случае (`print(r"\")`) обратная слэш экранирует двойную кавычку, оставив парсер без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слеш не работает в конце необработанной строки. +-- + + +### ▶ Не узел! (eng. not knot!) + +```py +x = True +y = False +``` + +**Результат:** +```py +>>> not x == y +True +>>> x == not y + File "", 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)`, что можно было бы ожидать на первый взгляд. +* Парсер ожидал, что ключевое слово `not` будет частью оператора `not in` (потому что оба оператора `==` и `not in` имеют одинаковый приоритет), но после того, как он не смог найти ключевое слово `in`, следующее за `not`, он выдает `SyntaxError`. + --- From 8a1536986f14f1bfddfd0c434f4fb178e6171fcb Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 12:19:28 +0300 Subject: [PATCH 22/83] Translate Half triple-quoted strings example --- translations/README-ru.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 0af0e51..2a8ac33 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1320,3 +1320,33 @@ SyntaxError: invalid syntax * Парсер ожидал, что ключевое слово `not` будет частью оператора `not in` (потому что оба оператора `==` и `not in` имеют одинаковый приоритет), но после того, как он не смог найти ключевое слово `in`, следующее за `not`, он выдает `SyntaxError`. --- + + +### ▶ Строки наполовину в тройных кавычках + +**Вывод:** +```py +>>> print('wtfpython''') +wtfpython +>>> print("wtfpython""") +wtfpython +>>> # Выражения ниже приводят к `SyntaxError` +>>> # print('''wtfpython') +>>> # print("""wtfpython") + File "", 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 ожидал завершающую тройную кавычку в качестве разделителя при сканировании текущего встреченного строкового литерала с тройной кавычкой. + +--- From a0069d842e8c79d257590697eff9773bed37ace2 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 13:58:11 +0300 Subject: [PATCH 23/83] Translate What's wrong with booleans? example --- translations/README-ru.md | 90 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 2a8ac33..70a7743 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1350,3 +1350,93 @@ SyntaxError: EOF while scanning triple-quoted string literal + `'''` и `"""` также являются разделителями строк в Python, что вызывает SyntaxError, поскольку интерпретатор Python ожидал завершающую тройную кавычку в качестве разделителя при сканировании текущего встреченного строкового литерала с тройной кавычкой. --- + +### ▶ Что не так с логическими значениями? + +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` нельзя было сделать константами. Они просто были встроенными переменными, и их можно было переназначить. + +* Python 3 был несовместим с предыдущими версиями, эту проблему наконец-то исправили, и поэтому последний фрагмент не будет работать с Python 3.x! + +--- From 972d1334fb1b75f154a355138b4e9abbc629d42c Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:03:16 +0300 Subject: [PATCH 24/83] Translate Class attributes and instance atributes example --- translations/README-ru.md | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 70a7743..23a67c5 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1440,3 +1440,74 @@ I have lost faith in truth! * Python 3 был несовместим с предыдущими версиями, эту проблему наконец-то исправили, и поэтому последний фрагмент не будет работать с Python 3.x! --- + + +### ▶ Атрибуты класса и экземпляра + +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 +``` + +#### 💡 Объяснение: + +* Переменные класса и переменные экземпляров класса внутренне обрабатываются как словари объекта класса. Если имя переменной не найдено в словаре текущего класса, оно ищется в родительских классах. +* Оператор += изменяет объект на месте, не создавая новый объект. Таким образом, изменение атрибута одного экземпляра влияет на другие экземпляры и атрибут класса также. + +--- From ecaab6dca1f6b87e11fd38bf0ddcff303f9eb214 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:05:53 +0300 Subject: [PATCH 25/83] Translate Yielding None example --- translations/README-ru.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 23a67c5..5f3f4bb 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1511,3 +1511,36 @@ True * Оператор += изменяет объект на месте, не создавая новый объект. Таким образом, изменение атрибута одного экземпляра влияет на другие экземпляры и атрибут класса также. --- + + +### ▶ Возврат None из генератора + +```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] + 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`. + +--- From 51d13b87cf0b3b2dd50cb1a84dc867329771ae45 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:13:11 +0300 Subject: [PATCH 26/83] Translate Yielding from... return example --- translations/README-ru.md | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 5f3f4bb..638536d 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1544,3 +1544,69 @@ def some_func(val): - В Python 3.8+ yield внутри списочных выражений больше не допускается и выдает `SyntaxError`. --- + + +### ▶ Yield from возвращает... * + +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)) +[] +``` + +То же самое, это тоже не сработало. Что происходит? + +#### 💡 Объяснение: + ++ С 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)` при выходе из генератора." + ++ В случае `some_func(3)` `StopIteration` возникает в начале из-за оператора `return`. Исключение `StopIteration` автоматически перехватывается внутри обертки `list(...)` и цикла `for`. Поэтому два вышеприведенных фрагмента приводят к пустому списку. + ++ Чтобы получить `["wtf"]` из генератора `some_func`, нужно перехватить исключение `StopIteration`. + + ```py + try: + next(some_func(3)) + except StopIteration as e: + some_string = e.value + ``` + + ```py + >>> some_string + ["wtf"] + ``` + +--- From 495c8402542277bfbda65d6c314a87e2664b76c4 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:21:35 +0300 Subject: [PATCH 27/83] Translate Nan-reflexivity example --- translations/README-ru.md | 75 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 638536d..9183b74 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1610,3 +1610,78 @@ def some_func(x): ``` --- + + +### ▶ Nan-рефлексивность * + + + +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 +>>> y is y # идендичность сохраняется +True +>>> y == y # сравнение ложно для y +False +>>> [y] == [y] # но сравнение истинно для списка, содержащего y +True +``` + +#### 💡 Объяснение: + +- `'inf'` и `'nan'` - это специальные строки (без учета регистра), которые при явном приведении к типу `float` используются для представления математической "бесконечности" и "не число" соответственно. + +- Согласно стандартам IEEE `NaN != NaN`, но соблюдение этого правила нарушает предположение о рефлексивности элемента коллекции в Python, то есть если `x` является частью коллекции, такой как `list`, реализации, методы сравнения предполагают, что `x == x`. Поэтому при сравнении элементов сначала сравниваются их идентификаторы (так как это быстрее), а значения сравниваются только при несовпадении идентификаторов. Следующий фрагмент сделает вещи более ясными: + + ```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/) + +--- From f2b1d7e8c290f21559b4748413b9faac13173a69 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:33:23 +0300 Subject: [PATCH 28/83] Translate Mutating the immutable! example --- translations/README-ru.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 9183b74..30384e7 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1685,3 +1685,42 @@ True - Интересное чтение: [Рефлексивность и другие основы цивилизации](https://bertrandmeyer.com/2010/02/06/reflexivity-and-other-pillars-of-civilization/) --- + + +### ▶ Мутируем немутируемое! + + + +Это может показаться тривиальным, если вы знаете, как работают ссылки в 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) + + > Неизменяемые последовательности + Объект неизменяемого типа последовательности не может измениться после создания. (Если объект содержит ссылки на другие объекты, эти объекты могут быть изменяемыми и могут быть изменены; однако набор объектов, на которые непосредственно ссылается неизменяемый объект, не может изменяться.) + +* Оператор `+=` изменяет список на месте. Присваивание элемента не работает, но когда возникает исключение, элемент уже был изменен на месте. +* Также есть объяснение в официальном [Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works). + +--- From 58de881f9320e4f18fba43a52d53601fb99d5303 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:51:49 +0300 Subject: [PATCH 29/83] Translate The dissapearing variable from outer scope example --- translations/README-ru.md | 82 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 30384e7..382aab8 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1724,3 +1724,85 @@ TypeError: 'tuple' object does not support item assignment * Также есть объяснение в официальном [Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works). --- + + +### ▶ Исчезающая переменная из внешней области видимости + + +```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 + ``` + +Это означает, что исключению должно быть присвоено другое имя, чтобы на него можно было ссылаться после завершения блока `except`. Исключения очищаются, потому что с прикрепленным к ним трейсбэком они образуют цикл ссылок со стеком вызовов, сохраняя все локальные объекты в этой стэке до следующей сборки мусора. + +* В Python clauses не имеют области видимости. В примере все объекты в одной области видимости, а переменная `e` была удалена из-за выполнения блока `except`. Этого нельзя сказать о функциях, которые имеют отдельные внутренние области видимости. Пример ниже иллюстрирует это: + +```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] + ``` + +* В Python 2.x, имя переменной `e` назначается на экземпляр `Exception()`, и при попытки вывести значение `e` ничего не выводится. + + **Результат (Python 2.x):** + ```py + >>> e + Exception() + >>> print e + # Ничего не выводится! + ``` + +--- From f96f5117c57be7e9d1de0cd603976d5320b78a00 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:08:54 +0300 Subject: [PATCH 30/83] Translate The mysterious key type conversion example --- translations/README-ru.md | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 382aab8..e032170 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1806,3 +1806,60 @@ NameError: name 'e' is not defined ``` --- + + +### ▶ Загадочное преобразование типов ключей + +```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) + ``` + +--- From c125f25fb5841000d2ca9eaa1e11ddc5023757fd Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:19:58 +0300 Subject: [PATCH 31/83] Translate Let's see if you can guess this? example --- translations/README-ru.md | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index e032170..2c35c8f 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1863,3 +1863,61 @@ str ``` --- + + +### ▶ Посмотрим, сможете ли вы угадать что здесь? + +```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 + ``` + + --- From 3fc9e9e028c9d55eeb4c6933e0f712aeadd6241d Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:24:31 +0300 Subject: [PATCH 32/83] Translate Exceeds the linit for integer string conversion example --- translations/README-ru.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 2c35c8f..6309e60 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1921,3 +1921,33 @@ a, b = a[b] = {}, 5 ``` --- + + +### ▶ Превышение предела целочисленного преобразования строк +```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 все еще может работать с большими целыми числами. Ошибка возникает только при преобразовании между целыми числами и строками. +К счастью, вы можете увеличить предел допустимого количества цифр. Для этого можно воспользоваться одним из следующих способов: +- `-X int_max_str_digits` - флаг командной строкиcommand-line flag +- `set_int_max_str_digits()` - функция из модуля `sys` +- `PYTHONINTMAXSTRDIGITS` - переменная окружения + +[Смотри документацию](https://docs.python.org/3/library/stdtypes.html#int-max-str-digits) для получения более подробной информации об изменении лимита по умолчанию, если вы ожидаете, что ваш код превысит это значение. + +--- From eccd68a4bd276b7dd7b1dda7a9bbbca44407f40e Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:37:59 +0300 Subject: [PATCH 33/83] Translate Modifying dictionary while iterating over it example --- translations/README-ru.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 6309e60..f880219 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1951,3 +1951,42 @@ ValueError: Exceeds the limit (4300) for integer string conversion: [Смотри документацию](https://docs.python.org/3/library/stdtypes.html#int-max-str-digits) для получения более подробной информации об изменении лимита по умолчанию, если вы ожидаете, что ваш код превысит это значение. --- + + +## Секция: Скользкие склоны + +### ▶ Изменение словаря во время прохода по нему + +```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`. + +--- From b1a8aadd704c13ecac3d771a6903afdaeee1d080 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:53:40 +0300 Subject: [PATCH 34/83] Translate Stubborn operation example --- translations/README-ru.md | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index f880219..cdf5133 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1990,3 +1990,50 @@ for i in x: * В Python 3.7.6 и выше при попытке запустить пример вызывается исключение `RuntimeError: dictionary keys changed during iteration`. --- + + +### ▶ Упрямая операция `del` + + + +```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__': , 'SomeClass': , '__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!" (наконец-то!). + +--- From 2aa7b375406ec86cea79199c8696f30ea8800f32 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 09:02:25 +0300 Subject: [PATCH 35/83] Translate The out of scope varibale example --- translations/README-ru.md | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index cdf5133..726b3ea 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2037,3 +2037,86 @@ Deleted! + Вызов `globals` (или вообще выполнение чего-либо, что будет иметь результат, отличный от `None`) заставил `_` сослаться на новый результат, отбросив существующую ссылку. Теперь количество ссылок достигло 0, и мы можем видеть, как выводится "Deleted!" (наконец-то!). --- + + +### ▶ Переменная за пределами видимости + + +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. + +--- From e8cd593e62dfd3002dda6500fba32763ef8b9d19 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:58:11 +0300 Subject: [PATCH 36/83] Translate Deleting list item while iterating over it example --- translations/README-ru.md | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 726b3ea..b102077 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2120,3 +2120,63 @@ UnboundLocalError: local variable 'a' referenced before assignment * Прочитайте [это](https://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html) короткое, но потрясающее руководство, чтобы узнать больше о том, как работают пространства имен и разрешение областей видимости в Python. --- + + +### ▶ Удаление элемента списка во время прохода по списку + +```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 + >>> id(some_list[:]) # Notice that python creates new object for sliced list. + 139798779601192 + ``` + +**Разница между `del`, `remove` и `pop`:** +* `del var_name` просто удаляет привязку `var_name` из локального или глобального пространства имен (поэтому `list_1` не затрагивается). +* `remove` удаляет первое подходящее значение, а не конкретный индекс, вызывает `ValueError`, если значение не найдено. +* `pop` удаляет элемент по определенному индексу и возвращает его, вызывает `IndexError`, если указан неверный индекс. + +**Почему на выходе получается `[2, 4]`? +- Проход по списку выполняется индекс за индексом, и когда мы удаляем `1` из `list_2` или `list_4`, содержимое списков становится `[2, 3, 4]`. Оставшиеся элементы сдвинуты вниз, то есть `2` находится на индексе 0, а `3` - на индексе 1. Поскольку на следующей итерации будет просматриваться индекс 1 (который и есть `3`), `2` будет пропущен полностью. Аналогичное произойдет с каждым альтернативным элементом в последовательности списка. + +* Объяснение примера можно найти на [StackOverflow](https://stackoverflow.com/questions/45946228/what-happens-when-you-try-to-delete-a-list-element-while-iterating-over-it). +* Также посмотрите на похожий пример на [StackOverflow](https://stackoverflow.com/questions/45877614/how-to-change-all-the-dictionary-keys-in-a-for-loop-with-d-items), связанный со словарями. + +--- From 3df9d0e4e322cafdeef3b1d94491046e7ad79603 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:07:40 +0300 Subject: [PATCH 37/83] Translate Lossy zip of iterators example --- translations/README-ru.md | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index b102077..d4928fe 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2180,3 +2180,53 @@ for idx, item in enumerate(list_4): * Также посмотрите на похожий пример на [StackOverflow](https://stackoverflow.com/questions/45877614/how-to-change-all-the-dictionary-keys-in-a-for-loop-with-d-items), связанный со словарями. --- + + +### ▶ Сжатие итераторов с потерями * + + +```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)] + ``` + Первый аргумент сжатия должен иметь наименьшее число элементов + +--- From 473e4229f249b9d0c08e9bb9f07c62f778e14dd5 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:23:47 +0300 Subject: [PATCH 38/83] Translate Loop variables leaking out example --- translations/README-ru.md | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index d4928fe..b78689d 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2230,3 +2230,68 @@ for idx, item in enumerate(list_4): Первый аргумент сжатия должен иметь наименьшее число элементов --- + + +### ▶ Утечка переменных внутри цикла + +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 +``` + +#### 💡 Объяснение: + +- В Python циклы for используют область видимости, в которой они существуют, и оставляют свою определенную переменную цикла после завершения. Это также относится к случаям, когда мы явно определили переменную цикла for в глобальном пространстве имен. В этом случае будет произведена перепривязка существующей переменной. + +- Различия в выводе интерпретаторов Python 2.x и Python 3.x для примера с пониманием списков можно объяснить следующим изменением, задокументированным в журнале изменений [What's New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html): + + > "Генераторы списков ("list comprehensions") больше не поддерживает синтаксическую форму `[... for var in item1, item2, ...]`. Вместо этого используйте `[... for var in (item1, item2, ...)]`. Кроме того, обратите внимание, что генераторы списков имеют другую семантику: они ближе к синтаксическому сахару для генераторного выражения внутри конструктора `list()`, и, в частности, управляющие переменные цикла больше не просачиваются в окружающую область видимости." + +--- From 7ce56da1d8d65f6339723e275fdd01249e4e836a Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:39:15 +0300 Subject: [PATCH 39/83] Translate Beware of default mutable arguments example --- translations/README-ru.md | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index b78689d..070cf6a 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2295,3 +2295,62 @@ print(x, ': x in global') > "Генераторы списков ("list comprehensions") больше не поддерживает синтаксическую форму `[... for var in item1, item2, ...]`. Вместо этого используйте `[... for var in (item1, item2, ...)]`. Кроме того, обратите внимание, что генераторы списков имеют другую семантику: они ближе к синтаксическому сахару для генераторного выражения внутри конструктора `list()`, и, в частности, управляющие переменные цикла больше не просачиваются в окружающую область видимости." --- + + +### ▶ Остерегайтесь изменяемых аргументов по умолчанию! + + +```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'] +``` + +#### 💡 Объяснение: + +- Изменяемые аргументы функций по умолчанию в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется недавно присвоенное им значение. Когда мы явно передали `[]` в `some_func в качестве аргумента, значение по умолчанию переменной `default_arg` не было использовано, поэтому функция вернулась, как и ожидалось. + + ```py + def some_func(default_arg=[]): + default_arg.append("some_string") + return default_arg + ``` + + **Результат:** + ```py + >>> some_func.__defaults__ # Выражение выведет значения стандартных аргументов фукнции + ([],) + >>> 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 + ``` + +--- From c2dd151ed551935145a395e83228c064f3a4d322 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:45:32 +0300 Subject: [PATCH 40/83] Translate Catching the Exceptions example --- translations/README-ru.md | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 070cf6a..135ddae 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2354,3 +2354,79 @@ def some_func(default_arg=[]): ``` --- + + +### ▶ Ловля исключений + +```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 "", 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 "", 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 + ``` + +--- From 40503d5ac55eea21e4a69c46f9f91bab58a1f8eb Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 12:02:54 +0300 Subject: [PATCH 41/83] Translate Same operands, different story example --- translations/README-ru.md | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 135ddae..b588ff7 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2430,3 +2430,46 @@ SyntaxError: invalid syntax ``` --- + + +### ▶ Одни и те же операнды, разная история! + +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` по-прежнему указывают на тот же самый список, который был изменен на месте. + +--- From a25fe26adc9b76e78ec4f2688f430da3d3da03b7 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 12:07:47 +0300 Subject: [PATCH 42/83] Translate Name resolution ignoring class scope example --- translations/README-ru.md | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index b588ff7..315e9e5 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2473,3 +2473,47 @@ a += [5, 6, 7, 8] * Выражение `a += [5,6,7,8]` фактически отображается на функцию "extend", которая работает со списком так, что `a` и `b` по-прежнему указывают на тот же самый список, который был изменен на месте. --- + + +### ▶ Разрешение имен игнорирует область видимости класса + +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 +``` + +#### 💡 Объяснение +- Области видимости, вложенные внутрь определения класса, игнорируют имена, связанные на уровне класса. +- Выражение-генератор имеет свою собственную область видимости. +- Начиная с версии Python 3.X, списковые вычисления также имеют свою собственную область видимости. + +--- From 0d28d47f0846aca77c1feea0ff3faa8f330e7dba Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 12:18:36 +0300 Subject: [PATCH 43/83] Translate Rounding like a banker example --- translations/README-ru.md | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 315e9e5..1f49565 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2517,3 +2517,55 @@ class SomeClass: - Начиная с версии Python 3.X, списковые вычисления также имеют свою собственную область видимости. --- + + +### ▶ Округляясь как банкир * + +Реализуем простейшую функцию по получению среднего элемента списка: +```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). + +--- From 2043112a9d8271a15cab21a040f1f7bd7bd7b016 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Tue, 23 Apr 2024 12:32:24 +0300 Subject: [PATCH 44/83] Translate Needles in a haystack example --- translations/README-ru.md | 176 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 1f49565..123b59e 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2569,3 +2569,179 @@ def get_middle(some_list): - Дополнительную информацию можно найти в [документации](https://docs.python.org/3/library/functions.html#round) функции `round` или на [StackOverflow](https://stackoverflow.com/questions/10825926/python-3-x-rounding-behavior). --- + + +### ▶ Иголки в стоге сена * + + + +Я не встречал ни одного питониста на данный момент, который не встречался с одним из следующих сценариев, + +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 +# assert выражение с сообщением об ошиб +>>> 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 "", line 1, in + AssertionError + + >>> assert (a == b, "Values are not equal") + :1: SyntaxWarning: assertion is always true, perhaps remove parentheses? + + >>> assert a == b, "Values are not equal" + Traceback (most recent call last): + File "", line 1, in + 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`) не является изменением значения. + +* Знание этих тонкостей может сэкономить вам часы отладки в долгосрочной перспективе. + +--- From bbb086a521d9a4c22f5fa97b32107c089cc8d938 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:27:46 +0300 Subject: [PATCH 45/83] Translate Splitsies example --- translations/README-ru.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 123b59e..ae55c30 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2745,3 +2745,40 @@ def similar_recursive_func(a): * Знание этих тонкостей может сэкономить вам часы отладки в долгосрочной перспективе. --- + + +### ▶ Сплиты (splitsies) * + +```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(' ') + [''] + ``` + +--- From 8f60bc1d0b38a52bd0c0b6add29d10db2cc728f9 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:35:57 +0300 Subject: [PATCH 46/83] Translate Wild imports example --- translations/README-ru.md | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index ae55c30..95cf37e 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2782,3 +2782,64 @@ def similar_recursive_func(a): ``` --- + + +### ▶ Подстановочное импортирование (wild imports) * + + + +```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 "", line 1, in +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 "", line 1, in + NameError: name 'some_weird_name_func_' is not defined + ``` + +--- From f84272fc5c054821043b7b02918f25a5bd465145 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:39:29 +0300 Subject: [PATCH 47/83] Translate All sorted? example --- translations/README-ru.md | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 95cf37e..750dc2e 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2843,3 +2843,45 @@ NameError: name '_another_weird_name_func' is not defined ``` --- + + +### ▶ Все ли отсортировано? * + + + +```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) + ``` + +- В отличие от метода `sorted, метод `reversed` возвращает итератор. Почему? Потому что сортировка требует, чтобы итератор либо изменялся на месте, либо использовал дополнительный контейнер (список), в то время как реверсирование может работать просто путем итерации от последнего индекса к первому. + +- Поэтому при сравнении `sorted(y) == sorted(y)` первый вызов `sorted()` будет потреблять итератор `y`, а следующий вызов просто вернет пустой список. + + ```py + >>> x = 7, 8, 9 + >>> y = reversed(x) + >>> sorted(y), sorted(y) + ([7, 8, 9], []) + ``` + +--- From 039adfa04ae4c2730a8c31942259978bdf2d5725 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:43:00 +0300 Subject: [PATCH 48/83] Translate Midnight time does not exist? example --- translations/README-ru.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 750dc2e..92c7cb9 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2885,3 +2885,37 @@ False ``` --- + + +### ▶ Полночи не существует? + +```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 или эквивалентом "пусто", возникает ошибка. + +--- +--- From 662b720b5ca0394b4004fa7ae230ef8eb1f9883c Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:47:58 +0300 Subject: [PATCH 49/83] Translate Okay Python, can you make me fly? example --- translations/README-ru.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 92c7cb9..2d87996 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2919,3 +2919,28 @@ if noon_time: --- --- + + + +## Секция: Скрытые сокровища! + +Секция содержит менее известные интересные нюансы работы Python, которые неизвестны большинству новичков. + +### ▶ Python, можешь ли ты помочь взлелеть? + +Что ж, поехали + +```py +import antigravity +``` + +**Результат:** +Sshh... It's a super-secret. + +#### 💡 Объяснение: + ++ Модуль `antigravity` - одно из немногих пасхальных яиц, выпущенных разработчиками Python. ++ `import antigravity` открывает веб-браузер, указывающий на [классический комикс XKCD](https://xkcd.com/353/) о Python. ++ Это еще не все. Внутри пасхального яйца находится **еще одно пасхальное яйцо**. Если вы посмотрите на [код](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), там определена функция, которая якобы реализует [алгоритм геохашинга XKCD](https://xkcd.com/426/). + +--- From 124b0f027df4b2e3fde7e10af823322f62b40050 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:58:51 +0300 Subject: [PATCH 50/83] Translate goto, but why? example --- translations/README-ru.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 2d87996..27e2585 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2944,3 +2944,33 @@ Sshh... It's a super-secret. + Это еще не все. Внутри пасхального яйца находится **еще одно пасхальное яйцо**. Если вы посмотрите на [код](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), там определена функция, которая якобы реализует [алгоритм геохашинга XKCD](https://xkcd.com/426/). --- + + +### ▶ `goto`, но почему? + + +```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. + +--- From 8ab55b73931edc8e16c430090fc387178fb1740e Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:02:09 +0300 Subject: [PATCH 51/83] Translate Brace yourself example --- translations/README-ru.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 27e2585..b75c6f0 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -2974,3 +2974,31 @@ Freedom! - Хотя он работает, но, пожалуйста, не используйте его. Вот [причина](https://docs.python.org/3/faq/design.html#why-is-there-no-goto) того, почему `goto` отсутствует в Python. --- + + +### ▶ Держитесь! + +Если вы относитесь к тем людям, которым не нравится использование пробелов в 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/025eb98dc0c1dc27404df6c544fc2944e0fa9f3a/Python/future.c#L49) в файле `future.c`. ++ Когда компилятор CPython встречает оператор [future](https://docs.python.org/3.3/reference/simple_stmts.html#future-statements), он сначала запускает соответствующий код в `future.c`, а затем рассматривает его как обычный оператор импорта. + +--- From e2d0be0e2adfa33e2504ed673442739dbfac08aa Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:09:26 +0300 Subject: [PATCH 52/83] Translate Meet Friendly Language Uncle For Life example --- translations/README-ru.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index b75c6f0..4cc91ba 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3002,3 +3002,37 @@ SyntaxError: not a chance + Когда компилятор CPython встречает оператор [future](https://docs.python.org/3.3/reference/simple_stmts.html#future-statements), он сначала запускает соответствующий код в `future.c`, а затем рассматривает его как обычный оператор импорта. --- + + +### ▶ Давайте познакомимся с дружелюбным Дядей Барри + +Непереводимая игра слов: 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"')) + ``` + +--- From 664bb038d42bbab9184d3e7fdfe371dfa83d80a0 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:12:47 +0300 Subject: [PATCH 53/83] Translate Even Python understands that love is complicated example --- translations/README-ru.md | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 4cc91ba..7106a5a 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3036,3 +3036,61 @@ True ``` --- + + +### ▶ Даже Python понимает, что любовь - это сложно. + +```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`). + +--- From 193c83916395713f3fe85ebbcb29f036a23b4603 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:17:37 +0300 Subject: [PATCH 54/83] Translate Yes, it exists example --- translations/README-ru.md | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 7106a5a..92fcdbb 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3094,3 +3094,50 @@ True * Что касается утверждения `любовь не является истиной или ложью; любовь - это любовь`, иронично, но описательно (если нет, пожалуйста, посмотрите примеры, связанные с операторами `is` и `is not`). --- + + +### ▶ Да, оно существует! + +**Ключевое слово `else` в связвке с циклом `for`.** Один из стандартных примеров: + +```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` означает, что блок попыток действительно успешно завершен. + +--- From be9c3bb0ae6e6bebe700bb01c6b6398fe4391782 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:24:34 +0300 Subject: [PATCH 55/83] Translate Ellipsis example --- translations/README-ru.md | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 92fcdbb..bf9ea26 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3141,3 +3141,64 @@ Try block executed successfully... - Блок `else` после блока `try` также называется "блоком завершения", поскольку достижение `else` в операторе `try` означает, что блок попыток действительно успешно завершен. --- + + +### ▶ Многоточие * + +```py +def some_func(): + Ellipsis +``` + +**Результат** +```py +>>> some_func() +# Ни вывода, ни ошибки + +>>> SomeRandomString +Traceback (most recent call last): + File "", line 1, in +NameError: name 'SomeRandomString' is not defined + +>>> Ellipsis +Ellipsis +``` + +#### 💡 Объяснение +- В Python, `Ellipsis` - глобальный встроенный объект, эквивалентный `...`. + ```py + >>> ... + Ellipsis + ``` +- Многоточие может использоваться в нескольких случаях, + + В качестве заполнителя для кода, который еще не написан (аналогично оператору `pass`) + + В синтаксисе срезов (slices) для представления полных срезов в оставшемся направлении + ``py + >>> 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`, чтобы обойти все предыдущие измерения + ``py + >>> 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]`) + + В [подсказках типов](https://docs.python.org/3/library/typing.html) для указания только части типа (например, `(Callable[..., int]` или `Tuple[str, ...]`)) + + Вы также можете использовать `Ellipsis` в качестве аргумента функции по умолчанию (в случаях, когда вы хотите провести различие между сценариями "аргумент не передан" и "значение не передано"). + +--- From 3b9d9bdcd10a5f07b1035c7dd587cc1608c9c67c Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:29:06 +0300 Subject: [PATCH 56/83] Translate Inpinity example --- translations/README-ru.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index bf9ea26..a0ee30f 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3189,7 +3189,7 @@ Ellipsis ]) ``` Таким образом, наш `трехмерный_массив` представляет собой массив массивов массивов. Допустим, мы хотим вывести второй элемент (индекс `1`) всех внутренних массивов, мы можем использовать `Ellipsis`, чтобы обойти все предыдущие измерения - ``py + ```py >>> three_dimensional_array[:,::,1] array([[1, 3], [5, 7]]) @@ -3202,3 +3202,23 @@ Ellipsis + Вы также можете использовать `Ellipsis` в качестве аргумента функции по умолчанию (в случаях, когда вы хотите провести различие между сценариями "аргумент не передан" и "значение не передано"). --- + + +### ▶ Писконечность (Inpinity) + +В заголовке нет ошибки, так и задумано, пожалуйста, не создавайте 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". + +--- From b5c20d02ea1b55316864dfe011fd4afc86ccf69b Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:39:50 +0300 Subject: [PATCH 57/83] Translate Name mangling example --- translations/README-ru.md | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index a0ee30f..9eb5ed4 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3222,3 +3222,80 @@ Ellipsis - Интересно, что хэш `float('-inf')` - "-10⁵ x π" в Python 3, тогда как в Python 2 - "-10⁵ x e". --- + + +### ▶ Давайте искажать + +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 "", line 1, in +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 "", line 1, in +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). + +--- +--- From a5f12582753a0ae9a64137f93f877faa6de490a5 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:47:58 +0300 Subject: [PATCH 58/83] Translate Skipping lines? example --- translations/README-ru.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 9eb5ed4..c8af1b4 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3299,3 +3299,41 @@ AttributeError: 'A' object has no attribute '__variable' --- --- + +## Секция: Внешность обманчива! + +### ▶ Пропускаем строки? + +**Результат:** +```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' оправдывают поведение приведенного выше примера. + +--- From eab5d5968e1e01b429e6d16a4327428ec588742b Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:52:39 +0300 Subject: [PATCH 59/83] Translate Teleportation example --- translations/README-ru.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index c8af1b4..507222f 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3337,3 +3337,37 @@ false Встроенная функция `ord()` возвращает юникод [кодовую точку символа](https://en.wikipedia.org/wiki/code_point), и разные кодовые позиции кириллического 'e' и латинского 'e' оправдывают поведение приведенного выше примера. --- + + +### ▶ Телепортация + + + +```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()` возвращает следующий свободный участок памяти без его повторной инициализации. Этот участок памяти просто оказывается тем же самым, который был только что освобожден (обычно, но не всегда). + +--- From 551b251c054587547c0a9324506558e80e0f776d Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:02:55 +0300 Subject: [PATCH 60/83] Translate Well, something is fishy example --- translations/README-ru.md | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 507222f..b17447a 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3371,3 +3371,45 @@ def energy_receive(): * `numpy.empty()` возвращает следующий свободный участок памяти без его повторной инициализации. Этот участок памяти просто оказывается тем же самым, который был только что освобожден (обычно, но не всегда). --- + + +### ▶ Что-то не так... + +```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 + ``` + +--- +--- From ebe5f59a9dca2b771898f06f8cf823fc8740464a Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:06:24 +0300 Subject: [PATCH 61/83] Translate += is faster example --- translations/README-ru.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index b17447a..032fef9 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3413,3 +3413,23 @@ def square(x): --- --- + +## Секция: Разное + + +### ▶ `+=` быстрее + + +```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 +``` + +#### 💡 Объяснение: ++ Операнд `+=` быстре `+` для "сложения" 2 и более строк, так как первая строка (например, `s1` for `s1 += s2 + s3`) не уничтожается во время формирования финальной строки. + +--- From 00e420fc516cd4c29a248cbeae5681fb92e6cac3 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:16:10 +0300 Subject: [PATCH 62/83] Translate Let's make a giant string! example --- translations/README-ru.md | 99 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index 032fef9..bb7a1ea 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3430,6 +3430,103 @@ def square(x): ``` #### 💡 Объяснение: -+ Операнд `+=` быстре `+` для "сложения" 2 и более строк, так как первая строка (например, `s1` for `s1 += s2 + s3`) не уничтожается во время формирования финальной строки. ++ Операнд `+=` быстрее `+` для "сложения" 2 и более строк, так как первая строка (например, `s1` for `s1 += s2 + s3`) не уничтожается во время формирования финальной строки. + +--- + + +### ▶ Сделаем гигантскую строку! + +```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) + >>> %timeit -n100 add_string_with_plus(10000) # Quadratic increase in execution time + 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/), согласно которому, + + > должен быть один - и желательно только один - очевидный способ сделать это. --- From 4b4951d7558dd3e76d841c747a19a9a7edd6ecdc Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:21:51 +0300 Subject: [PATCH 63/83] Translate Slowing down dict lookups example --- translations/README-ru.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index bb7a1ea..570c8b4 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3530,3 +3530,39 @@ def convert_list_to_string(l, iters): > должен быть один - и желательно только один - очевидный способ сделать это. --- + + +### ▶ Замедляем поиск по `dict` * + +```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 "", line 1, in +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`-ключей. ++ Специализированная функция (названная `lookdict_unicode` в [исходный код CPython](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841)) знает, что все существующие ключи (включая искомый ключ) являются строками, и использует более быстрое и простое сравнение строк для сравнения ключей, вместо вызова метода `__eq__`. ++ При первом обращении к экземпляру `dict` с ключом, не являющимся `str`, он модифицируется, чтобы в дальнейшем для поиска использовалась общая функция. ++ Этот процесс не обратим для конкретного экземпляра `dict`, и ключ даже не обязательно должен существовать в словаре. Поэтому попытка неудачного поиска имеет тот же эффект. + +--- From 9e2508ae6a95e61a2d924bbb61951aef4311307f Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:28:57 +0300 Subject: [PATCH 64/83] Translate Bloating instance dict's example --- translations/README-ru.md | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 570c8b4..5894073 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3566,3 +3566,67 @@ KeyError: 1 + Этот процесс не обратим для конкретного экземпляра `dict`, и ключ даже не обязательно должен существовать в словаре. Поэтому попытка неудачного поиска имеет тот же эффект. --- + + +### ▶ Раздуваем экземпляры словарей * + +```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__`! + +--- From f71b997a450c69e97916f0c49b0b68a740161048 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Wed, 24 Apr 2024 17:00:05 +0300 Subject: [PATCH 65/83] Translate Minor ones example --- translations/README-ru.md | 141 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 5894073..3e2f571 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3630,3 +3630,144 @@ def dict_size(o): + Небольшой совет, если вы стремитесь уменьшить занимаемый программой объем памяти: не удаляйте атрибуты экземпляров и обязательно инициализируйте все атрибуты в `__init__`! --- + + +### ▶ Минорное * + +* `join()` - строковая операция вместо списочной. (может показаться неочевидным при первом использовании) + + **💡 Объяснение:** Если `join()` - это строковый метод, то он может работать с любым итеруемыми объектами (список, кортеж, итераторы). Если бы это был списковый метод, то его пришлось бы реализовывать отдельно для каждого типа. Кроме того, нет особого смысла помещать метод, специфичный для строки, в общий API объекта `list`. + +* Несколько странных, но семантически правильных утверждений: + + `[] = ()` - семантически корректное утверждение (распаковка пустого `кортежа` в пустой `список`) + + `'a'[0][0][0][0][0]` также является семантически корректным утверждением, поскольку в Python строки являются [последовательностями](https://docs.python.org/3/glossary.html#term-sequence)(итерируемыми объектами, поддерживающими доступ к элементам с использованием целочисленных индексов). + + `3 --0-- 5 == 8` и `--5 == 5` - оба семантически корректные утверждения и имеют значение `True`. + +* Учитывая, что `a` - это число, `++a` и `--a` являются корректными утверждениями Python, но ведут себя не так, как аналогичные утверждения в таких языках, как C, C++ или Java. + ```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 в исходной строке. + +--- +--- From 05ad6cf2af4afa2e359a6a378faf5727bd082045 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:00:05 +0300 Subject: [PATCH 66/83] Translate Contributing example --- translations/README-ru.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 3e2f571..389de55 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3771,3 +3771,17 @@ def dict_size(o): --- --- + +# Вклад в проект + +Как можно внести свой вклад в развитие wtfpython, + +- Предложить новые примеры +- Помочь в переводе (См. [issues labeled translation](https://github.com/satwikkansal/wtfpython/issues?q=is%3Aissue+is%3Aopen+label%3Atranslation)) +- Мелкие исправления, такие как указание на устаревшие фрагменты, опечатки, ошибки форматирования и т.д. +- Выявление пробелов (таких как недостаточное объяснение, избыточные примеры и т. д.) +- Любые творческие предложения, чтобы сделать этот проект более интересным и полезным. + +Пожалуйста, смотрите [CONTRIBUTING.md](/CONTRIBUTING.md) для более подробной информации. Не стесняйтесь создать новый [issue](https://github.com/satwikkansal/wtfpython/issues/new) для обсуждения. + +PS: Пожалуйста, не обращайтесь к нам с просьбами об обратной ссылке, ссылки не будут добавлены, если они не имеют отношения к проекту. From d7d7e970d715b3ef7cc84f7bda6d7bcf3f1bd373 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:04:25 +0300 Subject: [PATCH 67/83] Translate Aknowledgements and links example --- translations/README-ru.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 389de55..4e48efa 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3785,3 +3785,19 @@ def dict_size(o): Пожалуйста, смотрите [CONTRIBUTING.md](/CONTRIBUTING.md) для более подробной информации. Не стесняйтесь создать новый [issue](https://github.com/satwikkansal/wtfpython/issues/new) для обсуждения. PS: Пожалуйста, не обращайтесь к нам с просьбами об обратной ссылке, ссылки не будут добавлены, если они не имеют отношения к проекту. + +# Благодарности + +Идея и дизайн этой коллекции были изначально вдохновлены потрясающим проектом Дениса Дована [wtfjs](https://github.com/denysdovhan/wtfjs). Подавляющая поддержка со стороны питонистов придала проекту ту форму, в которой он находится сейчас. + +#### Несколько хороших ссылок! +* https://www.youtube.com/watch?v=sH4XF6pKKmk +* https://www.reddit.com/r/Python/comments/3cu6ej/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/). From f0afccc347ff1eaa9f75dd20cdbaa6b3c6f0ff87 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:08:22 +0300 Subject: [PATCH 68/83] Translate License and remaining info example --- translations/README-ru.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/translations/README-ru.md b/translations/README-ru.md index 4e48efa..c986982 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -3801,3 +3801,24 @@ PS: Пожалуйста, не обращайтесь к нам с просьб * 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/). + +# 🎓 Лицензия + +[![WTFPL 2.0][license-image]][license-url] + +© [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%20you%20really%20think%20you%20know%20Python,%20think%20once%20more!%20Check%20out%20wtfpython&hashtags=python,wtfpython) | [Linkedin](https://www.linkedin.com/shareArticle?url=https://github.com/satwikkansal&title=What%20the%20f*ck%20Python!&summary=If%20you%20really%20thing%20you%20know%20Python,%20think%20once%20more!) | [Facebook](https://www.facebook.com/dialog/share?app_id=536779657179021&display=page&href=https%3A%2F%2Fgithub.com%2Fsatwikkansal%2Fwtfpython"e=If%20you%20really%20think%20you%20know%20Python%2C%20think%20once%20more!) + +### Нужна PDF версия? + +Я получил несколько запросов на pdf (и epub) версию wtfpython. Вы можете добавить свои данные [здесь](https://form.jotform.com/221593245656057), чтобы получить их, как только они будут готовы. + +**Вот и все, друзья!** Для получения новых материалов, подобных этому, вы можете добавить свой email [сюда](https://form.jotform.com/221593598380062). From 2c623dd33a8865e00be7261bb27a191df2e67d59 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:12:29 +0300 Subject: [PATCH 69/83] Actualize Table of contents --- translations/README-ru.md | 86 ++++++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index c986982..2f30ae0 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -17,16 +17,82 @@ PS: Если вы уже читали **wtfpython** раньше, с измен Ну что ж, приступим... # Содержание - -- [Содержание](#содержание) -- [Структура примера](#структура-примера) -- [Применение](#применение) -- [👀 Примеры](#-примеры) - - [Секция: Напряги мозги!](#секция-напряги-мозги) - - [▶ Первым делом!](#-первым-делом) - - [💡 Обьяснение](#-обьяснение) - - [▶ Строки иногда ведут себя непредсказуемо](#-строки-иногда-ведут-себя-непредсказуемо) - - [💡 Объяснение](#-объяснение) +* [Содержание](#Содержание) +* [Структура примера](#Структура-примера) +* [Применение](#Применение) +* [👀 Примеры](#👀-Примеры) + * [Секция: Напряги мозги!](#Секция:-Напряги-мозги!) + * [▶ Первым делом!](#▶-Первым-делом!) + * [▶ Строки иногда ведут себя непредсказуемо](#▶-Строки-иногда-ведут-себя-непредсказуемо) + * [▶ Осторожнее с цепочкой операций](#▶-Осторожнее-с-цепочкой-операций) + * [▶ Как не надо использовать оператор `is`](#▶-Как-не-надо-использовать-оператор-`is`) + * [▶ Мистическое хэширование](#▶-Мистическое-хэширование) + * [▶ В глубине души мы все одинаковы.](#▶-В-глубине-души-мы-все-одинаковы.) + * [▶ Беспорядок внутри порядка *](#▶-Беспорядок-внутри-порядка--*) + * [▶ Продолжай пытаться... *](#▶-Продолжай-пытаться...-*) + * [▶ Для чего?](#▶-Для-чего?) + * [▶ Расхождение во времени исполнения](#▶-Расхождение-во-времени-исполнения) + * [▶ `is not ...` не является `is (not ...)`](#▶-`is-not-...`-не-является-`is-(not-...)`) + * [▶ Крестики-нолики, где X побеждает с первой попытки!](#▶-Крестики-нолики,-где-X-побеждает-с-первой-попытки!) + * [▶ Переменная Шредингера *](#▶-Переменная-Шредингера-*) + * [▶ Проблема курицы и яйца *](#▶-Проблема-курицы-и-яйца-*) + * [▶ Отношения между подклассами](#▶-Отношения-между-подклассами) + * [▶ Равенство и тождество методов](#▶-Равенство-и-тождество-методов) + * [▶ All-true-ation (непереводимая игра слов) *](#▶-All-true-ation-(непереводимая-игра-слов)-*) + * [▶ Неожиданная запятая](#▶-Неожиданная-запятая) + * [▶ Строки и обратные слэши](#▶-Строки-и-обратные-слэши) + * [▶ Не узел! (eng. not knot!)](#▶-Не-узел!-(eng.-not-knot!)) + * [▶ Строки наполовину в тройных кавычках](#▶-Строки-наполовину-в-тройных-кавычках) + * [▶ Что не так с логическими значениями?](#▶-Что-не-так-с-логическими-значениями?) + * [▶ Атрибуты класса и экземпляра](#▶-Атрибуты-класса-и-экземпляра) + * [▶ Возврат None из генератора](#▶-Возврат-None-из-генератора) + * [▶ Yield from возвращает... *](#▶-Yield-from-возвращает...-*) + * [▶ Nan-рефлексивность *](#▶-Nan-рефлексивность-*) + * [▶ Мутируем немутируемое!](#▶-Мутируем-немутируемое!) + * [▶ Исчезающая переменная из внешней области видимости](#▶-Исчезающая-переменная-из-внешней-области-видимости) + * [▶ Превышение предела целочисленного преобразования строк](#▶-Превышение-предела-целочисленного-преобразования-строк) + * [Секция: Скользкие склоны](#Секция:-Скользкие-склоны) + * [▶ Изменение словаря во время прохода по нему](#▶-Изменение-словаря-во-время-прохода-по-нему) + * [▶ Упрямая операция `del`](#▶-Упрямая-операция-`del`) + * [▶ Переменная за пределами видимости](#▶-Переменная-за-пределами-видимости) + * [▶ Удаление элемента списка во время прохода по списку](#▶-Удаление-элемента-списка-во-время-прохода-по-списку) + * [▶ Сжатие итераторов с потерями *](#▶-Сжатие-итераторов-с-потерями-*) + * [▶ Утечка переменных внутри цикла](#▶-Утечка-переменных-внутри-цикла) + * [▶ Остерегайтесь изменяемых аргументов по умолчанию!](#▶-Остерегайтесь-изменяемых-аргументов-по-умолчанию!) + * [▶ Ловля исключений](#▶-Ловля-исключений) + * [▶ Одни и те же операнды, разная история!](#▶-Одни-и-те-же-операнды,-разная-история!) + * [▶ Разрешение имен игнорирует область видимости класса](#▶-Разрешение-имен-игнорирует-область-видимости-класса) + * [▶ Округляясь как банкир *](#▶-Округляясь-как-банкир-*) + * [▶ Иголки в стоге сена *](#▶-Иголки-в-стоге-сена-*) + * [▶ Сплиты (splitsies) *](#▶-Сплиты-(splitsies)-*) + * [▶ Подстановочное импортирование (wild imports) *](#▶-Подстановочное-импортирование-(wild-imports)-*) + * [▶ Все ли отсортировано? *](#▶-Все-ли-отсортировано?-*) + * [▶ Полночи не существует?](#▶-Полночи-не-существует?) + * [Секция: Скрытые сокровища!](#Секция:-Скрытые-сокровища!) + * [▶ Python, можешь ли ты помочь взлелеть?](#▶-Python,-можешь-ли-ты-помочь-взлелеть?) + * [▶ `goto`, но почему?](#▶-`goto`,-но-почему?) + * [▶ Держитесь!](#▶-Держитесь!) + * [▶ Давайте познакомимся с дружелюбным Дядей Барри](#▶-Давайте-познакомимся-с-дружелюбным-Дядей-Барри) + * [▶ Даже Python понимает, что любовь - это сложно.](#▶-Даже-Python-понимает,-что-любовь---это-сложно.) + * [▶ Да, оно существует!](#▶-Да,-оно-существует!) + * [▶ Многоточие *](#▶-Многоточие-*) + * [▶ Писконечность (Inpinity)](#▶-Писконечность-(Inpinity)) + * [▶ Давайте искажать](#▶-Давайте-искажать) + * [Секция: Внешность обманчива!](#Секция:-Внешность-обманчива!) + * [▶ Пропускаем строки?](#▶-Пропускаем-строки?) + * [▶ Телепортация](#▶-Телепортация) + * [▶ Что-то не так...](#▶-Что-то-не-так...) + * [Секция: Разное](#Секция:-Разное) + * [▶ `+=` быстрее](#▶-`+=`-быстрее) + * [▶ Сделаем гигантскую строку!](#▶-Сделаем-гигантскую-строку!) + * [▶ Замедляем поиск по `dict` *](#▶-Замедляем-поиск-по-`dict`-*) + * [▶ Раздуваем экземпляры словарей *](#▶-Раздуваем-экземпляры-словарей-*) + * [▶ Минорное *](#▶-Минорное-*) +* [Вклад в проект](#Вклад-в-проект) +* [Благодарности](#Благодарности) +* [🎓 Лицензия](#🎓-Лицензия) + * [Удиви своих друзей!](#Удиви-своих-друзей!) + * [Нужна PDF версия?](#Нужна-PDF-версия?) # Структура примера From 5bbdcdd5a505880c22c55f28860276f6eeab6a65 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 26 Apr 2024 10:44:11 +0300 Subject: [PATCH 70/83] Translate CONTRIBUTORS, fix Markdown table syntax --- CONTRIBUTORS.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ca0e88a..8a22a49 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,6 +1,6 @@ -Following are the wonderful people (in no specific order) who have contributed their examples to wtfpython. +Ниже перечислены (без определенного порядка) замечательные люди, которые внесли вклад в развитие wtfpython. -| Contributor | Github | Issues | +| Автор | Github | Issues | |-------------|--------|--------| | Lucas-C | [Lucas-C](https://github.com/Lucas-C) | [#36](https://github.com/satwikkansal/wtfpython/issues/36) | | MittalAshok | [MittalAshok](https://github.com/MittalAshok) | [#23](https://github.com/satwikkansal/wtfpython/issues/23) | @@ -18,25 +18,25 @@ Following are the wonderful people (in no specific order) who have contributed t | leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [#112](https://github.com/satwikkansal/wtfpython/issues/112) | | mishaturnbull | [mishaturnbull](https://github.com/mishaturnbull) | [#108](https://github.com/satwikkansal/wtfpython/issues/108) | | MuseBoy | [MuseBoy](https://github.com/MuseBoy) | [#101](https://github.com/satwikkansal/wtfpython/issues/101) | -| Ghost account | N/A | [#96](https://github.com/satwikkansal/wtfpython/issues/96) +| Ghost account | N/A | [#96](https://github.com/satwikkansal/wtfpython/issues/96) | | koddo | [koddo](https://github.com/koddo) | [#80](https://github.com/satwikkansal/wtfpython/issues/80), [#73](https://github.com/satwikkansal/wtfpython/issues/73) | | jab | [jab](https://github.com/jab) | [#77](https://github.com/satwikkansal/wtfpython/issues/77) | | Jongy | [Jongy](https://github.com/Jongy) | [#208](https://github.com/satwikkansal/wtfpython/issues/208), [#210](https://github.com/satwikkansal/wtfpython/issues/210), [#233](https://github.com/satwikkansal/wtfpython/issues/233) | | Diptangsu Goswami | [diptangsu](https://github.com/diptangsu) | [#193](https://github.com/satwikkansal/wtfpython/issues/193) | -| Charles | [charles-l](https://github.com/charles-l) | [#245](https://github.com/satwikkansal/wtfpython/issues/245) -| LiquidFun | [LiquidFun](https://github.com/LiquidFun) | [#267](https://github.com/satwikkansal/wtfpython/issues/267) +| Charles | [charles-l](https://github.com/charles-l) | [#245](https://github.com/satwikkansal/wtfpython/issues/245) | +| LiquidFun | [LiquidFun](https://github.com/LiquidFun) | [#267](https://github.com/satwikkansal/wtfpython/issues/267) | --- -**Translations** +**Переводчики** -| Translator | Github | Language | +| Переводчик | Github | Язык | |-------------|--------|--------| | leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [Chinese](https://github.com/leisurelicht/wtfpython-cn) | | vuduclyunitn | [vuduclyunitn](https://github.com/vuduclyunitn) | [Vietnamese](https://github.com/vuduclyunitn/wtfptyhon-vi) | | José De Freitas | [JoseDeFreitas](https://github.com/JoseDeFreitas) | [Spanish](https://github.com/JoseDeFreitas/wtfpython-es) | +| Vadim Nifadev | [nifadyev](https://github.com/nifadyev) | [Russian](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) | +Спасибо всем за ваше время и за то, что делаете wtfpython еще более потрясающим! :smile: -Thank you all for your time and making wtfpython more awesome! :smile: - -PS: This list is updated after every major release, if I forgot to add your contribution here, please feel free to raise a Pull request. +PS: Этот список обновляется после каждого крупного релиза, если я забыл добавить сюда ваш вклад, пожалуйста, не стесняйтесь сделать Pull request. From d0dd3ad2b7f5ccf73aeb9aba2d2f570f5cfff218 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 27 Apr 2024 12:21:12 +0300 Subject: [PATCH 71/83] Fix typos and spelling --- translations/README-ru.md | 392 ++++++++++++++++++++++---------------- 1 file changed, 226 insertions(+), 166 deletions(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index 2f30ae0..9cde024 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1,98 +1,163 @@

What the f*ck Python! 😱

-

Изучение и понимание Python с помощью нестандартного поведения и "магического" поведения.

+

Изучение и понимание Python с помощью удивительных примеров поведения.

-Переводы: [English Original](https://github.com/satwikkansal/wtfpython) [Chinese 中文](https://github.com/robertparley/wtfpython-cn) | [Vietnamese Tiếng Việt](https://github.com/vuduclyunitn/wtfptyhon-vi) | [Spanish Español](https://web.archive.org/web/20220511161045/https://github.com/JoseDeFreitas/wtfpython-es) | [Korean 한국어](https://github.com/buttercrab/wtfpython-ko) | [Russian Русский](https://github.com/nifadyev/wtfpython/tree/main/translations/README-ru.md) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) +Переводы: [English Original](https://github.com/satwikkansal/wtfpython) [Chinese 中文](https://github.com/robertparley/wtfpython-cn) | [Vietnamese Tiếng Việt](https://github.com/vuduclyunitn/wtfptyhon-vi) | [Spanish Español](https://web.archive.org/web/20220511161045/https://github.com/JoseDeFreitas/wtfpython-es) | [Korean 한국어](https://github.com/buttercrab/wtfpython-ko) | [Russian Русский](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) Альтернативные способы: [Интерактивный сайт](https://wtfpython-interactive.vercel.app) | [Интерактивный Jupiter notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) -Python, будучи прекрасно спроектированным высокоуровневым языком программирования, предоставляет множество возможностей для удобства программиста. Но иногда результаты работы Python кода могут показаться неочевидными на первый взгляд. +Python, будучи прекрасно спроектированным высокоуровневым языком программирования, предоставляет множество возможностей для удобства программиста. Но иногда поведение Python кода могут показаться запутывающим на первый взгляд. -**wtfpython** задуман как проект, пытающийся объяснить, что именно происходит под капотом некоторых неочевидных фрагментов кода и менее известных возможностей Python. +**wtfpython** задуман как проект, пытающийся объяснить, что именно происходит под капотом неочевидных фрагментов кода и малоизвестных возможностей Python. -Если вы опытный программист на Python, вы можете принять это как вызов и правильно объяснить WTF ситуации с первой попытки. Возможно, вы уже сталкивались с некоторыми из них раньше, и я смогу оживить ваши старые добрые воспоминания! 😅 +Если вы опытный питонист, вы можете принять это как вызов и правильно объяснить WTF ситуации с первой попытки. Возможно, вы уже сталкивались с некоторыми из них раньше, и я смогу оживить ваши старые добрые воспоминания! 😅 PS: Если вы уже читали **wtfpython** раньше, с изменениями можно ознакомиться [здесь](https://github.com/satwikkansal/wtfpython/releases/) (примеры, отмеченные звездочкой - это примеры, добавленные в последней основной редакции). Ну что ж, приступим... # Содержание -* [Содержание](#Содержание) -* [Структура примера](#Структура-примера) -* [Применение](#Применение) -* [👀 Примеры](#👀-Примеры) - * [Секция: Напряги мозги!](#Секция:-Напряги-мозги!) - * [▶ Первым делом!](#▶-Первым-делом!) - * [▶ Строки иногда ведут себя непредсказуемо](#▶-Строки-иногда-ведут-себя-непредсказуемо) - * [▶ Осторожнее с цепочкой операций](#▶-Осторожнее-с-цепочкой-операций) - * [▶ Как не надо использовать оператор `is`](#▶-Как-не-надо-использовать-оператор-`is`) - * [▶ Мистическое хэширование](#▶-Мистическое-хэширование) - * [▶ В глубине души мы все одинаковы.](#▶-В-глубине-души-мы-все-одинаковы.) - * [▶ Беспорядок внутри порядка *](#▶-Беспорядок-внутри-порядка--*) - * [▶ Продолжай пытаться... *](#▶-Продолжай-пытаться...-*) - * [▶ Для чего?](#▶-Для-чего?) - * [▶ Расхождение во времени исполнения](#▶-Расхождение-во-времени-исполнения) - * [▶ `is not ...` не является `is (not ...)`](#▶-`is-not-...`-не-является-`is-(not-...)`) - * [▶ Крестики-нолики, где X побеждает с первой попытки!](#▶-Крестики-нолики,-где-X-побеждает-с-первой-попытки!) - * [▶ Переменная Шредингера *](#▶-Переменная-Шредингера-*) - * [▶ Проблема курицы и яйца *](#▶-Проблема-курицы-и-яйца-*) - * [▶ Отношения между подклассами](#▶-Отношения-между-подклассами) - * [▶ Равенство и тождество методов](#▶-Равенство-и-тождество-методов) - * [▶ All-true-ation (непереводимая игра слов) *](#▶-All-true-ation-(непереводимая-игра-слов)-*) - * [▶ Неожиданная запятая](#▶-Неожиданная-запятая) - * [▶ Строки и обратные слэши](#▶-Строки-и-обратные-слэши) - * [▶ Не узел! (eng. not knot!)](#▶-Не-узел!-(eng.-not-knot!)) - * [▶ Строки наполовину в тройных кавычках](#▶-Строки-наполовину-в-тройных-кавычках) - * [▶ Что не так с логическими значениями?](#▶-Что-не-так-с-логическими-значениями?) - * [▶ Атрибуты класса и экземпляра](#▶-Атрибуты-класса-и-экземпляра) - * [▶ Возврат None из генератора](#▶-Возврат-None-из-генератора) - * [▶ Yield from возвращает... *](#▶-Yield-from-возвращает...-*) - * [▶ Nan-рефлексивность *](#▶-Nan-рефлексивность-*) - * [▶ Мутируем немутируемое!](#▶-Мутируем-немутируемое!) - * [▶ Исчезающая переменная из внешней области видимости](#▶-Исчезающая-переменная-из-внешней-области-видимости) - * [▶ Превышение предела целочисленного преобразования строк](#▶-Превышение-предела-целочисленного-преобразования-строк) - * [Секция: Скользкие склоны](#Секция:-Скользкие-склоны) - * [▶ Изменение словаря во время прохода по нему](#▶-Изменение-словаря-во-время-прохода-по-нему) - * [▶ Упрямая операция `del`](#▶-Упрямая-операция-`del`) - * [▶ Переменная за пределами видимости](#▶-Переменная-за-пределами-видимости) - * [▶ Удаление элемента списка во время прохода по списку](#▶-Удаление-элемента-списка-во-время-прохода-по-списку) - * [▶ Сжатие итераторов с потерями *](#▶-Сжатие-итераторов-с-потерями-*) - * [▶ Утечка переменных внутри цикла](#▶-Утечка-переменных-внутри-цикла) - * [▶ Остерегайтесь изменяемых аргументов по умолчанию!](#▶-Остерегайтесь-изменяемых-аргументов-по-умолчанию!) - * [▶ Ловля исключений](#▶-Ловля-исключений) - * [▶ Одни и те же операнды, разная история!](#▶-Одни-и-те-же-операнды,-разная-история!) - * [▶ Разрешение имен игнорирует область видимости класса](#▶-Разрешение-имен-игнорирует-область-видимости-класса) - * [▶ Округляясь как банкир *](#▶-Округляясь-как-банкир-*) - * [▶ Иголки в стоге сена *](#▶-Иголки-в-стоге-сена-*) - * [▶ Сплиты (splitsies) *](#▶-Сплиты-(splitsies)-*) - * [▶ Подстановочное импортирование (wild imports) *](#▶-Подстановочное-импортирование-(wild-imports)-*) - * [▶ Все ли отсортировано? *](#▶-Все-ли-отсортировано?-*) - * [▶ Полночи не существует?](#▶-Полночи-не-существует?) - * [Секция: Скрытые сокровища!](#Секция:-Скрытые-сокровища!) - * [▶ Python, можешь ли ты помочь взлелеть?](#▶-Python,-можешь-ли-ты-помочь-взлелеть?) - * [▶ `goto`, но почему?](#▶-`goto`,-но-почему?) - * [▶ Держитесь!](#▶-Держитесь!) - * [▶ Давайте познакомимся с дружелюбным Дядей Барри](#▶-Давайте-познакомимся-с-дружелюбным-Дядей-Барри) - * [▶ Даже Python понимает, что любовь - это сложно.](#▶-Даже-Python-понимает,-что-любовь---это-сложно.) - * [▶ Да, оно существует!](#▶-Да,-оно-существует!) - * [▶ Многоточие *](#▶-Многоточие-*) - * [▶ Писконечность (Inpinity)](#▶-Писконечность-(Inpinity)) - * [▶ Давайте искажать](#▶-Давайте-искажать) - * [Секция: Внешность обманчива!](#Секция:-Внешность-обманчива!) - * [▶ Пропускаем строки?](#▶-Пропускаем-строки?) - * [▶ Телепортация](#▶-Телепортация) - * [▶ Что-то не так...](#▶-Что-то-не-так...) - * [Секция: Разное](#Секция:-Разное) - * [▶ `+=` быстрее](#▶-`+=`-быстрее) - * [▶ Сделаем гигантскую строку!](#▶-Сделаем-гигантскую-строку!) - * [▶ Замедляем поиск по `dict` *](#▶-Замедляем-поиск-по-`dict`-*) - * [▶ Раздуваем экземпляры словарей *](#▶-Раздуваем-экземпляры-словарей-*) - * [▶ Минорное *](#▶-Минорное-*) -* [Вклад в проект](#Вклад-в-проект) -* [Благодарности](#Благодарности) -* [🎓 Лицензия](#🎓-Лицензия) - * [Удиви своих друзей!](#Удиви-своих-друзей!) - * [Нужна PDF версия?](#Нужна-PDF-версия?) +- [Содержание](#содержание) +- [Структура примера](#структура-примера) +- [Применение](#применение) +- [👀 Примеры](#-примеры) + - [Секция: Напряги мозги!](#секция-напряги-мозги) + - [▶ Первым делом!](#-первым-делом) + - [💡 Обьяснение](#-обьяснение) + - [▶ Строки иногда ведут себя непредсказуемо](#-строки-иногда-ведут-себя-непредсказуемо) + - [💡 Объяснение](#-объяснение) + - [▶ Осторожнее с цепочкой операций](#-осторожнее-с-цепочкой-операций) + - [💡 Объяснение:](#-объяснение-1) + - [▶ Как не надо использовать оператор `is`](#-как-не-надо-использовать-оператор-is) + - [💡 Объяснение:](#-объяснение-2) + - [▶ Мистическое хеширование](#-мистическое-хеширование) + - [💡 Объяснение](#-объяснение-3) + - [▶ В глубине души мы все одинаковы.](#-в-глубине-души-мы-все-одинаковы) + - [💡 Объяснение:](#-объяснение-4) + - [▶ Беспорядок внутри порядка \*](#-беспорядок-внутри-порядка-) + - [💡 Объяснение:](#-объяснение-5) + - [▶ Продолжай пытаться... \*](#-продолжай-пытаться-) + - [💡 Объяснение:](#-объяснение-6) + - [▶ Для чего?](#-для-чего) + - [💡 Объяснение:](#-объяснение-7) + - [▶ Расхождение во времени исполнения](#-расхождение-во-времени-исполнения) + - [💡 Объяснение](#-объяснение-8) + - [▶ `is not ...` не является `is (not ...)`](#-is-not--не-является-is-not-) + - [💡 Объяснение](#-объяснение-9) + - [▶ Крестики-нолики, где X побеждает с первой попытки!](#-крестики-нолики-где-x-побеждает-с-первой-попытки) + - [💡 Объяснение:](#-объяснение-10) + - [▶ Переменная Шредингера \*](#-переменная-шредингера-) + - [💡 Объяснение:](#-объяснение-11) + - [▶ Проблема курицы и яйца \*](#-проблема-курицы-и-яйца-) + - [💡 Объяснение](#-объяснение-12) + - [▶ Отношения между подклассами](#-отношения-между-подклассами) + - [💡 Объяснение](#-объяснение-13) + - [▶ Равенство и тождество методов](#-равенство-и-тождество-методов) + - [💡 Объяснение](#-объяснение-14) + - [▶ All-true-ation (непереводимая игра слов) \*](#-all-true-ation-непереводимая-игра-слов-) + - [💡 Объяснение:](#-объяснение-15) + - [💡 Объяснение:](#-объяснение-16) + - [▶ Строки и обратные слэши](#-строки-и-обратные-слэши) + - [💡 Объяснение](#-объяснение-17) + - [▶ Не узел! (англ. not knot!)](#-не-узел-англ-not-knot) + - [💡 Объяснение](#-объяснение-18) + - [▶ Строки, наполовину обернутые в тройные кавычки](#-строки-наполовину-обернутые-в-тройные-кавычки) + - [💡 Объяснение:](#-объяснение-19) + - [▶ Что не так с логическими значениями?](#-что-не-так-с-логическими-значениями) + - [💡 Объяснение:](#-объяснение-20) + - [▶ Атрибуты класса и экземпляра](#-атрибуты-класса-и-экземпляра) + - [💡 Объяснение:](#-объяснение-21) + - [▶ Возврат None из генератора](#-возврат-none-из-генератора) + - [💡 Объяснение:](#-объяснение-22) + - [▶ Yield from возвращает... \*](#-yield-from-возвращает-) + - [💡 Объяснение:](#-объяснение-23) + - [▶ Nan-рефлексивность \*](#-nan-рефлексивность-) + - [💡 Объяснение:](#-объяснение-24) + - [▶ Изменяем неизменяемое!](#-изменяем-неизменяемое) + - [💡 Объяснение:](#-объяснение-25) + - [▶ Исчезающая переменная из внешней области видимости](#-исчезающая-переменная-из-внешней-области-видимости) + - [💡 Объяснение:](#-объяснение-26) + - [▶ Загадочное преобразование типов ключей](#-загадочное-преобразование-типов-ключей) + - [💡 Объяснение:](#-объяснение-27) + - [▶ Посмотрим, сможете ли вы угадать что здесь?](#-посмотрим-сможете-ли-вы-угадать-что-здесь) + - [💡 Объяснение:](#-объяснение-28) + - [▶ Превышение предела целочисленного преобразования строк](#-превышение-предела-целочисленного-преобразования-строк) + - [💡 Объяснение:](#-объяснение-29) + - [Секция: Скользкие склоны](#секция-скользкие-склоны) + - [▶ Изменение словаря во время прохода по нему](#-изменение-словаря-во-время-прохода-по-нему) + - [💡 Объяснение:](#-объяснение-30) + - [▶ Упрямая операция `del`](#-упрямая-операция-del) + - [💡 Объяснение:](#-объяснение-31) + - [▶ Переменная за пределами видимости](#-переменная-за-пределами-видимости) + - [💡 Объяснение:](#-объяснение-32) + - [▶ Удаление элемента списка во время прохода по списку](#-удаление-элемента-списка-во-время-прохода-по-списку) + - [💡 Объяснение:](#-объяснение-33) + - [▶ Сжатие итераторов с потерями \*](#-сжатие-итераторов-с-потерями-) + - [💡 Объяснение:](#-объяснение-34) + - [▶ Утечка переменных внутри цикла](#-утечка-переменных-внутри-цикла) + - [💡 Объяснение:](#-объяснение-35) + - [▶ Остерегайтесь изменяемых аргументов по умолчанию!](#-остерегайтесь-изменяемых-аргументов-по-умолчанию) + - [💡 Объяснение:](#-объяснение-36) + - [▶ Ловля исключений](#-ловля-исключений) + - [💡 Объяснение](#-объяснение-37) + - [▶ Одни и те же операнды, разная история!](#-одни-и-те-же-операнды-разная-история) + - [💡 Объяснение:](#-объяснение-38) + - [▶ Разрешение имен игнорирует область видимости класса](#-разрешение-имен-игнорирует-область-видимости-класса) + - [💡 Объяснение](#-объяснение-39) + - [▶ Округляясь как банкир \*](#-округляясь-как-банкир-) + - [💡 Объяснение:](#-объяснение-40) + - [▶ Иголки в стоге сена \*](#-иголки-в-стоге-сена-) + - [💡 Объяснение:](#-объяснение-41) + - [▶ Сплиты (splitsies) \*](#-сплиты-splitsies-) + - [💡 Объяснение](#-объяснение-42) + - [▶ Подстановочное импортирование (wild imports) \*](#-подстановочное-импортирование-wild-imports-) + - [💡 Объяснение:](#-объяснение-43) + - [▶ Все ли отсортировано? \*](#-все-ли-отсортировано-) + - [💡 Объяснение:](#-объяснение-44) + - [▶ Полночи не существует?](#-полночи-не-существует) + - [💡 Объяснение:](#-объяснение-45) + - [Секция: Скрытые сокровища!](#секция-скрытые-сокровища) + - [▶ Python, можешь ли ты помочь взлететь?](#-python-можешь-ли-ты-помочь-взлететь) + - [💡 Объяснение:](#-объяснение-46) + - [▶ `goto`, но почему?](#-goto-но-почему) + - [💡 Объяснение:](#-объяснение-47) + - [▶ Держитесь!](#-держитесь) + - [💡 Объяснение:](#-объяснение-48) + - [▶ Давайте познакомимся с дружелюбным Дядей Барри](#-давайте-познакомимся-с-дружелюбным-дядей-барри) + - [💡 Объяснение:](#-объяснение-49) + - [▶ Даже Python понимает, что любовь - это сложно.](#-даже-python-понимает-что-любовь---это-сложно) + - [💡 Объяснение:](#-объяснение-50) + - [▶ Да, оно существует!](#-да-оно-существует) + - [💡 Объяснение:](#-объяснение-51) + - [▶ Многоточие \*](#-многоточие-) + - [💡 Объяснение](#-объяснение-52) + - [▶ Писконечность (Inpinity)](#-писконечность-inpinity) + - [💡 Объяснение:](#-объяснение-53) + - [▶ Давайте искажать](#-давайте-искажать) + - [💡 Объяснение:](#-объяснение-54) + - [Секция: Внешность обманчива!](#секция-внешность-обманчива) + - [▶ Пропускаем строки?](#-пропускаем-строки) + - [💡 Объяснение](#-объяснение-55) + - [▶ Телепортация](#-телепортация) + - [💡 Объяснение:](#-объяснение-56) + - [▶ Что-то не так...](#-что-то-не-так) + - [💡 Объяснение](#-объяснение-57) + - [Секция: Разное](#секция-разное) + - [▶ `+=` быстрее `+`](#--быстрее-) + - [💡 Объяснение:](#-объяснение-58) + - [▶ Сделаем гигантскую строку!](#-сделаем-гигантскую-строку) + - [💡 Объяснение](#-объяснение-59) + - [▶ Замедляем поиск по `dict` \*](#-замедляем-поиск-по-dict-) + - [💡 Объяснение:](#-объяснение-60) + - [▶ Раздуваем экземпляры словарей \*](#-раздуваем-экземпляры-словарей-) + - [💡 Объяснение:](#-объяснение-61) + - [▶ Минорное \*](#-минорное-) +- [Вклад в проект](#вклад-в-проект) +- [Благодарности](#благодарности) + - [Несколько хороших ссылок!](#несколько-хороших-ссылок) +- [🎓 Лицензия](#-лицензия) + - [Удиви своих друзей!](#удиви-своих-друзей) + - [Нужна PDF версия?](#нужна-pdf-версия) # Структура примера @@ -137,11 +202,11 @@ PS: Если вы уже читали **wtfpython** раньше, с измен Хороший способ получить максимальную пользу от этих примеров - читать их последовательно, причем для каждого из них важно: -- Внимательно изучить исходный код. Если вы опытный программист на Python, то в большинстве случаев сможете предугадать, что произойдет дальше. +- Внимательно изучить исходный код. Если вы опытный Python программист, то в большинстве случаев сможете предугадать, что произойдет дальше. - Прочитать фрагменты вывода и, - Проверить, совпадают ли выходные данные с вашими ожиданиями. - Убедиться, что вы знаете точную причину, по которой вывод получился именно таким. - - Если ответ отрицательный (что совершенно нормально), сделать глубокий вдох и прочитать объяснение (а если пример все еще непонятен, и создайте issue [здесь](https://github.com/satwikkansal/wtfpython/issues/new)). + - Если ответ отрицательный (что совершенно нормально), сделать глубокий вдох и прочитать объяснение (а если пример все еще непонятен, и создайте [issue](https://github.com/satwikkansal/wtfpython/issues/new)). - Если "да", ощутите мощь своих познаний в Python и переходите к следующему примеру. PS: Вы также можете читать WTFPython в командной строке, используя [pypi package](https://pypi.python.org/pypi/wtfpython), @@ -344,7 +409,7 @@ False - Строки интернируются во время компиляции (`'wtf'` будет интернирована, но `''.join(['w'', 't', 'f'])` - нет) - Строки, не состоящие из букв ASCII, цифр или знаков подчеркивания, не интернируются. В примере выше `'wtf!'` не интернируется из-за `!`. Реализацию этого правила в CPython можно найти [здесь](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19) ![image](/images/string-intern/string_intern.png) -- Когда переменные `a` и `b` принимают значение `"wtf!"` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на вторую переменную. Если это выполняется в отдельных строках, он не "знает", что уже существует `"wtf!"` как объект (потому что `"wtf!"` не является неявно интернированным в соответствии с фактами, упомянутыми выше). Это оптимизация во время компиляции, не применяется к версиям CPython 3.7.x (более подробное обсуждение смотрите здесь [issue](https://github.com/satwikkansal/wtfpython/issues/100)). +- Когда переменные `a` и `b` принимают значение `"wtf!"` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на вторую переменную. Если это выполняется в отдельных строках, он не "знает", что уже существует `"wtf!"` как объект (потому что `"wtf!"` не является неявно интернированным в соответствии с фактами, упомянутыми выше). Это оптимизация во время компиляции, не применяется к версиям CPython 3.7.x (более подробное обсуждение смотрите [здесь](https://github.com/satwikkansal/wtfpython/issues/100)). - Единица компиляции в интерактивной среде IPython состоит из одного оператора, тогда как в случае модулей она состоит из всего модуля. `a, b = "wtf!", "wtf!"` - это одно утверждение, тогда как `a = "wtf!"; b = "wtf!"` - это два утверждения в одной строке. Это объясняет, почему тождества различны в `a = "wtf!"; b = "wtf!"`, но одинаковы при вызове в модуле. - Резкое изменение в выводе четвертого фрагмента связано с [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) техникой, известной как складывание констант (англ. Constant folding). Это означает, что выражение `'a'*20` заменяется на `'aaaaaaaaaaaaaaaaaaaa'` во время компиляции, чтобы сэкономить несколько тактов во время выполнения. Складывание констант происходит только для строк длиной менее 21. (Почему? Представьте себе размер файла `.pyc`, созданного в результате выполнения выражения `'a'*10**10`). [Вот](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) исходный текст реализации для этого. - Примечание: В Python 3.7 складывание констант было перенесено из оптимизатора peephole в новый оптимизатор AST с некоторыми изменениями в логике, поэтому четвертый фрагмент не работает в Python 3.7. Подробнее об изменении можно прочитать [здесь](https://bugs.python.org/issue11549). @@ -378,7 +443,7 @@ False #### 💡 Объяснение: -Согласно https://docs.python.org/3/reference/expressions.html#comparisons +Согласно [документации](https://docs.python.org/3/reference/expressions.html#comparisons) > Формально, если a, b, c, ..., y, z - выражения, а op1, op2, ..., opN - операторы сравнения, то a op1 b op2 c ... y opN z эквивалентно a op1 b и b op2 c и ... y opN z, за исключением того, что каждое выражение оценивается не более одного раза. @@ -491,7 +556,7 @@ False Подобная оптимизация применима и к другим **изменяемым** объектам, таким как пустые кортежи. Поскольку списки являются изменяемыми, поэтому `[] is []` вернет `False`, а `() is ()` вернет `True`. Это объясняет наш второй фрагмент. Перейдем к третьему, -**И `a`, и `b` ссылаются на один и тот же объект при инициализации одним и тем же значением в одной и той же строкеi**. +**И `a`, и `b` ссылаются на один и тот же объект при инициализации одним и тем же значением в одной и той же строке**. **Вывод** @@ -511,7 +576,7 @@ False * Когда a и b инициализируются со значением `257` в одной строке, интерпретатор Python создает новый объект, а затем одновременно ссылается на него во второй переменной. Если делать это в отдельных строках, интерпретатор не "знает", что объект `257` уже существует. -* Это оптимизация компилятора и относится именно к интерактивной среде. Когда вы вводите две строки в интерпретаторе, они компилируются отдельно, поэтому оптимизируются отдельно. Если выполнить этот пример в файле `.py', поведение будет отличаться, потому что файл компилируется весь сразу. Эта оптимизация не ограничивается целыми числами, она работает и для других неизменяемых типов данных, таких как строки (проверьте пример "Строки - это сложно") и плавающие числа, +* Эта оптимизация компилятора относится именно к интерактивной среде. Когда вы вводите две строки в интерпретаторе, они компилируются отдельно, поэтому оптимизируются отдельно. Если выполнить этот пример в файле `.py', поведение будет отличаться, потому что файл компилируется целиком. Эта оптимизация не ограничивается целыми числами, она работает и для других неизменяемых типов данных, таких как строки (смотреть пример "Строки - это сложно") и плавающие числа, ```py >>> a, b = 257.0, 257.0 @@ -519,12 +584,12 @@ False True ``` -* Почему это не сработало в Python 3.7? Абстрактная причина в том, что такие оптимизации компилятора зависят от реализации (т.е. могут меняться в зависимости от версии, ОС и т.д.). Я все еще выясняю, какое именно изменение реализации вызвало проблему, вы можете проверить этот [issue](https://github.com/satwikkansal/wtfpython/issues/100) для получения обновлений. +* Почему это не сработало в Python 3.7? Абстрактная причина в том, что такие оптимизации компилятора зависят от реализации (т.е. могут меняться в зависимости от версии, ОС и т.д.). Я все еще выясняю, какое именно изменение реализации вызвало проблему, вы можете следить за этим [issue](https://github.com/satwikkansal/wtfpython/issues/100) для получения обновлений. --- -### ▶ Мистическое хэширование +### ▶ Мистическое хеширование 1\. ```py @@ -556,7 +621,7 @@ complex #### 💡 Объяснение -* Уникальность ключей в словаре Python определяется *эквивалентностью*, а не тождеством. Поэтому, даже если `5`, `5.0` и `5 + 0j` являются различными объектами разных типов, поскольку они равны, они не могут находиться в одном и том же `dict` (или `set`). Как только вы вставите любой из них, попытка поиска по любому другому, но эквивалентному ключу будет успешной с исходным сопоставленным значением (а не завершится ошибкой `KeyError`): +* Уникальность ключей в словаре Python определяется *эквивалентностью*, а не тождеством. Поэтому, даже если `5`, `5.0` и `5 + 0j` являются различными объектами разных типов, поскольку они эквивалентны, они не могут находиться в одном и том же `dict` (или `set`). Как только вы вставите любой из них, попытка поиска по любому другому, но эквивалентному ключу будет успешной с исходным сопоставленным значением (а не завершится ошибкой `KeyError`): ```py >>> 5 == 5.0 == 5 + 0j True @@ -569,7 +634,7 @@ complex >>> (5 in some_dict) and (5 + 0j in some_dict) True ``` -* Это применимо и во время присваения значения элементу. Поэтому, в выражении `some_dict[5] = "Python"` Python находит существующий элемент с эквивалентным ключом `5.0 -> "Ruby"`, перезаписывает его значение на место, а исходный ключ оставляет в покое. +* Это применимо и во время присваивания значения элементу. Поэтому, в выражении `some_dict[5] = "Python"` Python находит существующий элемент с эквивалентным ключом `5.0 -> "Ruby"`, перезаписывает его значение на место, а исходный ключ оставляет в покое. ```py >>> some_dict {5.0: 'Ruby'} @@ -577,16 +642,17 @@ complex >>> some_dict {5.0: 'Python'} ``` -* Итак, как мы можем обновить ключ до `5` (вместо `5.0`)? На самом деле мы не можем сделать это обновление на месте, но что мы можем сделать, так это сначала удалить ключ (`del some_dict[5.0]`), а затем установить его (`some_dict[5]`), чтобы получить целое число `5` в качестве ключа вместо плавающего `5.0`, хотя это нужно в редких случаях. +* Итак, как мы можем обновить ключ до `5` (вместо `5.0`)? На самом деле мы не можем сделать это обновление на месте, но все же это возможно, нужно сначала удалить ключ (`del some_dict[5.0]`), а затем установить его (`some_dict[5]`), чтобы получить целое число `5` в качестве ключа вместо плавающего `5.0`, хотя это нужно в редких случаях. + +* Как Python нашел `5` в словаре, содержащем `5.0`? Python делает это за постоянное время без необходимости сканирования каждого элемента, используя хэш-функции. Когда Python ищет ключ `foo` в словаре, он сначала вычисляет `hash(foo)` (что выполняется в постоянном времени). Поскольку в Python требуется, чтобы объекты, которые одинаковы в сравнении, имели одинаковое хэш-значение (смотри [документацию](https://docs.python.org/3/reference/datamodel.html#object.__hash__)), `5`, `5.0` и `5 + 0j` выполняют это условие. -* Как Python нашел `5` в словаре, содержащем `5.0`? Python делает это за постоянное время без необходимости сканирования каждого элемента, используя хэш-функции. Когда Python ищет ключ `foo` в словаре, он сначала вычисляет `hash(foo)` (что выполняется в постоянном времени). Поскольку в Python требуется, чтобы объекты, которые сравниваются одинаково, имели одинаковое хэш-значение ([docs](https://docs.python.org/3/reference/datamodel.html#object.__hash__) здесь), `5`, `5.0` и `5 + 0j` имеют одинаковое хэш-значение. ```py >>> 5 == 5.0 == 5 + 0j True >>> hash(5) == hash(5.0) == hash(5 + 0j) True ``` - **Примечание:** Обратное не обязательно верно: Объекты с одинаковыми хэш-значениями сами могут быть неравными. (Это вызывает так называемую [хэш-коллизию](https://en.wikipedia.org/wiki/Collision_(computer_science)) и ухудшает производительность постоянного времени, которую обычно обеспечивает хэширование). + **Примечание:** Обратное не обязательно верно: Объекты с одинаковыми хэш-значениями сами могут быть неравными. (Это вызывает так называемую [хэш-коллизию](https://en.wikipedia.org/wiki/Collision_(computer_science)) и ухудшает производительность постоянного времени, которую обычно обеспечивает хеширование). --- @@ -604,14 +670,14 @@ class WTF: False >>> WTF() is WTF() # идентификаторы также различаются False ->>> hash(WTF()) == hash(WTF()) # хэши тоже должны отличаться +>>> hash(WTF()) == hash(WTF()) # хеши тоже должны отличаться True >>> id(WTF()) == id(WTF()) True ``` #### 💡 Объяснение: -* При вызове `id` Python создал объект класса `WTF` и передал его функции `id`. Функция `id` забирает свой `id` (местоположение в памяти) и выбрасывает объект. Объект уничтожается. +* При вызове `id` Python создал объект класса `WTF` и передал его функции `id`. Функция `id` забирает свой `id` (расположение в памяти) и выбрасывает объект. Объект уничтожается. * Когда мы делаем это дважды подряд, Python выделяет ту же самую область памяти и для второго объекта. Поскольку (в CPython) `id` использует участок памяти в качестве идентификатора объекта, идентификатор двух объектов одинаков. * Таким образом, id объекта уникален только во время жизни объекта. После уничтожения объекта или до его создания, другой объект может иметь такой же id. * Но почему выражение с оператором `is` равно `False`? Давайте посмотрим с помощью этого фрагмента. @@ -641,7 +707,7 @@ True --- -### ▶ Беспорядок внутри порядка * +### ▶ Беспорядок внутри порядка * ```py from collections import OrderedDict @@ -657,13 +723,13 @@ another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a'; class DictWithHash(dict): """ - A dict that also implements __hash__ magic. + Словарь с реализованным методом __hash__. """ __hash__ = lambda self: 0 class OrderedDictWithHash(OrderedDict): """ - An OrderedDict that also implements __hash__ magic. + OrderedDict с реализованным методом __hash__. """ __hash__ = lambda self: 0 ``` @@ -677,7 +743,7 @@ True >>> ordered_dict == another_ordered_dict # почему же c != a ?? False -# Мы все знаем, что множество состоит только из уникальных элементов, +# Мы все знаем, что множество состоит из уникальных элементов, # давайте попробуем составить множество из этих словарей и посмотрим, что получится... >>> len({dictionary, ordered_dict, another_ordered_dict}) @@ -695,7 +761,7 @@ TypeError: unhashable type: 'dict' >>> another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a'; >>> len({dictionary, ordered_dict, another_ordered_dict}) 1 ->>> len({ordered_dict, another_ordered_dict, dictionary}) # changing the order +>>> len({ordered_dict, another_ordered_dict, dictionary}) # изменим порядок элементов 2 ``` @@ -703,7 +769,7 @@ TypeError: unhashable type: 'dict' #### 💡 Объяснение: -- Переходное (интрантизивное) равенство между `dictionary`, `ordered_dict` и `another_ordered_dict` не выполняется из-за реализации магического метода `__eq__` в классе `OrderedDict`. Перевод цитаты из [документации](https://docs.python.org/3/library/collections.html#ordereddict-objects) +- Переходное (интранзитивное) равенство между `dictionary`, `ordered_dict` и `another_ordered_dict` не выполняется из-за реализации магического метода `__eq__` в классе `OrderedDict`. Перевод цитаты из [документации](https://docs.python.org/3/library/collections.html#ordereddict-objects) > Тесты равенства между объектами OrderedDict чувствительны к порядку и реализуются как `list(od1.items())==list(od2.items())`. Тесты на равенство между объектами `OrderedDict` и другими объектами Mapping нечувствительны к порядку, как обычные словари. - Причина такого поведения равенства в том, что оно позволяет напрямую подставлять объекты `OrderedDict` везде, где используется обычный словарь. @@ -794,7 +860,7 @@ Iteration 0 #### 💡 Объяснение: -- Когда один из операторов `return`, `break` или `continue` выполняется в блоке `try` оператора "try...finally", на выходе также выполняется пункт `finally`. +- Когда один из операторов `return`, `break` или `continue` выполняется в блоке `try` оператора "try...finally", на выходе также выполняется блок `finally`. - Возвращаемое значение функции определяется последним выполненным оператором `return`. Поскольку блок `finally` выполняется всегда, оператор `return`, выполненный в блоке `finally`, всегда будет последним. - Предостережение - если в блоке `finally` выполняется оператор `return` или `break`, то временно сохраненное исключение отбрасывается. @@ -966,7 +1032,7 @@ board = [row] * 3 [['X', '', ''], ['X', '', ''], ['X', '', '']] ``` -Мы же не назначили три `"Х"`? +Мы же не назначали три `"Х"`? #### 💡 Объяснение: @@ -1006,7 +1072,7 @@ for x in range(7): funcs_results = [func() for func in funcs] ``` -**Вывод (Python version):** +**Вывод:** ```py >>> results [0, 1, 2, 3, 4, 5, 6] @@ -1039,7 +1105,7 @@ ClosureVars(nonlocals={}, globals={'x': 6}, builtins={}, unbound=set()) [42, 42, 42, 42, 42, 42, 42] ``` -* Чтобы получить желаемое поведение, вы можете передать переменную цикла как именованную переменную в функцию. **Почему это работает?** Потому что это определит переменную *внутри* области видимости функции. Она больше не будет обращаться к глобальной области видимости для поиска значения переменной, а создаст локальную переменную, которая будет хранить значение `x` в данный момент времени. +* Чтобы получить желаемое поведение, вы можете передать переменную цикла как именованную аргумент в функцию. **Почему это работает?** Потому что это определит переменную *внутри* области видимости функции. Она больше не будет обращаться к глобальной области видимости для поиска значения переменной, а создаст локальную переменную, которая будет хранить значение `x` в данный момент времени. ```py funcs = [] @@ -1079,7 +1145,7 @@ True True ``` -Так какой же базовый класс является "окончательным"? Кстати, это еще не все, +Так какой же базовый класс является "родительским"? Кстати, это еще не все, 2\. @@ -1137,12 +1203,11 @@ False * Отношения подклассов не обязательно являются транзитивными в Python. Можно переопределить магический метод `__subclasscheck__` в метаклассе. * Когда вызывается `issubclass(cls, Hashable)`, он просто ищет не-фальшивый метод "`__hash__`" в `cls` или во всем, от чего он наследуется. -* Поскольку `object` является хэшируемым, а `list` - нехэшируемым, это нарушает отношение транзитивности. -* Более подробное объяснение можно найти [здесь] (https://www.naftaliharris.com/blog/python-subclass-intransitivity/). +* Поскольку `object` является хэшируемым, а `list` - нет, это нарушает отношение транзитивности. +* Более подробное объяснение можно найти [здесь](https://www.naftaliharris.com/blog/python-subclass-intransitivity/). --- - ### ▶ Равенство и тождество методов @@ -1202,7 +1267,7 @@ True #### 💡 Объяснение * Функции являются [дескрипторами](https://docs.python.org/3/howto/descriptor.html). Всякий раз, когда к функции обращаются как к -атрибута, вызывается дескриптор, создавая объект метода, который "связывает" функцию с объектом, владеющим атрибутом. При вызове метод вызывает функцию, неявно передавая связанный объект в качестве первого аргумента +атрибуту, вызывается дескриптор, создавая объект метода, который "связывает" функцию с объектом, владеющим атрибутом. При вызове метод вызывает функцию, неявно передавая связанный объект в качестве первого аргумента (именно так мы получаем `self` в качестве первого аргумента, несмотря на то, что не передаем его явно). ```py >>> o1.method @@ -1338,7 +1403,7 @@ True #### 💡 Объяснение -- В обычной строке обратная слэш используется для экранирования символов, которые могут иметь специальное значение (например, одинарная кавычка, двойная кавычка и сам обратный слэш). +- В обычной строке обратный слэш используется для экранирования символов, которые могут иметь специальное значение (например, одинарная кавычка, двойная кавычка и сам обратный слэш). ```py >>> "wt\"f" 'wt"f' @@ -1355,12 +1420,12 @@ True >>> print(r"\\n") '\\n' ``` -- Это означает, что когда синтаксический анализатор встречает обратный слэш в необработанной строке, он ожидает, что за ней последует другой символ. А в нашем случае (`print(r"\")`) обратная слэш экранирует двойную кавычку, оставив парсер без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слеш не работает в конце необработанной строки. +- Это означает, что когда синтаксический анализатор встречает обратный слэш в необработанной строке, он ожидает, что за ней последует другой символ. А в нашем случае (`print(r"\")`) обратный слэш экранирует двойную кавычку, оставив синтаксический анализатор без завершающей кавычки (отсюда `SyntaxError`). Вот почему обратный слэш не работает в конце необработанной строки. --- +--- -### ▶ Не узел! (eng. not knot!) +### ▶ Не узел! (англ. not knot!) ```py x = True @@ -1383,12 +1448,12 @@ SyntaxError: invalid syntax * Старшинство операторов влияет на выполнение выражения, и оператор `==` имеет более высокий приоритет, чем оператор `not` в Python. * Поэтому `not x == y` эквивалентно `not (x == y)`, что эквивалентно `not (True == False)`, в итоге равное `True`. * Но `x == not y` вызывает `SyntaxError`, потому что его можно считать эквивалентным `(x == not) y`, а не `x == (not y)`, что можно было бы ожидать на первый взгляд. -* Парсер ожидал, что ключевое слово `not` будет частью оператора `not in` (потому что оба оператора `==` и `not in` имеют одинаковый приоритет), но после того, как он не смог найти ключевое слово `in`, следующее за `not`, он выдает `SyntaxError`. +* Синтаксический анализатор (англ. parser) ожидал, что ключевое слово `not` будет частью оператора `not in` (потому что оба оператора `==` и `not in` имеют одинаковый приоритет), но после того, как он не смог найти ключевое слово `in`, следующее за `not`, он выдает `SyntaxError`. --- -### ▶ Строки наполовину в тройных кавычках +### ▶ Строки, наполовину обернутые в тройные кавычки **Вывод:** ```py @@ -1503,7 +1568,7 @@ I have lost faith in truth! * Изначально в Python не было типа `bool` (использовали 0 для false и ненулевое значение 1 для true). В версиях 2.x были добавлены `True`, `False` и тип `bool`, но для обратной совместимости `True` и `False` нельзя было сделать константами. Они просто были встроенными переменными, и их можно было переназначить. -* Python 3 был несовместим с предыдущими версиями, эту проблему наконец-то исправили, и поэтому последний фрагмент не будет работать с Python 3.x! +* Python 3 несовместим с предыдущими версиями, эту проблему наконец-то исправили, и поэтому последний фрагмент не будет работать с Python 3.x! --- @@ -1651,7 +1716,7 @@ def some_func(x): [] ``` -То же самое, это тоже не сработало. Что происходит? +Опять не сработало. Что происходит? #### 💡 Объяснение: @@ -1659,7 +1724,7 @@ def some_func(x): > "... `return expr` в генераторе вызывает исключение `StopIteration(expr)` при выходе из генератора." -+ В случае `some_func(3)` `StopIteration` возникает в начале из-за оператора `return`. Исключение `StopIteration` автоматически перехватывается внутри обертки `list(...)` и цикла `for`. Поэтому два вышеприведенных фрагмента приводят к пустому списку. ++ В случае `some_func(3)` `StopIteration` возникает в начале из-за оператора `return`. Исключение `StopIteration` автоматически перехватывается внутри обертки `list(...)` и цикла `for`. Поэтому два вышеприведенных фрагмента возвращают пустой список. + Чтобы получить `["wtf"]` из генератора `some_func`, нужно перехватить исключение `StopIteration`. @@ -1721,7 +1786,7 @@ nan ```py >>> x = float('nan') >>> y = x / x ->>> y is y # идендичность сохраняется +>>> y is y # идентичность сохраняется True >>> y == y # сравнение ложно для y False @@ -1733,7 +1798,7 @@ True - `'inf'` и `'nan'` - это специальные строки (без учета регистра), которые при явном приведении к типу `float` используются для представления математической "бесконечности" и "не число" соответственно. -- Согласно стандартам IEEE `NaN != NaN`, но соблюдение этого правила нарушает предположение о рефлексивности элемента коллекции в Python, то есть если `x` является частью коллекции, такой как `list`, реализации, методы сравнения предполагают, что `x == x`. Поэтому при сравнении элементов сначала сравниваются их идентификаторы (так как это быстрее), а значения сравниваются только при несовпадении идентификаторов. Следующий фрагмент сделает вещи более ясными: +- Согласно стандартам IEEE, `NaN != NaN`, но соблюдение этого правила нарушает предположение о рефлексивности элемента коллекции в Python, то есть если `x` является частью коллекции, такой как `list`, реализации методов сравнения предполагают, что `x == x`. Поэтому при сравнении элементов сначала сравниваются их идентификаторы (так как это быстрее), а значения сравниваются только при несовпадении идентификаторов. Следующий фрагмент сделает вещи более ясными: ```py >>> x = float('nan') @@ -1753,7 +1818,7 @@ True --- -### ▶ Мутируем немутируемое! +### ▶ Изменяем неизменяемое! @@ -1783,8 +1848,7 @@ TypeError: 'tuple' object does not support item assignment * Перевод цитаты из [документации](https://docs.python.org/3/reference/datamodel.html) - > Неизменяемые последовательности - Объект неизменяемого типа последовательности не может измениться после создания. (Если объект содержит ссылки на другие объекты, эти объекты могут быть изменяемыми и могут быть изменены; однако набор объектов, на которые непосредственно ссылается неизменяемый объект, не может изменяться.) + > Объект неизменяемого типа последовательности не может измениться после создания. (Если объект содержит ссылки на другие объекты, эти объекты могут быть изменяемыми и могут быть изменены; однако набор объектов, на которые непосредственно ссылается неизменяемый объект, не может изменяться.) * Оператор `+=` изменяет список на месте. Присваивание элемента не работает, но когда возникает исключение, элемент уже был изменен на месте. * Также есть объяснение в официальном [Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works). @@ -1836,30 +1900,30 @@ NameError: name 'e' is not defined del N ``` -Это означает, что исключению должно быть присвоено другое имя, чтобы на него можно было ссылаться после завершения блока `except`. Исключения очищаются, потому что с прикрепленным к ним трейсбэком они образуют цикл ссылок со стеком вызовов, сохраняя все локальные объекты в этой стэке до следующей сборки мусора. +Это означает, что исключению должно быть присвоено другое имя, чтобы на него можно было ссылаться после завершения блока `except`. Исключения очищаются, потому что с прикрепленным к ним трейсбэком они образуют цикл ссылок со стэком вызовов, сохраняя все локальные объекты в этой стэке до следующей сборки мусора. * В Python clauses не имеют области видимости. В примере все объекты в одной области видимости, а переменная `e` была удалена из-за выполнения блока `except`. Этого нельзя сказать о функциях, которые имеют отдельные внутренние области видимости. Пример ниже иллюстрирует это: -```py - def f(x): - del(x) - print(x) + ```py + def f(x): + del(x) + print(x) - x = 5 - y = [5, 4, 3] - ``` + 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] - ``` + **Результат:** + ```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] + ``` * В Python 2.x, имя переменной `e` назначается на экземпляр `Exception()`, и при попытки вывести значение `e` ничего не выводится. @@ -1954,13 +2018,9 @@ a, b = a[b] = {}, 5 > Оператор присваивания исполняет список выражений (помните, что это может быть одно выражение или список, разделенный запятыми, в последнем случае получается кортеж) и присваивает единственный результирующий объект каждому из целевых списков, слева направо. * `+` в `(target_list "=")+` означает, что может быть **один или более** целевых списков. В данном случае целевыми списками являются `a, b` и `a[b]` (обратите внимание, что список выражений ровно один, в нашем случае это `{}, 5`). - * После исполнения списка выражений его значение распаковывается в целевые списки **слева направо**. Так, в нашем случае сначала кортеж `{}, 5` распаковывается в `a, b`, и теперь у нас есть `a = {}` и `b = 5`. - * Теперь `a` имеет значение `{}`, которое является изменяемым объектом. - * Вторым целевым списком является `a[b]` (вы можете ожидать, что это вызовет ошибку, поскольку `a` и `b` не были определены в предыдущих утверждениях. Но помните, мы только что присвоили `a` значение `{}` и `b` - `5`). - * Теперь мы устанавливаем ключ `5` в словаре в кортеж `({}, 5)`, создавая круговую ссылку (`{...}` в выводе ссылается на тот же объект, на который уже ссылается `a`). Другим более простым примером круговой ссылки может быть ```py @@ -2010,7 +2070,7 @@ ValueError: Exceeds the limit (4300) for integer string conversion: #### 💡 Объяснение: Этот вызов `int()` прекрасно работает в Python 3.10.6 и вызывает ошибку `ValueError` в Python 3.10.8, 3.11. Обратите внимание, что Python все еще может работать с большими целыми числами. Ошибка возникает только при преобразовании между целыми числами и строками. К счастью, вы можете увеличить предел допустимого количества цифр. Для этого можно воспользоваться одним из следующих способов: -- `-X int_max_str_digits` - флаг командной строкиcommand-line flag +- `-X int_max_str_digits` - флаг командной строки - `set_int_max_str_digits()` - функция из модуля `sys` - `PYTHONINTMAXSTRDIGITS` - переменная окружения @@ -2230,7 +2290,7 @@ for idx, item in enumerate(list_4): >>> some_list = [1, 2, 3, 4] >>> id(some_list) 139798789457608 - >>> id(some_list[:]) # Notice that python creates new object for sliced list. + >>> id(some_list[:]) # Обратите внимание, создается новый объект из среза списка 139798779601192 ``` @@ -2239,7 +2299,7 @@ for idx, item in enumerate(list_4): * `remove` удаляет первое подходящее значение, а не конкретный индекс, вызывает `ValueError`, если значение не найдено. * `pop` удаляет элемент по определенному индексу и возвращает его, вызывает `IndexError`, если указан неверный индекс. -**Почему на выходе получается `[2, 4]`? +**Почему на выходе получается `[2, 4]`?** - Проход по списку выполняется индекс за индексом, и когда мы удаляем `1` из `list_2` или `list_4`, содержимое списков становится `[2, 3, 4]`. Оставшиеся элементы сдвинуты вниз, то есть `2` находится на индексе 0, а `3` - на индексе 1. Поскольку на следующей итерации будет просматриваться индекс 1 (который и есть `3`), `2` будет пропущен полностью. Аналогичное произойдет с каждым альтернативным элементом в последовательности списка. * Объяснение примера можно найти на [StackOverflow](https://stackoverflow.com/questions/45946228/what-happens-when-you-try-to-delete-a-list-element-while-iterating-over-it). @@ -2354,7 +2414,7 @@ print(x, ': x in global') #### 💡 Объяснение: -- В Python циклы for используют область видимости, в которой они существуют, и оставляют свою определенную переменную цикла после завершения. Это также относится к случаям, когда мы явно определили переменную цикла for в глобальном пространстве имен. В этом случае будет произведена перепривязка существующей переменной. +- В Python циклы for используют область видимости, в которой они существуют, и оставляют свою определенную переменную цикла после завершения. Это также относится к случаям, когда мы явно определили переменную цикла for в глобальном пространстве имен. В этом случае будет произведена повторная привязка существующей переменной. - Различия в выводе интерпретаторов Python 2.x и Python 3.x для примера с пониманием списков можно объяснить следующим изменением, задокументированным в журнале изменений [What's New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html): @@ -2386,7 +2446,7 @@ def some_func(default_arg=[]): #### 💡 Объяснение: -- Изменяемые аргументы функций по умолчанию в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется недавно присвоенное им значение. Когда мы явно передали `[]` в `some_func в качестве аргумента, значение по умолчанию переменной `default_arg` не было использовано, поэтому функция вернулась, как и ожидалось. +- Изменяемые аргументы функций по умолчанию в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется недавно присвоенное им значение. Когда мы явно передали `[]` в `some_func` в качестве аргумента, значение по умолчанию переменной `default_arg` не было использовано, поэтому функция вернулась, как и ожидалось. ```py def some_func(default_arg=[]): @@ -2396,7 +2456,7 @@ def some_func(default_arg=[]): **Результат:** ```py - >>> some_func.__defaults__ # Выражение выведет значения стандартных аргументов фукнции + >>> some_func.__defaults__ # Выражение выведет значения стандартных аргументов функции ([],) >>> some_func() >>> some_func.__defaults__ @@ -2580,7 +2640,7 @@ class SomeClass: #### 💡 Объяснение - Области видимости, вложенные внутрь определения класса, игнорируют имена, связанные на уровне класса. - Выражение-генератор имеет свою собственную область видимости. -- Начиная с версии Python 3.X, списковые вычисления также имеют свою собственную область видимости. +- Начиная с версии Python 3.X, списковые выражения (list comprehensions) также имеют свою собственную область видимости. --- @@ -2716,7 +2776,7 @@ b = "javascript" **Результат:** ```py -# assert выражение с сообщением об ошиб +# assert выражение с сообщением об ошибке >>> assert(a == b, "Both languages are different") # Исключение AssertionError не возникло ``` @@ -2939,7 +2999,7 @@ False (tuple, list) ``` -- В отличие от метода `sorted, метод `reversed` возвращает итератор. Почему? Потому что сортировка требует, чтобы итератор либо изменялся на месте, либо использовал дополнительный контейнер (список), в то время как реверсирование может работать просто путем итерации от последнего индекса к первому. +- В отличие от метода `sorted`, метод `reversed` возвращает итератор. Почему? Потому что сортировка требует, чтобы итератор либо изменялся на месте, либо использовал дополнительный контейнер (список), в то время как реверсирование может работать просто путем итерации от последнего индекса к первому. - Поэтому при сравнении `sorted(y) == sorted(y)` первый вызов `sorted()` будет потреблять итератор `y`, а следующий вызов просто вернет пустой список. @@ -2992,7 +3052,7 @@ if noon_time: Секция содержит менее известные интересные нюансы работы Python, которые неизвестны большинству новичков. -### ▶ Python, можешь ли ты помочь взлелеть? +### ▶ Python, можешь ли ты помочь взлететь? Что ж, поехали @@ -3007,7 +3067,7 @@ Sshh... It's a super-secret. + Модуль `antigravity` - одно из немногих пасхальных яиц, выпущенных разработчиками Python. + `import antigravity` открывает веб-браузер, указывающий на [классический комикс XKCD](https://xkcd.com/353/) о Python. -+ Это еще не все. Внутри пасхального яйца находится **еще одно пасхальное яйцо**. Если вы посмотрите на [код](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), там определена функция, которая якобы реализует [алгоритм геохашинга XKCD](https://xkcd.com/426/). ++ Это еще не все. Внутри пасхального яйца находится **еще одно пасхальное яйцо**. Если вы посмотрите на [код](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), там определена функция, которая якобы реализует алгоритм [XKCD](https://xkcd.com/426/). --- @@ -3164,7 +3224,7 @@ True ### ▶ Да, оно существует! -**Ключевое слово `else` в связвке с циклом `for`.** Один из стандартных примеров: +**Ключевое слово `else` в связке с циклом `for`.** Один из стандартных примеров: ```py def does_exists_num(l, to_find): @@ -3239,7 +3299,7 @@ Ellipsis - Многоточие может использоваться в нескольких случаях, + В качестве заполнителя для кода, который еще не написан (аналогично оператору `pass`) + В синтаксисе срезов (slices) для представления полных срезов в оставшемся направлении - ``py + ```py >>> import numpy as np >>> three_dimensional_array = np.arange(8).reshape(2, 2, 2) array([ @@ -3264,7 +3324,7 @@ Ellipsis [5, 7]]) ``` Примечание: это будет работать для любого количества измерений. Можно даже выбрать срез в первом и последнем измерении и игнорировать средние (`n_dimensional_array[firs_dim_slice, ..., last_dim_slice]`) - + В [подсказках типов](https://docs.python.org/3/library/typing.html) для указания только части типа (например, `(Callable[..., int]` или `Tuple[str, ...]`)) + + В [подсказках типов](https://docs.python.org/3/library/typing.html) для указания только части типа (например, `Callable[..., int]` или `Tuple[str, ...]`) + Вы также можете использовать `Ellipsis` в качестве аргумента функции по умолчанию (в случаях, когда вы хотите провести различие между сценариями "аргумент не передан" и "значение не передано"). --- @@ -3483,7 +3543,7 @@ def square(x): ## Секция: Разное -### ▶ `+=` быстрее +### ▶ `+=` быстрее `+` ```py @@ -3587,7 +3647,7 @@ def convert_list_to_string(l, iters): >>> %timeit -n100 add_string_with_plus(1000) 388 µs ± 22.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) - >>> %timeit -n100 add_string_with_plus(10000) # Quadratic increase in execution time + >>> %timeit -n100 add_string_with_plus(10000) # Квадратичное увеличение времени выполнения 9 ms ± 298 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) ``` @@ -3627,7 +3687,7 @@ KeyError: 1 #### 💡 Объяснение: + В CPython есть общая функция поиска по словарю, которая работает со всеми типами ключей (`str`, `int`, любой объект ...), и специализированная для распространенного случая словарей, состоящих только из `str`-ключей. -+ Специализированная функция (названная `lookdict_unicode` в [исходный код CPython](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841)) знает, что все существующие ключи (включая искомый ключ) являются строками, и использует более быстрое и простое сравнение строк для сравнения ключей, вместо вызова метода `__eq__`. ++ Специализированная функция (названная `lookdict_unicode` в [CPython](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841)) знает, что все существующие ключи (включая искомый ключ) являются строками, и использует более быстрое и простое сравнение строк для сравнения ключей, вместо вызова метода `__eq__`. + При первом обращении к экземпляру `dict` с ключом, не являющимся `str`, он модифицируется, чтобы в дальнейшем для поиска использовалась общая функция. + Этот процесс не обратим для конкретного экземпляра `dict`, и ключ даже не обязательно должен существовать в словаре. Поэтому попытка неудачного поиска имеет тот же эффект. @@ -3706,7 +3766,7 @@ def dict_size(o): * Несколько странных, но семантически правильных утверждений: + `[] = ()` - семантически корректное утверждение (распаковка пустого `кортежа` в пустой `список`) - + `'a'[0][0][0][0][0]` также является семантически корректным утверждением, поскольку в Python строки являются [последовательностями](https://docs.python.org/3/glossary.html#term-sequence)(итерируемыми объектами, поддерживающими доступ к элементам с использованием целочисленных индексов). + + `'a'[0][0][0][0][0]` также является семантически корректным утверждением, поскольку в Python строки являются [последовательностями](https://docs.python.org/3/glossary.html#term-sequence) (итерируемыми объектами, поддерживающими доступ к элементам с использованием целочисленных индексов). + `3 --0-- 5 == 8` и `--5 == 5` - оба семантически корректные утверждения и имеют значение `True`. * Учитывая, что `a` - это число, `++a` и `--a` являются корректными утверждениями Python, но ведут себя не так, как аналогичные утверждения в таких языках, как C, C++ или Java. From 9687de2a67cda2fcd16e7cca56523ea3ce919278 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 29 Apr 2024 06:36:44 +0300 Subject: [PATCH 72/83] Translate CONTRIBUTING guide --- CONTRIBUTING.md | 78 ++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd9049d..a542814 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,63 +1,63 @@ -All kinds of patches are welcome. Feel free to even suggest some catchy and funny titles for the existing Examples. The goal is to make this collection as interesting to read as possible. Here are a few ways through which you can contribute, +Приветствуются все виды изменений. Не стесняйтесь предлагать броские и смешные названия для существующих примеров. Цель - сделать эту коллекцию как можно более интересной для чтения. Вот несколько способов, с помощью которых вы можете внести свой вклад, -- If you are interested in translating the project to another language (some people have done that in the past), please feel free to open up an issue, and let me know if you need any kind of help. -- If the changes you suggest are significant, filing an issue before submitting the actual patch will be appreciated. If you'd like to work on the issue (highly encouraged), you can mention that you're interested in working on it while creating the issue and get assigned to it. -- If you're adding a new example, it is highly recommended to create an issue to discuss it before submitting a patch. You can use the following template for adding a new example: +- Если вы заинтересованы в переводе проекта на другой язык (некоторые люди уже делали это в прошлом), пожалуйста, не стесняйтесь открыть тему и дайте мне знать, если вам нужна какая-либо помощь. +- Если изменения, которые вы предлагаете, значительны, то создание issue перед внесением изменений будет оценено по достоинству. Если вы хотите поработать над issue (это очень рекомендуется), выразите свою заинтересованность и вы будете назначены исполнителем. +- Если вы добавляете новый пример, настоятельно рекомендуется создать issue, чтобы обсудить ее перед отправкой изменений. Для добавления нового примера вы можете использовать следующий шаблон:
-### ▶ Some fancy Title *
-The asterisk at the end of the title indicates the example was not present in the first release and has been recently added.
+### ▶ Какое-то причудливое название. *
+* в конце названия означает, что пример был добавлен недавно.
 
 ```py
-# Setting up the code.
-# Preparation for the magic...
+# Подготовка кода.
+# Подготовка к волшебству...
 ```
 
-**Output (Python version):**
+**Вывод (версия Python):**
 ```py
 >>> triggering_statement
-Probably unexpected output
-```
-(Optional): One line describing the unexpected output.
+Вероятно, неожиданный вывод
 
-#### 💡 Explanation:
-* Brief explanation of what's happening and why is it happening.
-  ```py
-  Setting up examples for clarification (if necessary)
-  ```
-  **Output:**
-  ```py
-  >>> trigger # some example that makes it easy to unveil the magic
-  # some justified output
-  ```
 ```
+(Необязательно): Одна строка, описывающая неожиданный вывод.
+
+#### 💡 Объяснение:
+* Краткое объяснение того, что происходит и почему это происходит.
+  ```py
+  Подготовка примеров для пояснения (при необходимости)
+  ```
+
+  **Вывод:**
+  ```py
+  >>> trigger # пример, облегчающий понимание магии
+  # обоснованный вывод
+  ```
 
+Несколько моментов, которые стоит учитывать при написании примера, -Few things that you can consider while writing an example, +- Если вы решили отправить новый пример без создания issue и обсуждения, пожалуйста, проверьте проект, чтобы убедиться, что в нем уже нет похожих примеров. +- Старайтесь быть последовательными в именах и значениях, которые вы используете для переменных. Например, большинство имен переменных в проекте имеют вид `some_string`, `some_list`, `some_dict` и т.д. Вы увидите много `x` для однобуквенных имен переменных, и `"wtf"` в качестве значений для строк. В проекте нет строгой схемы, как таковой, но вы можете взглянуть на другие примеры, чтобы понять суть. +- Старайтесь быть как можно более креативными, чтобы добавить элемент "сюрприза" во время подготовки примеров. Иногда это может означать написание фрагмента, который здравомыслящий программист никогда бы не написал. +- Также не стесняйтесь добавлять свое имя в список [контрибьюторов](/CONTRIBUTORS.md). -- If you are choosing to submit a new example without creating an issue and discussing, please check the project to make sure there aren't similar examples already. -- Try to be consistent with the namings and the values you use with the variables. For instance, most variable names in the project are along the lines of `some_string`, `some_list`, `some_dict`, etc. You'd see a lot of `x`s for single letter variable names, and `"wtf"` as values for strings. There's no strictly enforced scheme in the project as such, but you can take a glance at other examples to get a gist. -- Try to be as creative as possible to add that element of "surprise" in the setting up part of an example. Sometimes this may mean writing a snippet a sane programmer would never write. -- Also, feel free to add your name to the [contributors list](/CONTRIBUTORS.md). +**Некоторые часто задаваемые вопросы** -**Some FAQs** + Что это такое после каждого заголовка сниппета (###) в README: ? Нужно ли его добавлять вручную или можно игнорировать при создании новых сниппетов? - What is is this after every snippet title (###) in the README: ? Should it be added manually or can it be ignored when creating new snippets? +Это случайный UUID, он используется для идентификации примеров в нескольких переводах проекта. Как контрибьютор, вы не должны беспокоиться о том, как он используется, вы просто должны добавлять новый случайный UUID к новым примерам в этом формате. -That's a random UUID, it is used to keep identify the examples across multiple translations of the project. As a contributor, you don't have to worry about behind the scenes of how it is used, you just have to add a new random UUID to new examples in that format. + Куда следует добавлять новые сниппеты? В начало/в конец раздела? - Where should new snippets be added? Top/bottom of the section, doesn't ? +При определении порядка учитывается множество факторов (зависимость от других примеров, уровень сложности, категория и т.д.). Я бы предложил просто добавить новый пример в конец раздела, который вы считаете более подходящим (или просто добавить его в раздел "Разное"). О его порядке можно будет позаботиться в будущих редакциях. -There are multiple things that are considered to decide the order (the dependency on the other examples, difficulty level, category, etc). I'd suggest simply adding the new example at the bottom of a section you find more fitting (or just add it to the Miscellaneous section). Its order will be taken care of in future revisions. + В чем разница между разделами (первые два очень похожи)? - What's the difference between the sections (the first two feel very similar)? +Раздел "Напрягите мозг" содержит более надуманные примеры, с которыми вы не столкнетесь в реальной жизни, в то время как раздел "Скользкие склоны" содержит примеры, с которыми можно чаще сталкиваться при программировании. -The section "Strain your brain" contains more contrived examples that you may not really encounter in real life, whereas the section "Slippery Slopes" contains examples that have the potential to be encountered more frequently while programming. + Перед оглавлением написано, что для его создания использовался markdown-toc -i README.md --maxdepth 3. Пакет pip markdown-toc не содержит ни флагов -i, ни --maxdepth. Какой пакет имеется в виду, или какая версия этого пакета? + Должна ли новая запись в оглавлении для фрагмента быть создана с помощью вышеуказанной команды или вручную (в случае, если вышеуказанная команда делает больше, чем просто добавляет запись)? - Before the table of contents it says that markdown-toc -i README.md --maxdepth 3 was used to create it. The pip package markdown-toc does not contain either -i or --maxdepth flags. Which package is meant, or what version of that package? - Should the new table of contents entry for the snippet be created with the above command or created manually (in case the above command does more than only add the entry)? +Мы используем пакет [markdown-toc](https://www.npmjs.com/package/markdown-toc) npm для создания ToC (содержание). Однако у него есть некоторые проблемы со специальными символами (не уверен, что они уже исправлены). Чаще всего я просто вставляю ссылку toc вручную в нужное место. Инструмент удобен, когда мне нужно сделать большую перестановку, в остальных случаях просто обновлять toc вручную удобнее. -We use the [markdown-toc](https://www.npmjs.com/package/markdown-toc) npm package to generate ToC. It has some issues with special characters though (I'm not sure if it's fixed yet). More often than not, I just end up inserting the toc link manually at the right place. The tool is handy when I have to big reordering, otherwise just updating toc manually is more convenient imo. - -If you have any questions feel free to ask on [this issue](https://github.com/satwikkansal/wtfpython/issues/269) (thanks to [@LiquidFun](https://github.com/LiquidFun) for starting it). +Если у вас есть вопросы, не стесняйтесь спрашивать в [issue](https://github.com/satwikkansal/wtfpython/issues/269) (спасибо [@LiquidFun](https://github.com/LiquidFun) за ее создание). From fcb70ba7b909b50d4bfa7c51d27a7b46a037d562 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 29 Apr 2024 06:43:47 +0300 Subject: [PATCH 73/83] Change translation for word "section" --- translations/README-ru.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index 9cde024..21dc057 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -21,7 +21,7 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [Структура примера](#структура-примера) - [Применение](#применение) - [👀 Примеры](#-примеры) - - [Секция: Напряги мозги!](#секция-напряги-мозги) + - [Раздел: Напряги мозги!](#раздел-напряги-мозги) - [▶ Первым делом!](#-первым-делом) - [💡 Обьяснение](#-обьяснение) - [▶ Строки иногда ведут себя непредсказуемо](#-строки-иногда-ведут-себя-непредсказуемо) @@ -83,7 +83,7 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [💡 Объяснение:](#-объяснение-28) - [▶ Превышение предела целочисленного преобразования строк](#-превышение-предела-целочисленного-преобразования-строк) - [💡 Объяснение:](#-объяснение-29) - - [Секция: Скользкие склоны](#секция-скользкие-склоны) + - [Раздел: Скользкие склоны](#раздел-скользкие-склоны) - [▶ Изменение словаря во время прохода по нему](#-изменение-словаря-во-время-прохода-по-нему) - [💡 Объяснение:](#-объяснение-30) - [▶ Упрямая операция `del`](#-упрямая-операция-del) @@ -116,7 +116,7 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [💡 Объяснение:](#-объяснение-44) - [▶ Полночи не существует?](#-полночи-не-существует) - [💡 Объяснение:](#-объяснение-45) - - [Секция: Скрытые сокровища!](#секция-скрытые-сокровища) + - [Раздел: Скрытые сокровища!](#раздел-скрытые-сокровища) - [▶ Python, можешь ли ты помочь взлететь?](#-python-можешь-ли-ты-помочь-взлететь) - [💡 Объяснение:](#-объяснение-46) - [▶ `goto`, но почему?](#-goto-но-почему) @@ -135,14 +135,14 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [💡 Объяснение:](#-объяснение-53) - [▶ Давайте искажать](#-давайте-искажать) - [💡 Объяснение:](#-объяснение-54) - - [Секция: Внешность обманчива!](#секция-внешность-обманчива) + - [Раздел: Внешность обманчива!](#раздел-внешность-обманчива) - [▶ Пропускаем строки?](#-пропускаем-строки) - [💡 Объяснение](#-объяснение-55) - [▶ Телепортация](#-телепортация) - [💡 Объяснение:](#-объяснение-56) - [▶ Что-то не так...](#-что-то-не-так) - [💡 Объяснение](#-объяснение-57) - - [Секция: Разное](#секция-разное) + - [Раздел: Разное](#раздел-разное) - [▶ `+=` быстрее `+`](#--быстрее-) - [💡 Объяснение:](#-объяснение-58) - [▶ Сделаем гигантскую строку!](#-сделаем-гигантскую-строку) @@ -218,7 +218,7 @@ wtfpython # 👀 Примеры -## Секция: Напряги мозги! +## Раздел: Напряги мозги! ### ▶ Первым делом! @@ -2079,7 +2079,7 @@ ValueError: Exceeds the limit (4300) for integer string conversion: --- -## Секция: Скользкие склоны +## Раздел: Скользкие склоны ### ▶ Изменение словаря во время прохода по нему @@ -3046,11 +3046,9 @@ if noon_time: --- --- +## Раздел: Скрытые сокровища! - -## Секция: Скрытые сокровища! - -Секция содержит менее известные интересные нюансы работы Python, которые неизвестны большинству новичков. +Раздел содержит менее известные интересные нюансы работы Python, которые неизвестны большинству новичков. ### ▶ Python, можешь ли ты помочь взлететь? @@ -3426,7 +3424,7 @@ AttributeError: 'A' object has no attribute '__variable' --- --- -## Секция: Внешность обманчива! +## Раздел: Внешность обманчива! ### ▶ Пропускаем строки? @@ -3540,7 +3538,7 @@ def square(x): --- --- -## Секция: Разное +## Раздел: Разное ### ▶ `+=` быстрее `+` From a2c5a17ca8346d6285e62b10dd6137cb1f3eb557 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Mon, 29 Apr 2024 06:50:59 +0300 Subject: [PATCH 74/83] Remove extra level of headings from Table of Content --- translations/README-ru.md | 64 --------------------------------------- 1 file changed, 64 deletions(-) diff --git a/translations/README-ru.md b/translations/README-ru.md index 21dc057..402b26a 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -23,138 +23,74 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [👀 Примеры](#-примеры) - [Раздел: Напряги мозги!](#раздел-напряги-мозги) - [▶ Первым делом!](#-первым-делом) - - [💡 Обьяснение](#-обьяснение) - [▶ Строки иногда ведут себя непредсказуемо](#-строки-иногда-ведут-себя-непредсказуемо) - - [💡 Объяснение](#-объяснение) - [▶ Осторожнее с цепочкой операций](#-осторожнее-с-цепочкой-операций) - - [💡 Объяснение:](#-объяснение-1) - [▶ Как не надо использовать оператор `is`](#-как-не-надо-использовать-оператор-is) - - [💡 Объяснение:](#-объяснение-2) - [▶ Мистическое хеширование](#-мистическое-хеширование) - - [💡 Объяснение](#-объяснение-3) - [▶ В глубине души мы все одинаковы.](#-в-глубине-души-мы-все-одинаковы) - - [💡 Объяснение:](#-объяснение-4) - [▶ Беспорядок внутри порядка \*](#-беспорядок-внутри-порядка-) - - [💡 Объяснение:](#-объяснение-5) - [▶ Продолжай пытаться... \*](#-продолжай-пытаться-) - - [💡 Объяснение:](#-объяснение-6) - [▶ Для чего?](#-для-чего) - - [💡 Объяснение:](#-объяснение-7) - [▶ Расхождение во времени исполнения](#-расхождение-во-времени-исполнения) - - [💡 Объяснение](#-объяснение-8) - [▶ `is not ...` не является `is (not ...)`](#-is-not--не-является-is-not-) - - [💡 Объяснение](#-объяснение-9) - [▶ Крестики-нолики, где X побеждает с первой попытки!](#-крестики-нолики-где-x-побеждает-с-первой-попытки) - - [💡 Объяснение:](#-объяснение-10) - [▶ Переменная Шредингера \*](#-переменная-шредингера-) - - [💡 Объяснение:](#-объяснение-11) - [▶ Проблема курицы и яйца \*](#-проблема-курицы-и-яйца-) - - [💡 Объяснение](#-объяснение-12) - [▶ Отношения между подклассами](#-отношения-между-подклассами) - - [💡 Объяснение](#-объяснение-13) - [▶ Равенство и тождество методов](#-равенство-и-тождество-методов) - - [💡 Объяснение](#-объяснение-14) - [▶ All-true-ation (непереводимая игра слов) \*](#-all-true-ation-непереводимая-игра-слов-) - - [💡 Объяснение:](#-объяснение-15) - - [💡 Объяснение:](#-объяснение-16) - [▶ Строки и обратные слэши](#-строки-и-обратные-слэши) - - [💡 Объяснение](#-объяснение-17) - [▶ Не узел! (англ. not knot!)](#-не-узел-англ-not-knot) - - [💡 Объяснение](#-объяснение-18) - [▶ Строки, наполовину обернутые в тройные кавычки](#-строки-наполовину-обернутые-в-тройные-кавычки) - - [💡 Объяснение:](#-объяснение-19) - [▶ Что не так с логическими значениями?](#-что-не-так-с-логическими-значениями) - - [💡 Объяснение:](#-объяснение-20) - [▶ Атрибуты класса и экземпляра](#-атрибуты-класса-и-экземпляра) - - [💡 Объяснение:](#-объяснение-21) - [▶ Возврат None из генератора](#-возврат-none-из-генератора) - - [💡 Объяснение:](#-объяснение-22) - [▶ Yield from возвращает... \*](#-yield-from-возвращает-) - - [💡 Объяснение:](#-объяснение-23) - [▶ Nan-рефлексивность \*](#-nan-рефлексивность-) - - [💡 Объяснение:](#-объяснение-24) - [▶ Изменяем неизменяемое!](#-изменяем-неизменяемое) - - [💡 Объяснение:](#-объяснение-25) - [▶ Исчезающая переменная из внешней области видимости](#-исчезающая-переменная-из-внешней-области-видимости) - - [💡 Объяснение:](#-объяснение-26) - [▶ Загадочное преобразование типов ключей](#-загадочное-преобразование-типов-ключей) - - [💡 Объяснение:](#-объяснение-27) - [▶ Посмотрим, сможете ли вы угадать что здесь?](#-посмотрим-сможете-ли-вы-угадать-что-здесь) - - [💡 Объяснение:](#-объяснение-28) - [▶ Превышение предела целочисленного преобразования строк](#-превышение-предела-целочисленного-преобразования-строк) - - [💡 Объяснение:](#-объяснение-29) - [Раздел: Скользкие склоны](#раздел-скользкие-склоны) - [▶ Изменение словаря во время прохода по нему](#-изменение-словаря-во-время-прохода-по-нему) - - [💡 Объяснение:](#-объяснение-30) - [▶ Упрямая операция `del`](#-упрямая-операция-del) - - [💡 Объяснение:](#-объяснение-31) - [▶ Переменная за пределами видимости](#-переменная-за-пределами-видимости) - - [💡 Объяснение:](#-объяснение-32) - [▶ Удаление элемента списка во время прохода по списку](#-удаление-элемента-списка-во-время-прохода-по-списку) - - [💡 Объяснение:](#-объяснение-33) - [▶ Сжатие итераторов с потерями \*](#-сжатие-итераторов-с-потерями-) - - [💡 Объяснение:](#-объяснение-34) - [▶ Утечка переменных внутри цикла](#-утечка-переменных-внутри-цикла) - - [💡 Объяснение:](#-объяснение-35) - [▶ Остерегайтесь изменяемых аргументов по умолчанию!](#-остерегайтесь-изменяемых-аргументов-по-умолчанию) - - [💡 Объяснение:](#-объяснение-36) - [▶ Ловля исключений](#-ловля-исключений) - - [💡 Объяснение](#-объяснение-37) - [▶ Одни и те же операнды, разная история!](#-одни-и-те-же-операнды-разная-история) - - [💡 Объяснение:](#-объяснение-38) - [▶ Разрешение имен игнорирует область видимости класса](#-разрешение-имен-игнорирует-область-видимости-класса) - - [💡 Объяснение](#-объяснение-39) - [▶ Округляясь как банкир \*](#-округляясь-как-банкир-) - - [💡 Объяснение:](#-объяснение-40) - [▶ Иголки в стоге сена \*](#-иголки-в-стоге-сена-) - - [💡 Объяснение:](#-объяснение-41) - [▶ Сплиты (splitsies) \*](#-сплиты-splitsies-) - - [💡 Объяснение](#-объяснение-42) - [▶ Подстановочное импортирование (wild imports) \*](#-подстановочное-импортирование-wild-imports-) - - [💡 Объяснение:](#-объяснение-43) - [▶ Все ли отсортировано? \*](#-все-ли-отсортировано-) - - [💡 Объяснение:](#-объяснение-44) - [▶ Полночи не существует?](#-полночи-не-существует) - - [💡 Объяснение:](#-объяснение-45) - [Раздел: Скрытые сокровища!](#раздел-скрытые-сокровища) - [▶ Python, можешь ли ты помочь взлететь?](#-python-можешь-ли-ты-помочь-взлететь) - - [💡 Объяснение:](#-объяснение-46) - [▶ `goto`, но почему?](#-goto-но-почему) - - [💡 Объяснение:](#-объяснение-47) - [▶ Держитесь!](#-держитесь) - - [💡 Объяснение:](#-объяснение-48) - [▶ Давайте познакомимся с дружелюбным Дядей Барри](#-давайте-познакомимся-с-дружелюбным-дядей-барри) - - [💡 Объяснение:](#-объяснение-49) - [▶ Даже Python понимает, что любовь - это сложно.](#-даже-python-понимает-что-любовь---это-сложно) - - [💡 Объяснение:](#-объяснение-50) - [▶ Да, оно существует!](#-да-оно-существует) - - [💡 Объяснение:](#-объяснение-51) - [▶ Многоточие \*](#-многоточие-) - - [💡 Объяснение](#-объяснение-52) - [▶ Писконечность (Inpinity)](#-писконечность-inpinity) - - [💡 Объяснение:](#-объяснение-53) - [▶ Давайте искажать](#-давайте-искажать) - - [💡 Объяснение:](#-объяснение-54) - [Раздел: Внешность обманчива!](#раздел-внешность-обманчива) - [▶ Пропускаем строки?](#-пропускаем-строки) - - [💡 Объяснение](#-объяснение-55) - [▶ Телепортация](#-телепортация) - - [💡 Объяснение:](#-объяснение-56) - [▶ Что-то не так...](#-что-то-не-так) - - [💡 Объяснение](#-объяснение-57) - [Раздел: Разное](#раздел-разное) - [▶ `+=` быстрее `+`](#--быстрее-) - - [💡 Объяснение:](#-объяснение-58) - [▶ Сделаем гигантскую строку!](#-сделаем-гигантскую-строку) - - [💡 Объяснение](#-объяснение-59) - [▶ Замедляем поиск по `dict` \*](#-замедляем-поиск-по-dict-) - - [💡 Объяснение:](#-объяснение-60) - [▶ Раздуваем экземпляры словарей \*](#-раздуваем-экземпляры-словарей-) - - [💡 Объяснение:](#-объяснение-61) - [▶ Минорное \*](#-минорное-) - [Вклад в проект](#вклад-в-проект) - [Благодарности](#благодарности) - - [Несколько хороших ссылок!](#несколько-хороших-ссылок) - [🎓 Лицензия](#-лицензия) - [Удиви своих друзей!](#удиви-своих-друзей) - [Нужна PDF версия?](#нужна-pdf-версия) From 6f35f0046194bcb907403a8c008b0ffe6cc1cc4c Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Fri, 3 May 2024 09:38:55 +0300 Subject: [PATCH 75/83] Translate Code of Conduct --- code-of-conduct.md | 106 ++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 55 deletions(-) diff --git a/code-of-conduct.md b/code-of-conduct.md index 558af4a..2aa521f 100644 --- a/code-of-conduct.md +++ b/code-of-conduct.md @@ -1,74 +1,70 @@ -# Contributor Covenant Code of Conduct +# Кодекс Поведения участника -## Our Pledge +## Наши обязательства -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, race, -religion, or sexual identity and orientation. +Мы, как участники, авторы и лидеры обязуемся сделать участие в сообществе +свободным от притеснений для всех, независимо от возраста, телосложения, +видимых или невидимых ограничений способности, этнической принадлежности, +половых признаков, гендерной идентичности и выражения, уровня опыта, +образования, социально-экономического статуса, национальности, внешности, +расы, религии, или сексуальной идентичности и ориентации. -## Our Standards +Мы обещаем действовать и взаимодействовать таким образом, чтобы вносить вклад в открытое, +дружелюбное, многообразное, инклюзивное и здоровое сообщество. -Examples of behavior that contributes to creating a positive environment -include: +## Наши стандарты -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +Примеры поведения, создающие условия для благоприятных взаимоотношений включают в себя: -Examples of unacceptable behavior by participants include: +* Проявление доброты и эмпатии к другим участникам проекта +* Уважение к чужой точке зрения и опыту +* Конструктивная критика и принятие конструктивной критики +* Принятие ответственности, принесение извинений тем, кто пострадал от наших ошибок + и извлечение уроков из опыта +* Ориентирование на то, что лучше подходит для сообщества, а не только для нас лично -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +Примеры неприемлемого поведения участников включают в себя: -## Our Responsibilities +* Использование выражений или изображений сексуального характера и нежелательное сексуальное внимание или домогательство в любой форме +* Троллинг, оскорбительные или уничижительные комментарии, переход на личности или затрагивание политических убеждений +* Публичное или приватное домогательство +* Публикация личной информации других лиц, например, физического или электронного адреса, без явного разрешения +* Иное поведение, которое обоснованно считать неуместным в профессиональной обстановке -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +## Обязанности -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Лидеры сообщества отвечают за разъяснение и применение наших стандартов приемлемого +поведения и будут предпринимать соответствующие и честные меры по исправлению положения +в ответ на любое поведение, которое они сочтут неприемлемым, угрожающим, оскорбительным или вредным. -## Scope +Лидеры сообщества обладают правом и обязанностью удалять, редактировать или отклонять +комментарии, коммиты, код, изменения в вики, вопросы и другой вклад, который не совпадает +с Кодексом Поведения, и предоставят причины принятого решения, когда сочтут нужным. -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +## Область применения -## Enforcement +Данный Кодекс Поведения применим во всех публичных физических и цифровых пространства сообщества, +а также когда человек официально представляет сообщество в публичных местах. +Примеры представления проекта или сообщества включают использование официальной электронной почты, +публикации в официальном аккаунте в социальных сетях, +или упоминания как представителя в онлайн или офлайн мероприятии. -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at [INSERT EMAIL ADDRESS]. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +## Приведение в исполнение -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +О случаях домогательства, а так же оскорбительного или иного другого неприемлемого +поведения можно сообщить ответственным лидерам сообщества с помощью email. +Все жалобы будут рассмотрены и расследованы оперативно и беспристрастно. -## Attribution +Все лидеры сообщества обязаны уважать неприкосновенность частной жизни и личную +неприкосновенность автора сообщения. -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +## Атрибуция + +Данный Кодекс Поведения основан на [Кодекс Поведения участника][homepage], +версии 2.0, доступной по адресу +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Принципы Воздействия в Сообществе были вдохновлены [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org - From b1684aaf39a5277e607c28f1c90b6c7cacc602eb Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 4 May 2024 18:58:57 +0300 Subject: [PATCH 76/83] Move translated files to translations/ru-russian --- CONTRIBUTING.md | 70 ++++++------ CONTRIBUTORS.md | 12 +- code-of-conduct.md | 105 +++++++++--------- translations/ru-russian/CONTIRBUTING.md | 63 +++++++++++ translations/ru-russian/CONTRIBUTORS.md | 42 +++++++ .../{README-ru.md => ru-russian/README.md} | 0 translations/ru-russian/code-of-conduct.md | 70 ++++++++++++ 7 files changed, 270 insertions(+), 92 deletions(-) create mode 100644 translations/ru-russian/CONTIRBUTING.md create mode 100644 translations/ru-russian/CONTRIBUTORS.md rename translations/{README-ru.md => ru-russian/README.md} (100%) create mode 100644 translations/ru-russian/code-of-conduct.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a542814..e6863e3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,63 +1,63 @@ -Приветствуются все виды изменений. Не стесняйтесь предлагать броские и смешные названия для существующих примеров. Цель - сделать эту коллекцию как можно более интересной для чтения. Вот несколько способов, с помощью которых вы можете внести свой вклад, +All kinds of patches are welcome. Feel free to even suggest some catchy and funny titles for the existing Examples. The goal is to make this collection as interesting to read as possible. Here are a few ways through which you can contribute, -- Если вы заинтересованы в переводе проекта на другой язык (некоторые люди уже делали это в прошлом), пожалуйста, не стесняйтесь открыть тему и дайте мне знать, если вам нужна какая-либо помощь. -- Если изменения, которые вы предлагаете, значительны, то создание issue перед внесением изменений будет оценено по достоинству. Если вы хотите поработать над issue (это очень рекомендуется), выразите свою заинтересованность и вы будете назначены исполнителем. -- Если вы добавляете новый пример, настоятельно рекомендуется создать issue, чтобы обсудить ее перед отправкой изменений. Для добавления нового примера вы можете использовать следующий шаблон: +- If you are interested in translating the project to another language (some people have done that in the past), please feel free to open up an issue, and let me know if you need any kind of help. +- If the changes you suggest are significant, filing an issue before submitting the actual patch will be appreciated. If you'd like to work on the issue (highly encouraged), you can mention that you're interested in working on it while creating the issue and get assigned to it. +- If you're adding a new example, it is highly recommended to create an issue to discuss it before submitting a patch. You can use the following template for adding a new example:
-### ▶ Какое-то причудливое название. *
-* в конце названия означает, что пример был добавлен недавно.
+### ▶ Some fancy Title *
+The asterisk at the end of the title indicates the example was not present in the first release and has been recently added.
 
 ```py
-# Подготовка кода.
-# Подготовка к волшебству...
+# Setting up the code.
+# Preparation for the magic...
 ```
 
-**Вывод (версия Python):**
+**Output (Python version):**
 ```py
 >>> triggering_statement
-Вероятно, неожиданный вывод
-
+Probably unexpected output
 ```
-(Необязательно): Одна строка, описывающая неожиданный вывод.
+(Optional): One line describing the unexpected output.
 
-#### 💡 Объяснение:
-* Краткое объяснение того, что происходит и почему это происходит.
+#### 💡 Explanation:
+* Brief explanation of what's happening and why is it happening.
   ```py
-  Подготовка примеров для пояснения (при необходимости)
+  Setting up examples for clarification (if necessary)
   ```
-
-  **Вывод:**
+  **Output:**
   ```py
-  >>> trigger # пример, облегчающий понимание магии
-  # обоснованный вывод
+  >>> trigger # some example that makes it easy to unveil the magic
+  # some justified output
   ```
+```
 
-Несколько моментов, которые стоит учитывать при написании примера, -- Если вы решили отправить новый пример без создания issue и обсуждения, пожалуйста, проверьте проект, чтобы убедиться, что в нем уже нет похожих примеров. -- Старайтесь быть последовательными в именах и значениях, которые вы используете для переменных. Например, большинство имен переменных в проекте имеют вид `some_string`, `some_list`, `some_dict` и т.д. Вы увидите много `x` для однобуквенных имен переменных, и `"wtf"` в качестве значений для строк. В проекте нет строгой схемы, как таковой, но вы можете взглянуть на другие примеры, чтобы понять суть. -- Старайтесь быть как можно более креативными, чтобы добавить элемент "сюрприза" во время подготовки примеров. Иногда это может означать написание фрагмента, который здравомыслящий программист никогда бы не написал. -- Также не стесняйтесь добавлять свое имя в список [контрибьюторов](/CONTRIBUTORS.md). +Few things that you can consider while writing an example, -**Некоторые часто задаваемые вопросы** +- If you are choosing to submit a new example without creating an issue and discussing, please check the project to make sure there aren't similar examples already. +- Try to be consistent with the namings and the values you use with the variables. For instance, most variable names in the project are along the lines of `some_string`, `some_list`, `some_dict`, etc. You'd see a lot of `x`s for single letter variable names, and `"wtf"` as values for strings. There's no strictly enforced scheme in the project as such, but you can take a glance at other examples to get a gist. +- Try to be as creative as possible to add that element of "surprise" in the setting up part of an example. Sometimes this may mean writing a snippet a sane programmer would never write. +- Also, feel free to add your name to the [contributors list](/CONTRIBUTORS.md). - Что это такое после каждого заголовка сниппета (###) в README: ? Нужно ли его добавлять вручную или можно игнорировать при создании новых сниппетов? +**Some FAQs** -Это случайный UUID, он используется для идентификации примеров в нескольких переводах проекта. Как контрибьютор, вы не должны беспокоиться о том, как он используется, вы просто должны добавлять новый случайный UUID к новым примерам в этом формате. + What is is this after every snippet title (###) in the README: ? Should it be added manually or can it be ignored when creating new snippets? - Куда следует добавлять новые сниппеты? В начало/в конец раздела? +That's a random UUID, it is used to keep identify the examples across multiple translations of the project. As a contributor, you don't have to worry about behind the scenes of how it is used, you just have to add a new random UUID to new examples in that format. -При определении порядка учитывается множество факторов (зависимость от других примеров, уровень сложности, категория и т.д.). Я бы предложил просто добавить новый пример в конец раздела, который вы считаете более подходящим (или просто добавить его в раздел "Разное"). О его порядке можно будет позаботиться в будущих редакциях. + Where should new snippets be added? Top/bottom of the section, doesn't ? - В чем разница между разделами (первые два очень похожи)? +There are multiple things that are considered to decide the order (the dependency on the other examples, difficulty level, category, etc). I'd suggest simply adding the new example at the bottom of a section you find more fitting (or just add it to the Miscellaneous section). Its order will be taken care of in future revisions. -Раздел "Напрягите мозг" содержит более надуманные примеры, с которыми вы не столкнетесь в реальной жизни, в то время как раздел "Скользкие склоны" содержит примеры, с которыми можно чаще сталкиваться при программировании. + What's the difference between the sections (the first two feel very similar)? - Перед оглавлением написано, что для его создания использовался markdown-toc -i README.md --maxdepth 3. Пакет pip markdown-toc не содержит ни флагов -i, ни --maxdepth. Какой пакет имеется в виду, или какая версия этого пакета? - Должна ли новая запись в оглавлении для фрагмента быть создана с помощью вышеуказанной команды или вручную (в случае, если вышеуказанная команда делает больше, чем просто добавляет запись)? +The section "Strain your brain" contains more contrived examples that you may not really encounter in real life, whereas the section "Slippery Slopes" contains examples that have the potential to be encountered more frequently while programming. -Мы используем пакет [markdown-toc](https://www.npmjs.com/package/markdown-toc) npm для создания ToC (содержание). Однако у него есть некоторые проблемы со специальными символами (не уверен, что они уже исправлены). Чаще всего я просто вставляю ссылку toc вручную в нужное место. Инструмент удобен, когда мне нужно сделать большую перестановку, в остальных случаях просто обновлять toc вручную удобнее. + Before the table of contents it says that markdown-toc -i README.md --maxdepth 3 was used to create it. The pip package markdown-toc does not contain either -i or --maxdepth flags. Which package is meant, or what version of that package? + Should the new table of contents entry for the snippet be created with the above command or created manually (in case the above command does more than only add the entry)? -Если у вас есть вопросы, не стесняйтесь спрашивать в [issue](https://github.com/satwikkansal/wtfpython/issues/269) (спасибо [@LiquidFun](https://github.com/LiquidFun) за ее создание). +We use the [markdown-toc](https://www.npmjs.com/package/markdown-toc) npm package to generate ToC. It has some issues with special characters though (I'm not sure if it's fixed yet). More often than not, I just end up inserting the toc link manually at the right place. The tool is handy when I have to big reordering, otherwise just updating toc manually is more convenient imo. + +If you have any questions feel free to ask on [this issue](https://github.com/satwikkansal/wtfpython/issues/269) (thanks to [@LiquidFun](https://github.com/LiquidFun) for starting it). \ No newline at end of file diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 8a22a49..eb62496 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,6 +1,6 @@ -Ниже перечислены (без определенного порядка) замечательные люди, которые внесли вклад в развитие wtfpython. +Following are the wonderful people (in no specific order) who have contributed their examples to wtfpython. -| Автор | Github | Issues | +| Contributor | Github | Issues | |-------------|--------|--------| | Lucas-C | [Lucas-C](https://github.com/Lucas-C) | [#36](https://github.com/satwikkansal/wtfpython/issues/36) | | MittalAshok | [MittalAshok](https://github.com/MittalAshok) | [#23](https://github.com/satwikkansal/wtfpython/issues/23) | @@ -28,15 +28,15 @@ --- -**Переводчики** +**Translations** -| Переводчик | Github | Язык | +| Translator | Github | Language | |-------------|--------|--------| | leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [Chinese](https://github.com/leisurelicht/wtfpython-cn) | | vuduclyunitn | [vuduclyunitn](https://github.com/vuduclyunitn) | [Vietnamese](https://github.com/vuduclyunitn/wtfptyhon-vi) | | José De Freitas | [JoseDeFreitas](https://github.com/JoseDeFreitas) | [Spanish](https://github.com/JoseDeFreitas/wtfpython-es) | | Vadim Nifadev | [nifadyev](https://github.com/nifadyev) | [Russian](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) | -Спасибо всем за ваше время и за то, что делаете wtfpython еще более потрясающим! :smile: +Thank you all for your time and making wtfpython more awesome! :smile: -PS: Этот список обновляется после каждого крупного релиза, если я забыл добавить сюда ваш вклад, пожалуйста, не стесняйтесь сделать Pull request. +PS: This list is updated after every major release, if I forgot to add your contribution here, please feel free to raise a Pull request. \ No newline at end of file diff --git a/code-of-conduct.md b/code-of-conduct.md index 2aa521f..45904fe 100644 --- a/code-of-conduct.md +++ b/code-of-conduct.md @@ -1,70 +1,73 @@ -# Кодекс Поведения участника +# Contributor Covenant Code of Conduct -## Наши обязательства +## Our Pledge -Мы, как участники, авторы и лидеры обязуемся сделать участие в сообществе -свободным от притеснений для всех, независимо от возраста, телосложения, -видимых или невидимых ограничений способности, этнической принадлежности, -половых признаков, гендерной идентичности и выражения, уровня опыта, -образования, социально-экономического статуса, национальности, внешности, -расы, религии, или сексуальной идентичности и ориентации. +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. -Мы обещаем действовать и взаимодействовать таким образом, чтобы вносить вклад в открытое, -дружелюбное, многообразное, инклюзивное и здоровое сообщество. +## Our Standards -## Наши стандарты +Examples of behavior that contributes to creating a positive environment +include: -Примеры поведения, создающие условия для благоприятных взаимоотношений включают в себя: +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members -* Проявление доброты и эмпатии к другим участникам проекта -* Уважение к чужой точке зрения и опыту -* Конструктивная критика и принятие конструктивной критики -* Принятие ответственности, принесение извинений тем, кто пострадал от наших ошибок - и извлечение уроков из опыта -* Ориентирование на то, что лучше подходит для сообщества, а не только для нас лично +Examples of unacceptable behavior by participants include: -Примеры неприемлемого поведения участников включают в себя: +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting -* Использование выражений или изображений сексуального характера и нежелательное сексуальное внимание или домогательство в любой форме -* Троллинг, оскорбительные или уничижительные комментарии, переход на личности или затрагивание политических убеждений -* Публичное или приватное домогательство -* Публикация личной информации других лиц, например, физического или электронного адреса, без явного разрешения -* Иное поведение, которое обоснованно считать неуместным в профессиональной обстановке +## Our Responsibilities -## Обязанности +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. -Лидеры сообщества отвечают за разъяснение и применение наших стандартов приемлемого -поведения и будут предпринимать соответствующие и честные меры по исправлению положения -в ответ на любое поведение, которое они сочтут неприемлемым, угрожающим, оскорбительным или вредным. +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. -Лидеры сообщества обладают правом и обязанностью удалять, редактировать или отклонять -комментарии, коммиты, код, изменения в вики, вопросы и другой вклад, который не совпадает -с Кодексом Поведения, и предоставят причины принятого решения, когда сочтут нужным. +## Scope -## Область применения +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. -Данный Кодекс Поведения применим во всех публичных физических и цифровых пространства сообщества, -а также когда человек официально представляет сообщество в публичных местах. -Примеры представления проекта или сообщества включают использование официальной электронной почты, -публикации в официальном аккаунте в социальных сетях, -или упоминания как представителя в онлайн или офлайн мероприятии. +## Enforcement -## Приведение в исполнение +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [INSERT EMAIL ADDRESS]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. -О случаях домогательства, а так же оскорбительного или иного другого неприемлемого -поведения можно сообщить ответственным лидерам сообщества с помощью email. -Все жалобы будут рассмотрены и расследованы оперативно и беспристрастно. +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. -Все лидеры сообщества обязаны уважать неприкосновенность частной жизни и личную -неприкосновенность автора сообщения. +## Attribution -## Атрибуция - -Данный Кодекс Поведения основан на [Кодекс Поведения участника][homepage], -версии 2.0, доступной по адресу -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Принципы Воздействия в Сообществе были вдохновлены [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org diff --git a/translations/ru-russian/CONTIRBUTING.md b/translations/ru-russian/CONTIRBUTING.md new file mode 100644 index 0000000..a542814 --- /dev/null +++ b/translations/ru-russian/CONTIRBUTING.md @@ -0,0 +1,63 @@ +Приветствуются все виды изменений. Не стесняйтесь предлагать броские и смешные названия для существующих примеров. Цель - сделать эту коллекцию как можно более интересной для чтения. Вот несколько способов, с помощью которых вы можете внести свой вклад, + +- Если вы заинтересованы в переводе проекта на другой язык (некоторые люди уже делали это в прошлом), пожалуйста, не стесняйтесь открыть тему и дайте мне знать, если вам нужна какая-либо помощь. +- Если изменения, которые вы предлагаете, значительны, то создание issue перед внесением изменений будет оценено по достоинству. Если вы хотите поработать над issue (это очень рекомендуется), выразите свою заинтересованность и вы будете назначены исполнителем. +- Если вы добавляете новый пример, настоятельно рекомендуется создать issue, чтобы обсудить ее перед отправкой изменений. Для добавления нового примера вы можете использовать следующий шаблон: + +
+### ▶ Какое-то причудливое название. *
+* в конце названия означает, что пример был добавлен недавно.
+
+```py
+# Подготовка кода.
+# Подготовка к волшебству...
+```
+
+**Вывод (версия Python):**
+```py
+>>> triggering_statement
+Вероятно, неожиданный вывод
+
+```
+(Необязательно): Одна строка, описывающая неожиданный вывод.
+
+#### 💡 Объяснение:
+* Краткое объяснение того, что происходит и почему это происходит.
+  ```py
+  Подготовка примеров для пояснения (при необходимости)
+  ```
+
+  **Вывод:**
+  ```py
+  >>> trigger # пример, облегчающий понимание магии
+  # обоснованный вывод
+  ```
+
+ +Несколько моментов, которые стоит учитывать при написании примера, + +- Если вы решили отправить новый пример без создания issue и обсуждения, пожалуйста, проверьте проект, чтобы убедиться, что в нем уже нет похожих примеров. +- Старайтесь быть последовательными в именах и значениях, которые вы используете для переменных. Например, большинство имен переменных в проекте имеют вид `some_string`, `some_list`, `some_dict` и т.д. Вы увидите много `x` для однобуквенных имен переменных, и `"wtf"` в качестве значений для строк. В проекте нет строгой схемы, как таковой, но вы можете взглянуть на другие примеры, чтобы понять суть. +- Старайтесь быть как можно более креативными, чтобы добавить элемент "сюрприза" во время подготовки примеров. Иногда это может означать написание фрагмента, который здравомыслящий программист никогда бы не написал. +- Также не стесняйтесь добавлять свое имя в список [контрибьюторов](/CONTRIBUTORS.md). + +**Некоторые часто задаваемые вопросы** + + Что это такое после каждого заголовка сниппета (###) в README: ? Нужно ли его добавлять вручную или можно игнорировать при создании новых сниппетов? + +Это случайный UUID, он используется для идентификации примеров в нескольких переводах проекта. Как контрибьютор, вы не должны беспокоиться о том, как он используется, вы просто должны добавлять новый случайный UUID к новым примерам в этом формате. + + Куда следует добавлять новые сниппеты? В начало/в конец раздела? + +При определении порядка учитывается множество факторов (зависимость от других примеров, уровень сложности, категория и т.д.). Я бы предложил просто добавить новый пример в конец раздела, который вы считаете более подходящим (или просто добавить его в раздел "Разное"). О его порядке можно будет позаботиться в будущих редакциях. + + В чем разница между разделами (первые два очень похожи)? + +Раздел "Напрягите мозг" содержит более надуманные примеры, с которыми вы не столкнетесь в реальной жизни, в то время как раздел "Скользкие склоны" содержит примеры, с которыми можно чаще сталкиваться при программировании. + + Перед оглавлением написано, что для его создания использовался markdown-toc -i README.md --maxdepth 3. Пакет pip markdown-toc не содержит ни флагов -i, ни --maxdepth. Какой пакет имеется в виду, или какая версия этого пакета? + Должна ли новая запись в оглавлении для фрагмента быть создана с помощью вышеуказанной команды или вручную (в случае, если вышеуказанная команда делает больше, чем просто добавляет запись)? + +Мы используем пакет [markdown-toc](https://www.npmjs.com/package/markdown-toc) npm для создания ToC (содержание). Однако у него есть некоторые проблемы со специальными символами (не уверен, что они уже исправлены). Чаще всего я просто вставляю ссылку toc вручную в нужное место. Инструмент удобен, когда мне нужно сделать большую перестановку, в остальных случаях просто обновлять toc вручную удобнее. + +Если у вас есть вопросы, не стесняйтесь спрашивать в [issue](https://github.com/satwikkansal/wtfpython/issues/269) (спасибо [@LiquidFun](https://github.com/LiquidFun) за ее создание). diff --git a/translations/ru-russian/CONTRIBUTORS.md b/translations/ru-russian/CONTRIBUTORS.md new file mode 100644 index 0000000..8a22a49 --- /dev/null +++ b/translations/ru-russian/CONTRIBUTORS.md @@ -0,0 +1,42 @@ +Ниже перечислены (без определенного порядка) замечательные люди, которые внесли вклад в развитие wtfpython. + +| Автор | Github | Issues | +|-------------|--------|--------| +| Lucas-C | [Lucas-C](https://github.com/Lucas-C) | [#36](https://github.com/satwikkansal/wtfpython/issues/36) | +| MittalAshok | [MittalAshok](https://github.com/MittalAshok) | [#23](https://github.com/satwikkansal/wtfpython/issues/23) | +| asottile | [asottile](https://github.com/asottile) | [#40](https://github.com/satwikkansal/wtfpython/issues/40) | +| MostAwesomeDude | [MostAwesomeDude](https://github.com/MostAwesomeDude) | [#1](https://github.com/satwikkansal/wtfpython/issues/1) | +| tukkek | [tukkek](https://github.com/tukkek) | [#11](https://github.com/satwikkansal/wtfpython/issues/11), [#26](https://github.com/satwikkansal/wtfpython/issues/26) | +| PiaFraus | [PiaFraus](https://github.com/PiaFraus) | [#9](https://github.com/satwikkansal/wtfpython/issues/9) | +| chris-rands | [chris-rands](https://github.com/chris-rands) | [#32](https://github.com/satwikkansal/wtfpython/issues/32) | +| sohaibfarooqi | [sohaibfarooqi](https://github.com/sohaibfarooqi) | [#63](https://github.com/satwikkansal/wtfpython/issues/63) | +| ipid | [ipid](https://github.com/ipid) | [#145](https://github.com/satwikkansal/wtfpython/issues/145) | +| roshnet | [roshnet](https://github.com/roshnet) | [#140](https://github.com/satwikkansal/wtfpython/issues/140) | +| daidai21 | [daidai21](https://github.com/daidai21) | [#137](https://github.com/satwikkansal/wtfpython/issues/137) | +| scidam | [scidam](https://github.com/scidam) | [#136](https://github.com/satwikkansal/wtfpython/issues/136) | +| pmjpawelec | [pmjpawelec](https://github.com/pmjpawelec) | [#121](https://github.com/satwikkansal/wtfpython/issues/121) | +| leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [#112](https://github.com/satwikkansal/wtfpython/issues/112) | +| mishaturnbull | [mishaturnbull](https://github.com/mishaturnbull) | [#108](https://github.com/satwikkansal/wtfpython/issues/108) | +| MuseBoy | [MuseBoy](https://github.com/MuseBoy) | [#101](https://github.com/satwikkansal/wtfpython/issues/101) | +| Ghost account | N/A | [#96](https://github.com/satwikkansal/wtfpython/issues/96) | +| koddo | [koddo](https://github.com/koddo) | [#80](https://github.com/satwikkansal/wtfpython/issues/80), [#73](https://github.com/satwikkansal/wtfpython/issues/73) | +| jab | [jab](https://github.com/jab) | [#77](https://github.com/satwikkansal/wtfpython/issues/77) | +| Jongy | [Jongy](https://github.com/Jongy) | [#208](https://github.com/satwikkansal/wtfpython/issues/208), [#210](https://github.com/satwikkansal/wtfpython/issues/210), [#233](https://github.com/satwikkansal/wtfpython/issues/233) | +| Diptangsu Goswami | [diptangsu](https://github.com/diptangsu) | [#193](https://github.com/satwikkansal/wtfpython/issues/193) | +| Charles | [charles-l](https://github.com/charles-l) | [#245](https://github.com/satwikkansal/wtfpython/issues/245) | +| LiquidFun | [LiquidFun](https://github.com/LiquidFun) | [#267](https://github.com/satwikkansal/wtfpython/issues/267) | + +--- + +**Переводчики** + +| Переводчик | Github | Язык | +|-------------|--------|--------| +| leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [Chinese](https://github.com/leisurelicht/wtfpython-cn) | +| vuduclyunitn | [vuduclyunitn](https://github.com/vuduclyunitn) | [Vietnamese](https://github.com/vuduclyunitn/wtfptyhon-vi) | +| José De Freitas | [JoseDeFreitas](https://github.com/JoseDeFreitas) | [Spanish](https://github.com/JoseDeFreitas/wtfpython-es) | +| Vadim Nifadev | [nifadyev](https://github.com/nifadyev) | [Russian](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) | + +Спасибо всем за ваше время и за то, что делаете wtfpython еще более потрясающим! :smile: + +PS: Этот список обновляется после каждого крупного релиза, если я забыл добавить сюда ваш вклад, пожалуйста, не стесняйтесь сделать Pull request. diff --git a/translations/README-ru.md b/translations/ru-russian/README.md similarity index 100% rename from translations/README-ru.md rename to translations/ru-russian/README.md diff --git a/translations/ru-russian/code-of-conduct.md b/translations/ru-russian/code-of-conduct.md new file mode 100644 index 0000000..2aa521f --- /dev/null +++ b/translations/ru-russian/code-of-conduct.md @@ -0,0 +1,70 @@ +# Кодекс Поведения участника + +## Наши обязательства + +Мы, как участники, авторы и лидеры обязуемся сделать участие в сообществе +свободным от притеснений для всех, независимо от возраста, телосложения, +видимых или невидимых ограничений способности, этнической принадлежности, +половых признаков, гендерной идентичности и выражения, уровня опыта, +образования, социально-экономического статуса, национальности, внешности, +расы, религии, или сексуальной идентичности и ориентации. + +Мы обещаем действовать и взаимодействовать таким образом, чтобы вносить вклад в открытое, +дружелюбное, многообразное, инклюзивное и здоровое сообщество. + +## Наши стандарты + +Примеры поведения, создающие условия для благоприятных взаимоотношений включают в себя: + +* Проявление доброты и эмпатии к другим участникам проекта +* Уважение к чужой точке зрения и опыту +* Конструктивная критика и принятие конструктивной критики +* Принятие ответственности, принесение извинений тем, кто пострадал от наших ошибок + и извлечение уроков из опыта +* Ориентирование на то, что лучше подходит для сообщества, а не только для нас лично + +Примеры неприемлемого поведения участников включают в себя: + +* Использование выражений или изображений сексуального характера и нежелательное сексуальное внимание или домогательство в любой форме +* Троллинг, оскорбительные или уничижительные комментарии, переход на личности или затрагивание политических убеждений +* Публичное или приватное домогательство +* Публикация личной информации других лиц, например, физического или электронного адреса, без явного разрешения +* Иное поведение, которое обоснованно считать неуместным в профессиональной обстановке + +## Обязанности + +Лидеры сообщества отвечают за разъяснение и применение наших стандартов приемлемого +поведения и будут предпринимать соответствующие и честные меры по исправлению положения +в ответ на любое поведение, которое они сочтут неприемлемым, угрожающим, оскорбительным или вредным. + +Лидеры сообщества обладают правом и обязанностью удалять, редактировать или отклонять +комментарии, коммиты, код, изменения в вики, вопросы и другой вклад, который не совпадает +с Кодексом Поведения, и предоставят причины принятого решения, когда сочтут нужным. + +## Область применения + +Данный Кодекс Поведения применим во всех публичных физических и цифровых пространства сообщества, +а также когда человек официально представляет сообщество в публичных местах. +Примеры представления проекта или сообщества включают использование официальной электронной почты, +публикации в официальном аккаунте в социальных сетях, +или упоминания как представителя в онлайн или офлайн мероприятии. + +## Приведение в исполнение + +О случаях домогательства, а так же оскорбительного или иного другого неприемлемого +поведения можно сообщить ответственным лидерам сообщества с помощью email. +Все жалобы будут рассмотрены и расследованы оперативно и беспристрастно. + +Все лидеры сообщества обязаны уважать неприкосновенность частной жизни и личную +неприкосновенность автора сообщения. + +## Атрибуция + +Данный Кодекс Поведения основан на [Кодекс Поведения участника][homepage], +версии 2.0, доступной по адресу +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Принципы Воздействия в Сообществе были вдохновлены [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org From 16628ba0711a686c45a9d59b3c3a67bb30edab8c Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 4 May 2024 19:05:24 +0300 Subject: [PATCH 77/83] Minor changes --- CONTRIBUTING.md | 2 +- CONTRIBUTORS.md | 2 +- code-of-conduct.md | 1 + translations/ru-russian/{CONTIRBUTING.md => CONTRIBUTING.md} | 0 4 files changed, 3 insertions(+), 2 deletions(-) mode change 100644 => 100755 CONTRIBUTING.md mode change 100644 => 100755 code-of-conduct.md rename translations/ru-russian/{CONTIRBUTING.md => CONTRIBUTING.md} (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md old mode 100644 new mode 100755 index e6863e3..dd9049d --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,4 +60,4 @@ The section "Strain your brain" contains more contrived examples that you may no We use the [markdown-toc](https://www.npmjs.com/package/markdown-toc) npm package to generate ToC. It has some issues with special characters though (I'm not sure if it's fixed yet). More often than not, I just end up inserting the toc link manually at the right place. The tool is handy when I have to big reordering, otherwise just updating toc manually is more convenient imo. -If you have any questions feel free to ask on [this issue](https://github.com/satwikkansal/wtfpython/issues/269) (thanks to [@LiquidFun](https://github.com/LiquidFun) for starting it). \ No newline at end of file +If you have any questions feel free to ask on [this issue](https://github.com/satwikkansal/wtfpython/issues/269) (thanks to [@LiquidFun](https://github.com/LiquidFun) for starting it). diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index eb62496..68d5176 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -39,4 +39,4 @@ Following are the wonderful people (in no specific order) who have contributed t Thank you all for your time and making wtfpython more awesome! :smile: -PS: This list is updated after every major release, if I forgot to add your contribution here, please feel free to raise a Pull request. \ No newline at end of file +PS: This list is updated after every major release, if I forgot to add your contribution here, please feel free to raise a Pull request. diff --git a/code-of-conduct.md b/code-of-conduct.md old mode 100644 new mode 100755 index 45904fe..558af4a --- a/code-of-conduct.md +++ b/code-of-conduct.md @@ -71,3 +71,4 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], versi available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org + diff --git a/translations/ru-russian/CONTIRBUTING.md b/translations/ru-russian/CONTRIBUTING.md similarity index 100% rename from translations/ru-russian/CONTIRBUTING.md rename to translations/ru-russian/CONTRIBUTING.md From 19fba3855684a21f93af9f85b0db71bf5ccea102 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 4 May 2024 19:58:02 +0300 Subject: [PATCH 78/83] Fix links to Russian translation --- README.md | 209 +++++++++++++++++++----------- translations/ru-russian/README.md | 66 +++++++++- 2 files changed, 201 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index bb3100f..0d3fd48 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

What the f*ck Python! 😱

Exploring and understanding Python through surprising snippets.

-Translations: [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/frontdevops/wtfpython) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) +Translations: [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%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) Other modes: [Interactive Website](https://wtfpython-interactive.vercel.app) | [Interactive Notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) @@ -24,84 +24,147 @@ So, here we go... +- [Table of Contents](#table-of-contents) - [Structure of the Examples](#structure-of-the-examples) - + [▶ Some fancy Title](#-some-fancy-title) - [Usage](#usage) - [👀 Examples](#-examples) - * [Section: Strain your brain!](#section-strain-your-brain) - + [▶ First things first! *](#-first-things-first-) - + [▶ Strings can be tricky sometimes](#-strings-can-be-tricky-sometimes) - + [▶ Be careful with chained operations](#-be-careful-with-chained-operations) - + [▶ How not to use `is` operator](#-how-not-to-use-is-operator) - + [▶ Hash brownies](#-hash-brownies) - + [▶ Deep down, we're all the same.](#-deep-down-were-all-the-same) - + [▶ Disorder within order *](#-disorder-within-order-) - + [▶ Keep trying... *](#-keep-trying-) - + [▶ For what?](#-for-what) - + [▶ Evaluation time discrepancy](#-evaluation-time-discrepancy) - + [▶ `is not ...` is not `is (not ...)`](#-is-not--is-not-is-not-) - + [▶ A tic-tac-toe where X wins in the first attempt!](#-a-tic-tac-toe-where-x-wins-in-the-first-attempt) - + [▶ Schrödinger's variable](#-schrödingers-variable-) - + [▶ The chicken-egg problem *](#-the-chicken-egg-problem-) - + [▶ Subclass relationships](#-subclass-relationships) - + [▶ Methods equality and identity](#-methods-equality-and-identity) - + [▶ All-true-ation *](#-all-true-ation-) - + [▶ The surprising comma](#-the-surprising-comma) - + [▶ Strings and the backslashes](#-strings-and-the-backslashes) - + [▶ not knot!](#-not-knot) - + [▶ Half triple-quoted strings](#-half-triple-quoted-strings) - + [▶ What's wrong with booleans?](#-whats-wrong-with-booleans) - + [▶ Class attributes and instance attributes](#-class-attributes-and-instance-attributes) - + [▶ yielding None](#-yielding-none) - + [▶ Yielding from... return! *](#-yielding-from-return-) - + [▶ Nan-reflexivity *](#-nan-reflexivity-) - + [▶ Mutating the immutable!](#-mutating-the-immutable) - + [▶ The disappearing variable from outer scope](#-the-disappearing-variable-from-outer-scope) - + [▶ The mysterious key type conversion](#-the-mysterious-key-type-conversion) - + [▶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) - + [▶ Exceeds the limit for integer string conversion](#-exceeds-the-limit-for-integer-string-conversion) - * [Section: Slippery Slopes](#section-slippery-slopes) - + [▶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) - + [▶ Stubborn `del` operation](#-stubborn-del-operation) - + [▶ The out of scope variable](#-the-out-of-scope-variable) - + [▶ Deleting a list item while iterating](#-deleting-a-list-item-while-iterating) - + [▶ Lossy zip of iterators *](#-lossy-zip-of-iterators-) - + [▶ Loop variables leaking out!](#-loop-variables-leaking-out) - + [▶ Beware of default mutable arguments!](#-beware-of-default-mutable-arguments) - + [▶ Catching the Exceptions](#-catching-the-exceptions) - + [▶ Same operands, different story!](#-same-operands-different-story) - + [▶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) - + [▶ Rounding like a banker *](#-rounding-like-a-banker-) - + [▶ Needles in a Haystack *](#-needles-in-a-haystack-) - + [▶ Splitsies *](#-splitsies-) - + [▶ Wild imports *](#-wild-imports-) - + [▶ All sorted? *](#-all-sorted-) - + [▶ Midnight time doesn't exist?](#-midnight-time-doesnt-exist) - * [Section: The Hidden treasures!](#section-the-hidden-treasures) - + [▶ Okay Python, Can you make me fly?](#-okay-python-can-you-make-me-fly) - + [▶ `goto`, but why?](#-goto-but-why) - + [▶ Brace yourself!](#-brace-yourself) - + [▶ Let's meet Friendly Language Uncle For Life](#-lets-meet-friendly-language-uncle-for-life) - + [▶ Even Python understands that love is complicated](#-even-python-understands-that-love-is-complicated) - + [▶ Yes, it exists!](#-yes-it-exists) - + [▶ Ellipsis *](#-ellipsis-) - + [▶ Inpinity](#-inpinity) - + [▶ Let's mangle](#-lets-mangle) - * [Section: Appearances are deceptive!](#section-appearances-are-deceptive) - + [▶ Skipping lines?](#-skipping-lines) - + [▶ Teleportation](#-teleportation) - + [▶ Well, something is fishy...](#-well-something-is-fishy) - * [Section: Miscellaneous](#section-miscellaneous) - + [▶ `+=` is faster](#--is-faster) - + [▶ Let's make a giant string!](#-lets-make-a-giant-string) - + [▶ Slowing down `dict` lookups *](#-slowing-down-dict-lookups-) - + [▶ Bloating instance `dict`s *](#-bloating-instance-dicts-) - + [▶ Minor Ones *](#-minor-ones-) + - [Section: Strain your brain!](#section-strain-your-brain) + - [▶ First things first! \*](#-first-things-first-) + - [💡 Explanation](#-explanation) + - [▶ Strings can be tricky sometimes](#-strings-can-be-tricky-sometimes) + - [💡 Explanation:](#-explanation-1) + - [▶ Be careful with chained operations](#-be-careful-with-chained-operations) + - [💡 Explanation:](#-explanation-2) + - [▶ How not to use `is` operator](#-how-not-to-use-is-operator) + - [💡 Explanation:](#-explanation-3) + - [▶ Hash brownies](#-hash-brownies) + - [💡 Explanation](#-explanation-4) + - [▶ Deep down, we're all the same.](#-deep-down-were-all-the-same) + - [💡 Explanation:](#-explanation-5) + - [▶ Disorder within order \*](#-disorder-within-order-) + - [💡 Explanation:](#-explanation-6) + - [▶ Keep trying... \*](#-keep-trying-) + - [💡 Explanation:](#-explanation-7) + - [▶ For what?](#-for-what) + - [💡 Explanation:](#-explanation-8) + - [▶ Evaluation time discrepancy](#-evaluation-time-discrepancy) + - [💡 Explanation](#-explanation-9) + - [▶ `is not ...` is not `is (not ...)`](#-is-not--is-not-is-not-) + - [💡 Explanation](#-explanation-10) + - [▶ A tic-tac-toe where X wins in the first attempt!](#-a-tic-tac-toe-where-x-wins-in-the-first-attempt) + - [💡 Explanation:](#-explanation-11) + - [▶ Schrödinger's variable \*](#-schrödingers-variable-) + - [💡 Explanation:](#-explanation-12) + - [▶ The chicken-egg problem \*](#-the-chicken-egg-problem-) + - [💡 Explanation](#-explanation-13) + - [▶ Subclass relationships](#-subclass-relationships) + - [💡 Explanation:](#-explanation-14) + - [▶ Methods equality and identity](#-methods-equality-and-identity) + - [💡 Explanation](#-explanation-15) + - [▶ All-true-ation \*](#-all-true-ation-) + - [💡 Explanation:](#-explanation-16) + - [💡 Explanation:](#-explanation-17) + - [▶ Strings and the backslashes](#-strings-and-the-backslashes) + - [💡 Explanation](#-explanation-18) + - [▶ not knot!](#-not-knot) + - [💡 Explanation:](#-explanation-19) + - [▶ Half triple-quoted strings](#-half-triple-quoted-strings) + - [💡 Explanation:](#-explanation-20) + - [▶ What's wrong with booleans?](#-whats-wrong-with-booleans) + - [💡 Explanation:](#-explanation-21) + - [▶ Class attributes and instance attributes](#-class-attributes-and-instance-attributes) + - [💡 Explanation:](#-explanation-22) + - [▶ yielding None](#-yielding-none) + - [💡 Explanation:](#-explanation-23) + - [▶ Yielding from... return! \*](#-yielding-from-return-) + - [💡 Explanation:](#-explanation-24) + - [▶ Nan-reflexivity \*](#-nan-reflexivity-) + - [💡 Explanation:](#-explanation-25) + - [▶ Mutating the immutable!](#-mutating-the-immutable) + - [💡 Explanation:](#-explanation-26) + - [▶ The disappearing variable from outer scope](#-the-disappearing-variable-from-outer-scope) + - [💡 Explanation:](#-explanation-27) + - [▶ The mysterious key type conversion](#-the-mysterious-key-type-conversion) + - [💡 Explanation:](#-explanation-28) + - [▶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) + - [💡 Explanation:](#-explanation-29) + - [▶ Exceeds the limit for integer string conversion](#-exceeds-the-limit-for-integer-string-conversion) + - [💡 Explanation:](#-explanation-30) + - [Section: Slippery Slopes](#section-slippery-slopes) + - [▶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) + - [💡 Explanation:](#-explanation-31) + - [▶ Stubborn `del` operation](#-stubborn-del-operation) + - [💡 Explanation:](#-explanation-32) + - [▶ The out of scope variable](#-the-out-of-scope-variable) + - [💡 Explanation:](#-explanation-33) + - [▶ Deleting a list item while iterating](#-deleting-a-list-item-while-iterating) + - [💡 Explanation:](#-explanation-34) + - [▶ Lossy zip of iterators \*](#-lossy-zip-of-iterators-) + - [💡 Explanation:](#-explanation-35) + - [▶ Loop variables leaking out!](#-loop-variables-leaking-out) + - [💡 Explanation:](#-explanation-36) + - [▶ Beware of default mutable arguments!](#-beware-of-default-mutable-arguments) + - [💡 Explanation:](#-explanation-37) + - [▶ Catching the Exceptions](#-catching-the-exceptions) + - [💡 Explanation](#-explanation-38) + - [▶ Same operands, different story!](#-same-operands-different-story) + - [💡 Explanation:](#-explanation-39) + - [▶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) + - [💡 Explanation](#-explanation-40) + - [▶ Rounding like a banker \*](#-rounding-like-a-banker-) + - [💡 Explanation:](#-explanation-41) + - [▶ Needles in a Haystack \*](#-needles-in-a-haystack-) + - [💡 Explanation:](#-explanation-42) + - [▶ Splitsies \*](#-splitsies-) + - [💡 Explanation:](#-explanation-43) + - [▶ Wild imports \*](#-wild-imports-) + - [💡 Explanation:](#-explanation-44) + - [▶ All sorted? \*](#-all-sorted-) + - [💡 Explanation:](#-explanation-45) + - [▶ Midnight time doesn't exist?](#-midnight-time-doesnt-exist) + - [💡 Explanation:](#-explanation-46) + - [Section: The Hidden treasures!](#section-the-hidden-treasures) + - [▶ Okay Python, Can you make me fly?](#-okay-python-can-you-make-me-fly) + - [💡 Explanation:](#-explanation-47) + - [▶ `goto`, but why?](#-goto-but-why) + - [💡 Explanation:](#-explanation-48) + - [▶ Brace yourself!](#-brace-yourself) + - [💡 Explanation:](#-explanation-49) + - [▶ Let's meet Friendly Language Uncle For Life](#-lets-meet-friendly-language-uncle-for-life) + - [💡 Explanation:](#-explanation-50) + - [▶ Even Python understands that love is complicated](#-even-python-understands-that-love-is-complicated) + - [💡 Explanation:](#-explanation-51) + - [▶ Yes, it exists!](#-yes-it-exists) + - [💡 Explanation:](#-explanation-52) + - [▶ Ellipsis \*](#-ellipsis-) + - [💡 Explanation](#-explanation-53) + - [▶ Inpinity](#-inpinity) + - [💡 Explanation:](#-explanation-54) + - [▶ Let's mangle](#-lets-mangle) + - [💡 Explanation:](#-explanation-55) + - [Section: Appearances are deceptive!](#section-appearances-are-deceptive) + - [▶ Skipping lines?](#-skipping-lines) + - [💡 Explanation](#-explanation-56) + - [▶ Teleportation](#-teleportation) + - [💡 Explanation:](#-explanation-57) + - [▶ Well, something is fishy...](#-well-something-is-fishy) + - [💡 Explanation](#-explanation-58) + - [Section: Miscellaneous](#section-miscellaneous) + - [▶ `+=` is faster](#--is-faster) + - [💡 Explanation:](#-explanation-59) + - [▶ Let's make a giant string!](#-lets-make-a-giant-string) + - [💡 Explanation](#-explanation-60) + - [▶ Slowing down `dict` lookups \*](#-slowing-down-dict-lookups-) + - [💡 Explanation:](#-explanation-61) + - [▶ Bloating instance `dict`s \*](#-bloating-instance-dicts-) + - [💡 Explanation:](#-explanation-62) + - [▶ Minor Ones \*](#-minor-ones-) - [Contributing](#contributing) - [Acknowledgements](#acknowledgements) + - [Some nice Links!](#some-nice-links) - [🎓 License](#-license) - * [Surprise your friends as well!](#surprise-your-friends-as-well) - * [More content like this?](#more-content-like-this) + - [Surprise your friends as well!](#surprise-your-friends-as-well) + - [Need a pdf version?](#need-a-pdf-version) diff --git a/translations/ru-russian/README.md b/translations/ru-russian/README.md index 402b26a..d8dff4a 100644 --- a/translations/ru-russian/README.md +++ b/translations/ru-russian/README.md @@ -2,7 +2,7 @@

What the f*ck Python! 😱

Изучение и понимание Python с помощью удивительных примеров поведения.

-Переводы: [English Original](https://github.com/satwikkansal/wtfpython) [Chinese 中文](https://github.com/robertparley/wtfpython-cn) | [Vietnamese Tiếng Việt](https://github.com/vuduclyunitn/wtfptyhon-vi) | [Spanish Español](https://web.archive.org/web/20220511161045/https://github.com/JoseDeFreitas/wtfpython-es) | [Korean 한국어](https://github.com/buttercrab/wtfpython-ko) | [Russian Русский](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) +Переводы: [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%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) Альтернативные способы: [Интерактивный сайт](https://wtfpython-interactive.vercel.app) | [Интерактивный Jupiter notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) @@ -23,74 +23,138 @@ PS: Если вы уже читали **wtfpython** раньше, с измен - [👀 Примеры](#-примеры) - [Раздел: Напряги мозги!](#раздел-напряги-мозги) - [▶ Первым делом!](#-первым-делом) + - [💡 Обьяснение](#-обьяснение) - [▶ Строки иногда ведут себя непредсказуемо](#-строки-иногда-ведут-себя-непредсказуемо) + - [💡 Объяснение](#-объяснение) - [▶ Осторожнее с цепочкой операций](#-осторожнее-с-цепочкой-операций) + - [💡 Объяснение:](#-объяснение-1) - [▶ Как не надо использовать оператор `is`](#-как-не-надо-использовать-оператор-is) + - [💡 Объяснение:](#-объяснение-2) - [▶ Мистическое хеширование](#-мистическое-хеширование) + - [💡 Объяснение](#-объяснение-3) - [▶ В глубине души мы все одинаковы.](#-в-глубине-души-мы-все-одинаковы) + - [💡 Объяснение:](#-объяснение-4) - [▶ Беспорядок внутри порядка \*](#-беспорядок-внутри-порядка-) + - [💡 Объяснение:](#-объяснение-5) - [▶ Продолжай пытаться... \*](#-продолжай-пытаться-) + - [💡 Объяснение:](#-объяснение-6) - [▶ Для чего?](#-для-чего) + - [💡 Объяснение:](#-объяснение-7) - [▶ Расхождение во времени исполнения](#-расхождение-во-времени-исполнения) + - [💡 Объяснение](#-объяснение-8) - [▶ `is not ...` не является `is (not ...)`](#-is-not--не-является-is-not-) + - [💡 Объяснение](#-объяснение-9) - [▶ Крестики-нолики, где X побеждает с первой попытки!](#-крестики-нолики-где-x-побеждает-с-первой-попытки) + - [💡 Объяснение:](#-объяснение-10) - [▶ Переменная Шредингера \*](#-переменная-шредингера-) + - [💡 Объяснение:](#-объяснение-11) - [▶ Проблема курицы и яйца \*](#-проблема-курицы-и-яйца-) + - [💡 Объяснение](#-объяснение-12) - [▶ Отношения между подклассами](#-отношения-между-подклассами) + - [💡 Объяснение](#-объяснение-13) - [▶ Равенство и тождество методов](#-равенство-и-тождество-методов) + - [💡 Объяснение](#-объяснение-14) - [▶ All-true-ation (непереводимая игра слов) \*](#-all-true-ation-непереводимая-игра-слов-) + - [💡 Объяснение:](#-объяснение-15) + - [💡 Объяснение:](#-объяснение-16) - [▶ Строки и обратные слэши](#-строки-и-обратные-слэши) + - [💡 Объяснение](#-объяснение-17) - [▶ Не узел! (англ. not knot!)](#-не-узел-англ-not-knot) + - [💡 Объяснение](#-объяснение-18) - [▶ Строки, наполовину обернутые в тройные кавычки](#-строки-наполовину-обернутые-в-тройные-кавычки) + - [💡 Объяснение:](#-объяснение-19) - [▶ Что не так с логическими значениями?](#-что-не-так-с-логическими-значениями) + - [💡 Объяснение:](#-объяснение-20) - [▶ Атрибуты класса и экземпляра](#-атрибуты-класса-и-экземпляра) + - [💡 Объяснение:](#-объяснение-21) - [▶ Возврат None из генератора](#-возврат-none-из-генератора) + - [💡 Объяснение:](#-объяснение-22) - [▶ Yield from возвращает... \*](#-yield-from-возвращает-) + - [💡 Объяснение:](#-объяснение-23) - [▶ Nan-рефлексивность \*](#-nan-рефлексивность-) + - [💡 Объяснение:](#-объяснение-24) - [▶ Изменяем неизменяемое!](#-изменяем-неизменяемое) + - [💡 Объяснение:](#-объяснение-25) - [▶ Исчезающая переменная из внешней области видимости](#-исчезающая-переменная-из-внешней-области-видимости) + - [💡 Объяснение:](#-объяснение-26) - [▶ Загадочное преобразование типов ключей](#-загадочное-преобразование-типов-ключей) + - [💡 Объяснение:](#-объяснение-27) - [▶ Посмотрим, сможете ли вы угадать что здесь?](#-посмотрим-сможете-ли-вы-угадать-что-здесь) + - [💡 Объяснение:](#-объяснение-28) - [▶ Превышение предела целочисленного преобразования строк](#-превышение-предела-целочисленного-преобразования-строк) + - [💡 Объяснение:](#-объяснение-29) - [Раздел: Скользкие склоны](#раздел-скользкие-склоны) - [▶ Изменение словаря во время прохода по нему](#-изменение-словаря-во-время-прохода-по-нему) + - [💡 Объяснение:](#-объяснение-30) - [▶ Упрямая операция `del`](#-упрямая-операция-del) + - [💡 Объяснение:](#-объяснение-31) - [▶ Переменная за пределами видимости](#-переменная-за-пределами-видимости) + - [💡 Объяснение:](#-объяснение-32) - [▶ Удаление элемента списка во время прохода по списку](#-удаление-элемента-списка-во-время-прохода-по-списку) + - [💡 Объяснение:](#-объяснение-33) - [▶ Сжатие итераторов с потерями \*](#-сжатие-итераторов-с-потерями-) + - [💡 Объяснение:](#-объяснение-34) - [▶ Утечка переменных внутри цикла](#-утечка-переменных-внутри-цикла) + - [💡 Объяснение:](#-объяснение-35) - [▶ Остерегайтесь изменяемых аргументов по умолчанию!](#-остерегайтесь-изменяемых-аргументов-по-умолчанию) + - [💡 Объяснение:](#-объяснение-36) - [▶ Ловля исключений](#-ловля-исключений) + - [💡 Объяснение](#-объяснение-37) - [▶ Одни и те же операнды, разная история!](#-одни-и-те-же-операнды-разная-история) + - [💡 Объяснение:](#-объяснение-38) - [▶ Разрешение имен игнорирует область видимости класса](#-разрешение-имен-игнорирует-область-видимости-класса) + - [💡 Объяснение](#-объяснение-39) - [▶ Округляясь как банкир \*](#-округляясь-как-банкир-) + - [💡 Объяснение:](#-объяснение-40) - [▶ Иголки в стоге сена \*](#-иголки-в-стоге-сена-) + - [💡 Объяснение:](#-объяснение-41) - [▶ Сплиты (splitsies) \*](#-сплиты-splitsies-) + - [💡 Объяснение](#-объяснение-42) - [▶ Подстановочное импортирование (wild imports) \*](#-подстановочное-импортирование-wild-imports-) + - [💡 Объяснение:](#-объяснение-43) - [▶ Все ли отсортировано? \*](#-все-ли-отсортировано-) + - [💡 Объяснение:](#-объяснение-44) - [▶ Полночи не существует?](#-полночи-не-существует) + - [💡 Объяснение:](#-объяснение-45) - [Раздел: Скрытые сокровища!](#раздел-скрытые-сокровища) - [▶ Python, можешь ли ты помочь взлететь?](#-python-можешь-ли-ты-помочь-взлететь) + - [💡 Объяснение:](#-объяснение-46) - [▶ `goto`, но почему?](#-goto-но-почему) + - [💡 Объяснение:](#-объяснение-47) - [▶ Держитесь!](#-держитесь) + - [💡 Объяснение:](#-объяснение-48) - [▶ Давайте познакомимся с дружелюбным Дядей Барри](#-давайте-познакомимся-с-дружелюбным-дядей-барри) + - [💡 Объяснение:](#-объяснение-49) - [▶ Даже Python понимает, что любовь - это сложно.](#-даже-python-понимает-что-любовь---это-сложно) + - [💡 Объяснение:](#-объяснение-50) - [▶ Да, оно существует!](#-да-оно-существует) + - [💡 Объяснение:](#-объяснение-51) - [▶ Многоточие \*](#-многоточие-) + - [💡 Объяснение](#-объяснение-52) - [▶ Писконечность (Inpinity)](#-писконечность-inpinity) + - [💡 Объяснение:](#-объяснение-53) - [▶ Давайте искажать](#-давайте-искажать) + - [💡 Объяснение:](#-объяснение-54) - [Раздел: Внешность обманчива!](#раздел-внешность-обманчива) - [▶ Пропускаем строки?](#-пропускаем-строки) + - [💡 Объяснение](#-объяснение-55) - [▶ Телепортация](#-телепортация) + - [💡 Объяснение:](#-объяснение-56) - [▶ Что-то не так...](#-что-то-не-так) + - [💡 Объяснение](#-объяснение-57) - [Раздел: Разное](#раздел-разное) - [▶ `+=` быстрее `+`](#--быстрее-) + - [💡 Объяснение:](#-объяснение-58) - [▶ Сделаем гигантскую строку!](#-сделаем-гигантскую-строку) + - [💡 Объяснение](#-объяснение-59) - [▶ Замедляем поиск по `dict` \*](#-замедляем-поиск-по-dict-) + - [💡 Объяснение:](#-объяснение-60) - [▶ Раздуваем экземпляры словарей \*](#-раздуваем-экземпляры-словарей-) + - [💡 Объяснение:](#-объяснение-61) - [▶ Минорное \*](#-минорное-) - [Вклад в проект](#вклад-в-проект) - [Благодарности](#благодарности) + - [Несколько хороших ссылок!](#несколько-хороших-ссылок) - [🎓 Лицензия](#-лицензия) - [Удиви своих друзей!](#удиви-своих-друзей) - [Нужна PDF версия?](#нужна-pdf-версия) From 0ec593971346c2575b605442cb9ce9dba0a9abfe Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 4 May 2024 19:58:56 +0300 Subject: [PATCH 79/83] Revert CONTRIBUTING.md --- CONTRIBUTING.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md old mode 100755 new mode 100644 From b6fd12efa2fb58d1984460ac3fe5abca94da39ba Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 4 May 2024 20:01:51 +0300 Subject: [PATCH 80/83] Revert code-of-conduct.md --- code-of-conduct.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 code-of-conduct.md diff --git a/code-of-conduct.md b/code-of-conduct.md old mode 100755 new mode 100644 From 39595fc35f5538040c825f28f191926707a84fa9 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 4 May 2024 20:03:28 +0300 Subject: [PATCH 81/83] Revert README.md --- README.md | 209 +++++++++++++++++++----------------------------------- 1 file changed, 73 insertions(+), 136 deletions(-) diff --git a/README.md b/README.md index 0d3fd48..bb3100f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

What the f*ck Python! 😱

Exploring and understanding Python through surprising snippets.

-Translations: [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%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) +Translations: [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/frontdevops/wtfpython) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) Other modes: [Interactive Website](https://wtfpython-interactive.vercel.app) | [Interactive Notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) @@ -24,147 +24,84 @@ So, here we go... -- [Table of Contents](#table-of-contents) - [Structure of the Examples](#structure-of-the-examples) + + [▶ Some fancy Title](#-some-fancy-title) - [Usage](#usage) - [👀 Examples](#-examples) - - [Section: Strain your brain!](#section-strain-your-brain) - - [▶ First things first! \*](#-first-things-first-) - - [💡 Explanation](#-explanation) - - [▶ Strings can be tricky sometimes](#-strings-can-be-tricky-sometimes) - - [💡 Explanation:](#-explanation-1) - - [▶ Be careful with chained operations](#-be-careful-with-chained-operations) - - [💡 Explanation:](#-explanation-2) - - [▶ How not to use `is` operator](#-how-not-to-use-is-operator) - - [💡 Explanation:](#-explanation-3) - - [▶ Hash brownies](#-hash-brownies) - - [💡 Explanation](#-explanation-4) - - [▶ Deep down, we're all the same.](#-deep-down-were-all-the-same) - - [💡 Explanation:](#-explanation-5) - - [▶ Disorder within order \*](#-disorder-within-order-) - - [💡 Explanation:](#-explanation-6) - - [▶ Keep trying... \*](#-keep-trying-) - - [💡 Explanation:](#-explanation-7) - - [▶ For what?](#-for-what) - - [💡 Explanation:](#-explanation-8) - - [▶ Evaluation time discrepancy](#-evaluation-time-discrepancy) - - [💡 Explanation](#-explanation-9) - - [▶ `is not ...` is not `is (not ...)`](#-is-not--is-not-is-not-) - - [💡 Explanation](#-explanation-10) - - [▶ A tic-tac-toe where X wins in the first attempt!](#-a-tic-tac-toe-where-x-wins-in-the-first-attempt) - - [💡 Explanation:](#-explanation-11) - - [▶ Schrödinger's variable \*](#-schrödingers-variable-) - - [💡 Explanation:](#-explanation-12) - - [▶ The chicken-egg problem \*](#-the-chicken-egg-problem-) - - [💡 Explanation](#-explanation-13) - - [▶ Subclass relationships](#-subclass-relationships) - - [💡 Explanation:](#-explanation-14) - - [▶ Methods equality and identity](#-methods-equality-and-identity) - - [💡 Explanation](#-explanation-15) - - [▶ All-true-ation \*](#-all-true-ation-) - - [💡 Explanation:](#-explanation-16) - - [💡 Explanation:](#-explanation-17) - - [▶ Strings and the backslashes](#-strings-and-the-backslashes) - - [💡 Explanation](#-explanation-18) - - [▶ not knot!](#-not-knot) - - [💡 Explanation:](#-explanation-19) - - [▶ Half triple-quoted strings](#-half-triple-quoted-strings) - - [💡 Explanation:](#-explanation-20) - - [▶ What's wrong with booleans?](#-whats-wrong-with-booleans) - - [💡 Explanation:](#-explanation-21) - - [▶ Class attributes and instance attributes](#-class-attributes-and-instance-attributes) - - [💡 Explanation:](#-explanation-22) - - [▶ yielding None](#-yielding-none) - - [💡 Explanation:](#-explanation-23) - - [▶ Yielding from... return! \*](#-yielding-from-return-) - - [💡 Explanation:](#-explanation-24) - - [▶ Nan-reflexivity \*](#-nan-reflexivity-) - - [💡 Explanation:](#-explanation-25) - - [▶ Mutating the immutable!](#-mutating-the-immutable) - - [💡 Explanation:](#-explanation-26) - - [▶ The disappearing variable from outer scope](#-the-disappearing-variable-from-outer-scope) - - [💡 Explanation:](#-explanation-27) - - [▶ The mysterious key type conversion](#-the-mysterious-key-type-conversion) - - [💡 Explanation:](#-explanation-28) - - [▶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) - - [💡 Explanation:](#-explanation-29) - - [▶ Exceeds the limit for integer string conversion](#-exceeds-the-limit-for-integer-string-conversion) - - [💡 Explanation:](#-explanation-30) - - [Section: Slippery Slopes](#section-slippery-slopes) - - [▶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) - - [💡 Explanation:](#-explanation-31) - - [▶ Stubborn `del` operation](#-stubborn-del-operation) - - [💡 Explanation:](#-explanation-32) - - [▶ The out of scope variable](#-the-out-of-scope-variable) - - [💡 Explanation:](#-explanation-33) - - [▶ Deleting a list item while iterating](#-deleting-a-list-item-while-iterating) - - [💡 Explanation:](#-explanation-34) - - [▶ Lossy zip of iterators \*](#-lossy-zip-of-iterators-) - - [💡 Explanation:](#-explanation-35) - - [▶ Loop variables leaking out!](#-loop-variables-leaking-out) - - [💡 Explanation:](#-explanation-36) - - [▶ Beware of default mutable arguments!](#-beware-of-default-mutable-arguments) - - [💡 Explanation:](#-explanation-37) - - [▶ Catching the Exceptions](#-catching-the-exceptions) - - [💡 Explanation](#-explanation-38) - - [▶ Same operands, different story!](#-same-operands-different-story) - - [💡 Explanation:](#-explanation-39) - - [▶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) - - [💡 Explanation](#-explanation-40) - - [▶ Rounding like a banker \*](#-rounding-like-a-banker-) - - [💡 Explanation:](#-explanation-41) - - [▶ Needles in a Haystack \*](#-needles-in-a-haystack-) - - [💡 Explanation:](#-explanation-42) - - [▶ Splitsies \*](#-splitsies-) - - [💡 Explanation:](#-explanation-43) - - [▶ Wild imports \*](#-wild-imports-) - - [💡 Explanation:](#-explanation-44) - - [▶ All sorted? \*](#-all-sorted-) - - [💡 Explanation:](#-explanation-45) - - [▶ Midnight time doesn't exist?](#-midnight-time-doesnt-exist) - - [💡 Explanation:](#-explanation-46) - - [Section: The Hidden treasures!](#section-the-hidden-treasures) - - [▶ Okay Python, Can you make me fly?](#-okay-python-can-you-make-me-fly) - - [💡 Explanation:](#-explanation-47) - - [▶ `goto`, but why?](#-goto-but-why) - - [💡 Explanation:](#-explanation-48) - - [▶ Brace yourself!](#-brace-yourself) - - [💡 Explanation:](#-explanation-49) - - [▶ Let's meet Friendly Language Uncle For Life](#-lets-meet-friendly-language-uncle-for-life) - - [💡 Explanation:](#-explanation-50) - - [▶ Even Python understands that love is complicated](#-even-python-understands-that-love-is-complicated) - - [💡 Explanation:](#-explanation-51) - - [▶ Yes, it exists!](#-yes-it-exists) - - [💡 Explanation:](#-explanation-52) - - [▶ Ellipsis \*](#-ellipsis-) - - [💡 Explanation](#-explanation-53) - - [▶ Inpinity](#-inpinity) - - [💡 Explanation:](#-explanation-54) - - [▶ Let's mangle](#-lets-mangle) - - [💡 Explanation:](#-explanation-55) - - [Section: Appearances are deceptive!](#section-appearances-are-deceptive) - - [▶ Skipping lines?](#-skipping-lines) - - [💡 Explanation](#-explanation-56) - - [▶ Teleportation](#-teleportation) - - [💡 Explanation:](#-explanation-57) - - [▶ Well, something is fishy...](#-well-something-is-fishy) - - [💡 Explanation](#-explanation-58) - - [Section: Miscellaneous](#section-miscellaneous) - - [▶ `+=` is faster](#--is-faster) - - [💡 Explanation:](#-explanation-59) - - [▶ Let's make a giant string!](#-lets-make-a-giant-string) - - [💡 Explanation](#-explanation-60) - - [▶ Slowing down `dict` lookups \*](#-slowing-down-dict-lookups-) - - [💡 Explanation:](#-explanation-61) - - [▶ Bloating instance `dict`s \*](#-bloating-instance-dicts-) - - [💡 Explanation:](#-explanation-62) - - [▶ Minor Ones \*](#-minor-ones-) + * [Section: Strain your brain!](#section-strain-your-brain) + + [▶ First things first! *](#-first-things-first-) + + [▶ Strings can be tricky sometimes](#-strings-can-be-tricky-sometimes) + + [▶ Be careful with chained operations](#-be-careful-with-chained-operations) + + [▶ How not to use `is` operator](#-how-not-to-use-is-operator) + + [▶ Hash brownies](#-hash-brownies) + + [▶ Deep down, we're all the same.](#-deep-down-were-all-the-same) + + [▶ Disorder within order *](#-disorder-within-order-) + + [▶ Keep trying... *](#-keep-trying-) + + [▶ For what?](#-for-what) + + [▶ Evaluation time discrepancy](#-evaluation-time-discrepancy) + + [▶ `is not ...` is not `is (not ...)`](#-is-not--is-not-is-not-) + + [▶ A tic-tac-toe where X wins in the first attempt!](#-a-tic-tac-toe-where-x-wins-in-the-first-attempt) + + [▶ Schrödinger's variable](#-schrödingers-variable-) + + [▶ The chicken-egg problem *](#-the-chicken-egg-problem-) + + [▶ Subclass relationships](#-subclass-relationships) + + [▶ Methods equality and identity](#-methods-equality-and-identity) + + [▶ All-true-ation *](#-all-true-ation-) + + [▶ The surprising comma](#-the-surprising-comma) + + [▶ Strings and the backslashes](#-strings-and-the-backslashes) + + [▶ not knot!](#-not-knot) + + [▶ Half triple-quoted strings](#-half-triple-quoted-strings) + + [▶ What's wrong with booleans?](#-whats-wrong-with-booleans) + + [▶ Class attributes and instance attributes](#-class-attributes-and-instance-attributes) + + [▶ yielding None](#-yielding-none) + + [▶ Yielding from... return! *](#-yielding-from-return-) + + [▶ Nan-reflexivity *](#-nan-reflexivity-) + + [▶ Mutating the immutable!](#-mutating-the-immutable) + + [▶ The disappearing variable from outer scope](#-the-disappearing-variable-from-outer-scope) + + [▶ The mysterious key type conversion](#-the-mysterious-key-type-conversion) + + [▶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) + + [▶ Exceeds the limit for integer string conversion](#-exceeds-the-limit-for-integer-string-conversion) + * [Section: Slippery Slopes](#section-slippery-slopes) + + [▶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) + + [▶ Stubborn `del` operation](#-stubborn-del-operation) + + [▶ The out of scope variable](#-the-out-of-scope-variable) + + [▶ Deleting a list item while iterating](#-deleting-a-list-item-while-iterating) + + [▶ Lossy zip of iterators *](#-lossy-zip-of-iterators-) + + [▶ Loop variables leaking out!](#-loop-variables-leaking-out) + + [▶ Beware of default mutable arguments!](#-beware-of-default-mutable-arguments) + + [▶ Catching the Exceptions](#-catching-the-exceptions) + + [▶ Same operands, different story!](#-same-operands-different-story) + + [▶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) + + [▶ Rounding like a banker *](#-rounding-like-a-banker-) + + [▶ Needles in a Haystack *](#-needles-in-a-haystack-) + + [▶ Splitsies *](#-splitsies-) + + [▶ Wild imports *](#-wild-imports-) + + [▶ All sorted? *](#-all-sorted-) + + [▶ Midnight time doesn't exist?](#-midnight-time-doesnt-exist) + * [Section: The Hidden treasures!](#section-the-hidden-treasures) + + [▶ Okay Python, Can you make me fly?](#-okay-python-can-you-make-me-fly) + + [▶ `goto`, but why?](#-goto-but-why) + + [▶ Brace yourself!](#-brace-yourself) + + [▶ Let's meet Friendly Language Uncle For Life](#-lets-meet-friendly-language-uncle-for-life) + + [▶ Even Python understands that love is complicated](#-even-python-understands-that-love-is-complicated) + + [▶ Yes, it exists!](#-yes-it-exists) + + [▶ Ellipsis *](#-ellipsis-) + + [▶ Inpinity](#-inpinity) + + [▶ Let's mangle](#-lets-mangle) + * [Section: Appearances are deceptive!](#section-appearances-are-deceptive) + + [▶ Skipping lines?](#-skipping-lines) + + [▶ Teleportation](#-teleportation) + + [▶ Well, something is fishy...](#-well-something-is-fishy) + * [Section: Miscellaneous](#section-miscellaneous) + + [▶ `+=` is faster](#--is-faster) + + [▶ Let's make a giant string!](#-lets-make-a-giant-string) + + [▶ Slowing down `dict` lookups *](#-slowing-down-dict-lookups-) + + [▶ Bloating instance `dict`s *](#-bloating-instance-dicts-) + + [▶ Minor Ones *](#-minor-ones-) - [Contributing](#contributing) - [Acknowledgements](#acknowledgements) - - [Some nice Links!](#some-nice-links) - [🎓 License](#-license) - - [Surprise your friends as well!](#surprise-your-friends-as-well) - - [Need a pdf version?](#need-a-pdf-version) + * [Surprise your friends as well!](#surprise-your-friends-as-well) + * [More content like this?](#more-content-like-this) From 8db7d48ad67179b43027cfa104c3cbe61f5fca9e Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 4 May 2024 20:04:21 +0300 Subject: [PATCH 82/83] Add new link to Russian translation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb3100f..9311af6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

What the f*ck Python! 😱

Exploring and understanding Python through surprising snippets.

-Translations: [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/frontdevops/wtfpython) | [German Deutsch](https://github.com/BenSt099/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) +Translations: [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%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) Other modes: [Interactive Website](https://wtfpython-interactive.vercel.app) | [Interactive Notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) From d70bf71cb67fd918603d992f3aaae85305d22708 Mon Sep 17 00:00:00 2001 From: Vadim Nifadev <36514612+nifadyev@users.noreply.github.com> Date: Sat, 4 May 2024 20:06:24 +0300 Subject: [PATCH 83/83] Fix link to Russian translation --- CONTRIBUTORS.md | 2 +- translations/ru-russian/CONTRIBUTORS.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 68d5176..40526d9 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -35,7 +35,7 @@ Following are the wonderful people (in no specific order) who have contributed t | leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [Chinese](https://github.com/leisurelicht/wtfpython-cn) | | vuduclyunitn | [vuduclyunitn](https://github.com/vuduclyunitn) | [Vietnamese](https://github.com/vuduclyunitn/wtfptyhon-vi) | | José De Freitas | [JoseDeFreitas](https://github.com/JoseDeFreitas) | [Spanish](https://github.com/JoseDeFreitas/wtfpython-es) | -| Vadim Nifadev | [nifadyev](https://github.com/nifadyev) | [Russian](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) | +| Vadim Nifadev | [nifadyev](https://github.com/nifadyev) | [Russian](https://github.com/satwikkansal/wtfpython/tree/master/translations/ru-russian) | Thank you all for your time and making wtfpython more awesome! :smile: diff --git a/translations/ru-russian/CONTRIBUTORS.md b/translations/ru-russian/CONTRIBUTORS.md index 8a22a49..2599f8a 100644 --- a/translations/ru-russian/CONTRIBUTORS.md +++ b/translations/ru-russian/CONTRIBUTORS.md @@ -35,7 +35,7 @@ | leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [Chinese](https://github.com/leisurelicht/wtfpython-cn) | | vuduclyunitn | [vuduclyunitn](https://github.com/vuduclyunitn) | [Vietnamese](https://github.com/vuduclyunitn/wtfptyhon-vi) | | José De Freitas | [JoseDeFreitas](https://github.com/JoseDeFreitas) | [Spanish](https://github.com/JoseDeFreitas/wtfpython-es) | -| Vadim Nifadev | [nifadyev](https://github.com/nifadyev) | [Russian](https://github.com/satwikkansal/wtfpython/tree/main/translations/README-ru.md) | +| Vadim Nifadev | [nifadyev](https://github.com/nifadyev) | [Russian](https://github.com/satwikkansal/wtfpython/tree/master/translations/ru-russian) | Спасибо всем за ваше время и за то, что делаете wtfpython еще более потрясающим! :smile: