Quand les arguments par défaut seront-ils liés en python? Lorsque les variables sont liées dans l'évaluation différée de la fermeture.

Mise en garde

Les termes et le libellé de Python sont assez suspects.

TLTR

Motivation

J'ai lu un article sur l'évaluation des délais python et je l'ai résumé.

Exemple 1 Quand l'argument par défaut d'une fonction est-il évalué?

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 **.

Parfois, l'argument par défaut = Aucun est bon

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.

Cause

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 ».

Solution

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é.

Exemple 2 Évaluation du délai de fermeture

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.

Cause

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) ».

Essayez de déboguer

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.

2020-05-192.gif

C'est difficile à comprendre, alors j'en posterai un autre.

2020-05-17.gif

Solution

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.

2020-05-193.gif

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.

Autres solutions

Il semble que vous devriez utiliser la bibliothèque. Cette fois, il est omis.

from functools import partial
from operator import mul

Résumé

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>

Postscript 19/05/2020

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.

Les références

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

Quand les arguments par défaut seront-ils liés en python? Lorsque les variables sont liées dans l'évaluation différée de la fermeture.
Soyez prudent lorsque vous spécifiez la valeur d'argument par défaut dans la série Python 3
Quand les arguments par défaut seront-ils liés en python? Lorsque les variables sont liées dans l'évaluation différée de la fermeture.
Python: variables de classe et d'instance
Variables de classe et d'instance Python
Les mines terrestres cachées dans les variables de classe Python
Quand le fichier mmap (2) sera-t-il mis à jour? (2)
Quand le fichier mmap (2) sera-t-il mis à jour? (1)
[Python] Soyez prudent lorsque vous utilisez print
[Python] Hériter d'une classe avec des variables de classe
[Python] Utiliser et et ou lors de la création de variables
Prédire quand l'ISS sera visible
Maîtrisez le type avec Python? (Quand faire la vérification de type)
Choses à surveiller lors de l'utilisation d'arguments par défaut en Python
python: utilisez les variables définies dans le format de chaîne telles quelles
Précautions lors de l'attribution de valeurs par défaut aux arguments dans les définitions de fonctions Python
Prédire quand l'ISS sera visible
Si vous ajoutez sudo dans ubuntu, il sera appelé le python par défaut.
Vous serez ingénieur dans 100 jours - Jour 29 - Python - Bases du langage Python 5
Vous serez ingénieur dans 100 jours - Jour 33 - Python - Bases du langage Python 8
Vous serez ingénieur dans 100 jours --Jour 26 --Python --Basiques du langage Python 3
Vous serez ingénieur dans 100 jours --Jour 32 --Python --Basiques du langage Python 7
Vous serez ingénieur dans 100 jours --Jour 28 --Python --Les bases du langage Python 4
Vérifiez si les caractères sont similaires en Python
Quand les fonctions python affectent-elles les arguments de l'appelant?
Utilisez pydantic lors de la lecture des variables d'environnement en Python
Que faire quand n'est pas dans le fichier sudoers. Cet incident sera signalé.
Remarque Python: lorsque la commande pip ne peut pas être utilisée
Paramètres initiaux lors de l'utilisation de l'API foursquare avec python
Obtenez des variables d'environnement en Python, sinon définissez les valeurs par défaut
Utilisation de l'application LibreOffice en Python (1) Où sont les macros?
Les arguments par défaut de Python ne sont pas initialisés à chaque appel
Élément de note Python efficace 20 Utilisez Aucun et la chaîne de documentation lors de la spécification d'arguments par défaut dynamiques