Encapsuler des variables dans des fermetures pour les supprimer des signatures de fonction est une technique souvent utilisée pour une structuration efficace du code. Cependant, dans le cas de lambdas non imbriquées, la fermeture conserve la valeur finale de la variable, ce qui entraîne des problèmes lors de la tentative d'accès à des valeurs spécifiques basées sur la variable itérative.
Considérez l'extrait de code fourni :
names = ['a', 'b', 'c'] def test_fun(name, x): print(name, x) def gen_clousure(name): return lambda x: test_fun(name, x) funcs1 = [gen_clousure(n) for n in names] funcs2 = [lambda x: test_fun(n, x) for n in names] # Expected output for funcs1 for f in funcs1: f(1) # Unexpected output for funcs2 (returns last element for all cases) for f in funcs2: f(1)
Comprendre la raison de cet écart est crucial pour une utilisation efficace des fermetures.
Le concept fondamental dans cette situation est portée variable dans les fermetures . Les fermetures contiennent intrinsèquement les noms de variables plutôt que leurs valeurs. Cela signifie que l'évaluation de la variable se produit au début de l'exécution de lambda, plutôt qu'au moment de la définition de lambda.
Dans le cas de funcs2, lorsque vous exécutez lambda x : test_fun(n, x), la variable n n’est pas évalué lors de la définition lambda. Au lieu de cela, l'évaluation n'a lieu que lors de l'appel lambda. À ce stade, n contient la dernière valeur de la boucle (qui est « c » dans ce cas). Par conséquent, la fonction f utilise toujours « c » comme valeur de n, quelle que soit l'entrée x.
Pour résoudre ce problème et obtenir la fonctionnalité souhaitée, la variable n doit être capturée dans la portée de la fonction lambda. Ceci peut être réalisé en passant la variable comme argument au lambda, comme illustré dans ce qui suit :
funcs2 = [lambda x: test_fun(n, x) for n in names if 2 > 0]
En incluant cette instruction if supplémentaire qui est toujours vraie, nous forçons le lambda à prendre la valeur de n comme argument, garantissant le comportement personnalisé attendu dans tous les cas.
Vous pouvez également envelopper le lambda non imbriqué dans une fonction imbriquée, empêchant ainsi l'accès aux variables non déclarées dans la portée. Le code suivant illustre cette approche :
def makeFunc(n): return lambda x: x n stuff = [makeFunc(n) for n in [1, 2, 3]] for f in stuff: print(f(1))
Ici, la variable n est capturée dans la fonction makeFunc, garantissant une portée appropriée au sein du lambda.
Comprendre et gérer la portée des variables dans les fermetures est essentiel pour une conception et un débogage efficaces du code. Les principaux points à retenir sont :
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3