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()) +``` + +---