Ответ 1
Вложенная функция ищет переменные из родительской области при ее выполнении, а не при определении.
Тело функции скомпилировано, а "свободные" переменные (не определенные в самой функции по назначению) проверяются, а затем привязываются как замыкающие ячейки к функции, причем код использует индекс для ссылки на каждую ячейку. pet_function
образом, pet_function
имеет одну свободную переменную (cage
), которая затем ссылается через ячейку замыкания, индекс 0. Сама закрытие указывает на локальную переменную cage
в функции get_petters
.
Когда вы на самом деле вызываете функцию, это закрытие затем используется для просмотра значения cage
в окружающей области в момент вызова функции. Здесь кроется проблема. К тому моменту, когда вы вызываете свои функции, функция get_petters
уже выполняется, вычисляя ее. Локальная переменная cage
в какой-то момент во время этого выполнения была назначена каждой из строк 'cow'
, 'dog'
и 'cat'
, но в конце этой функции cage
содержит последнее значение 'cat'
. Таким образом, когда вы вызываете каждую из динамически возвращенных функций, вы получаете значение 'cat'
.
Обход - это не полагаться на закрытие. Вместо этого вы можете использовать частичную функцию, создать новую область функций или привязать переменную как значение по умолчанию для параметра ключевого слова.
-
Пример частичной функции, используя
functools.partial()
:from functools import partial def pet_function(cage=None): print "Mary pets the " + cage.animal + "." yield (animal, partial(gotimes, partial(pet_function, cage=cage)))
-
Пример создания новой области:
def scoped_cage(cage=None): def pet_function(): print "Mary pets the " + cage.animal + "." return pet_function yield (animal, partial(gotimes, scoped_cage(cage)))
-
Привязка переменной в качестве значения по умолчанию для параметра ключевого слова:
def pet_function(cage=cage): print "Mary pets the " + cage.animal + "." yield (animal, partial(gotimes, pet_function))
Нет необходимости определять функцию scoped_cage
в цикле, компиляция выполняется только один раз, а не на каждой итерации цикла.