Les termes et le libellé de Python sont assez suspects.
TLTR
J'ai lu un article sur l'évaluation des délais python et je l'ai résumé.
Python peut définir des arguments par défaut. Cependant, ** les arguments par défaut de la fonction sont évalués lors de la définition de la fonction. Pas au moment de l'exécution. Ce sera un piège inattendu si vous ne connaissez pas la spécification de **.
Définissez une fonction append_to qui ajoute simplement les arguments passés à la liste. Il a une liste vide par défaut.
Ajouter pour ajouter un argument à la liste_Pour fonctionner
>>> def append_to(element, to=[]):
... to.append(element)
... return to
...
Ajoutons 12,42.
Parce qu'il y a un argument to = []
[12]
[42]
Il semble que.
>>> my_list = append_to(12)
>>> print(my_list)
[12]
>>> my_other_list = append_to(42)
>>> print(my_other_list)
[12, 42]
Ce n'est pas ce que vous attendiez. Qu'est-ce que ça veut dire.
L'argument par défaut de est défini comme «to = []». Nous mettrons à jour la valeur l'une après l'autre ici.
Si to = []
est évalué en train de devenir to = []
-> to = [12]
-> to = [12,42]
,
to = []
-> to = [12]
-> to = []
-> to = [42]
, ce qui semble donner le résultat souhaité, mais ** l'argument par défaut est une fonction Il sera évalué au moment de la définition. ** **
En d'autres termes, to est to = []
lors de la définition d'une fonction, mais ** ne fait pas to = []
chaque fois qu'il est appelé **, donc quand ʻappent_to (42) ,
to = [12] Cela signifie qu'il reste ».
Que faire à la place Il semble que «to = None» devrait être fait.
Cela semble un peu redondant. Je ne sais pas quoi faire.
def append_to(element, to=None):
if to is None:
to = []
to.append(element)
return to
my_list = append_to(12)
print(my_list)
my_other_list = append_to(42)
print(my_other_list)
[12]
[42]
J'ai obtenu le résultat souhaité.
Python peut faire une évaluation paresseuse. En gros, une évaluation retardée signifie une évaluation au besoin.
Si vous êtes un débutant comme moi qui apprend Python normalement, ce sera "Je sais! C'est celui que j'ai vu au ** séminaire".
Si vous allez écrire du code de taille moyenne à partir de maintenant, il est inévitable de concevoir les arguments par défaut de la fonction.
Cependant, il existe une telle spécification Python.
** La liaison de variable à la fermeture est évaluée différée **
Examinons un exemple de code qui utilise une soi-disant fermeture, où les valeurs sont stockées dans une fonction.
Le but est un code qui renvoie une liste avec le contenu de la liste multiplié par la valeur de l'argument.
Un script qui renvoie une liste avec le contenu de la liste multiplié par la valeur de l'argument
functions = []
for n in [1, 2, 3]:
def func(x):
return n * x
functions.append(func)
# You would expect this to print [2, 4, 6]
print('{}'.format(str([function(2) for function in functions])))
Il semble que [2, 4, 6]([1 * 2, 2 * 2, 3 * 2])
sera émis, mais ...
python
[6, 6, 6]
A été sortie.
les fermetures python sont évaluées différées. Les valeurs des variables utilisées dans la fermeture sont également référencées au moment de leur appel.
Par conséquent, n n'est pas fixé au moment où la fermeture est appelée dans l'instruction for, et il est stocké dans «functions» à l'état «n * x». Pour ainsi dire, [n * x, n * x, n * x]
Par conséquent, lorsqu'il est exécuté par l'instruction d'impression, le dernier état de n, n == 3
, est référencé, donc` [6,6,6]([3 * 2,3 * 2,3 * 2) ], X = 2) ».
Utilisons le débogueur pour voir l'ordre de mise à jour des valeurs des instructions for et print.
Puisque la valeur de la variable n a été mise à jour par l'itération pour être déjà 3, la fonction est évaluée par print tout le temps n == 3. Vous pouvez voir sur l'impression que n == 3 est référencé 3 fois.
C'est difficile à comprendre, alors j'en posterai un autre.
Changez l'argument de fermeture de «x» à «x, n = n». Le problème est résolu en passant la valeur de n, c'est-à-dire en passant la valeur de n aux fonctions qui stockent la fermeture chaque fois qu'elle est itérée avec une instruction for.
Pour ce faire, mettez la valeur de n dans l'argument, comme def func (x, n = n):
, et faites-le prendre la forme d'une réaffectation.
Cela permet à la fermeture de mettre à jour la valeur de n à partir de la spécification de conserver la valeur dans cette fonction.
Un script qui renvoie une liste avec le contenu de la liste multiplié par la valeur de l'argument
functions = []
for n in [1, 2, 3]:
def func(x, n=n):# n=Ajouté n.
# def func(x):
return n * x
functions.append(func)
print('{}'.format(str([function(2) for function in functions])))
Résultat de sortie
[2,4,6]
Jetons un coup d'œil au débogueur.
Je me demande si le comportement de func pourrait être bien exprimé avec le débogueur, mais j'ai pu le faire se comporter comme prévu.
Il semble que vous devriez utiliser la bibliothèque. Cette fois, il est omis.
from functools import partial
from operator import mul
Python effectue une évaluation paresseuse. C'est un peu déroutant lorsque vous effectuez une programmation procédurale régulière. C'est une fonction issue d'un langage fonctionnel, donc c'est un peu bizarre.
Je ne sais pas comment utiliser correctement la liaison de variable d'expression (affectation dans un langage fonctionnel) en Python. </ del>
Il y avait un point dans le commentaire.
J'ai écrit dans l'exemple 1 que les arguments par défaut de Python sont évalués différés. Mais c'était une mauvaise compréhension. L'argument par défaut de Python est une spécification qui est liée lorsqu'une fonction est déclarée, plutôt que d'être évaluée et liée différée. Il semble plus correct de se comporter de manière non intuitive comme dans l'exemple 1.
https://ja.coder.work/so/python/1087272 https://python-guideja.readthedocs.io/ja/latest/writing/gotchas.html https://stackoverflow.com/questions/36463498/late-binding-python-closures
Recommended Posts