Сначала создается список из четырех функций.
funcs = []
for i in range(4):
def f():
print(i)
funcs.append(f)
Каждая из этих функций ищет значение i
и затем печатает его.
Это перебирает список функций и вызывает каждую из них:
>>> for f in funcs:
f()
Как указано выше, эти функции ищут i
, что в настоящий момент равно 3 из-за цикла for i in range(4)
, который завершился ранее, поэтому вы получаете четыре распечатки по 3.
Теперь вы снова выполняете цикл, используя i
в качестве переменной цикла:
for i in range(4):
funcs[i]()
0
1
2
3
Первый раз в цикле, i
равен 0, поэтому, когда функция ищет i
, она получает 0, а затем печатает это. Затем он меняется на 1, затем 2, затем 3.
Следующий код просто меняет i
еще одним способом и вызывает функцию:
>>> i = 2
>>> funcs[i]()
2
Вы могли бы вызвать любую из этих функций, и они все равно напечатали бы 2, потому что сейчас это значение i
. Вы просто заблудились, потому что для создания этих функций вы перебрали range(4)
, затем вы перебрали range(4)
, чтобы проиндексировать список функций, продолжаете повторно использовать i
, а затем переназначаете i
и также используете это индексировать список.
Если вы хотите, чтобы печатное значение каждой функции i
было зафиксировано на том же уровне, что и при определении функции, самый простой способ сделать это с аргументом по умолчанию, так как они оцениваются, когда функция определена, а не когда это называется:
funcs = []
for i in range(4):
def f(num=i):
print(num)
funcs.append(f)