La fonction imbriquée recherche les variables de la portée parent lorsqu'il est exécuté, pas quand définis.
Le corps de la fonction est compilé, et le "libre" des variables (non défini dans la fonction elle-même par la cession), sont vérifiées, alors forcément que de la fermeture des cellules à la fonction, avec le code à l'aide d'un indice de référence de chaque cellule. pet_function
a donc une variable indépendante (cage
) qui est référencée par l'intermédiaire d'une fermeture de la cellule, l'index 0. La fermeture elle-même pointe vers la variable locale cage
dans la get_petters
fonction.
Lorsque vous appelez la fonction, que la fermeture est ensuite utilisé pour regarder la valeur de cage
dans les environs du champ d'application au moment de l'appel de la fonction. C'est là que réside le problème. Par le temps que vous appelez de vos fonctions, l' get_petters
fonction est déjà fait le calcul des résultats. L' cage
variable locale à un certain moment au cours de cette exécution a été assigné à chacun de l' 'cow'
, 'dog'
, et 'cat'
chaînes, mais à la fin de la fonction, cage
contient la dernière valeur 'cat'
. Ainsi, lorsque vous appelez chaque renvoyé dynamiquement les fonctions, vous obtenez la valeur 'cat'
imprimé.
Le travail est de ne pas s'appuyer sur les fermetures. Vous pouvez utiliser une fonction partielle au lieu de cela, créer un nouveau domaine de la fonction, ou de lier la variable comme valeur par défaut pour un mot-clé en paramètre.
-
Fonction partielle exemple, à l'aide de 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)))
-
La création d'un nouveau champ d'application exemple:
def scoped_cage(cage=None):
def pet_function():
print "Mary pets the " + cage.animal + "."
return pet_function
yield (animal, partial(gotimes, scoped_cage(cage)))
-
La liaison de la variable comme valeur par défaut pour un mot-clé en paramètre:
def pet_function(cage=cage):
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, pet_function))
Il n'est pas nécessaire de définir l' pet_function
ou scoped_cage
fonction dans la boucle, la compilation a lieu seulement une fois, pas à chaque itération de la boucle.