⚠️ Méfiez-vous des valeurs d'argument par défaut de Python ⚠️

Chao ... †

J'ai récemment été en proie à un comportement involontaire avec les valeurs d'argument par défaut de Python, donc j'aimerais partager des informations ici afin de ne pas répéter les mêmes erreurs. Cet environnement est Python 3.7.7 et 3.8.3.

Quelle est la valeur d'argument par défaut?

Se réfère à «dt = datetime.now ()» dans le code ci-dessous.

from datetime import datetime


def show_second(dt=datetime.now()):
    print(dt.second)

Piège de valeur d'argument par défaut Python

J'ai manipulé le code précédent pour appeler la fonction show_second une fois, puis appeler à nouveau la fonction show_second trois secondes plus tard.

import time
from datetime import datetime


def show_second(dt=datetime.now()):
    print(dt.second)

show_second()  #=> 23
time.sleep(3)
show_second()  #=> 23

Alors qu'est-ce que tu veux dire! Même si j'ai dormi 3 secondes, la valeur imprimée lors de l'appel de la fonction show_second pour la deuxième fois était la même qu'il y a 3 secondes ...! ?? Le temps s'est-il arrêté? le monde? ?? ?? Utilisez-vous un nouveau stand? ?? ??

Comportement des valeurs d'argument par défaut de Python

Eh bien, quand j'ai lu le document Python ce que cela signifie, j'ai trouvé la description suivante.

La valeur de l'argument par défaut est évaluée de gauche à droite lorsque la définition de fonction est exécutée. Cela signifie que l'expression d'argument par défaut n'est évaluée qu'une seule fois lorsque la fonction est définie et que la même valeur «calculée» est utilisée pour chaque appel. from: https://docs.python.org/ja/3/reference/compound_stmts.html#function-definitions

En d'autres termes, la valeur de l'argument par défaut est évaluée une fois lorsque la fonction est définie, le résultat est enregistré dans la mémoire, et après cela, lorsque la valeur de l'argument par défaut est utilisée quel que soit le nombre d'appels de la fonction, le résultat de l'évaluation au moment de la définition de la fonction est utilisé. Il semble que ce soit un mécanisme.

Par conséquent, il est dangereux d'utiliser quelque chose comme datetime.now () qui donne un résultat différent à chaque fois que vous appelez et / ou quelque chose qui nécessite des performances en temps réel comme valeur d'argument par défaut ⚠️

De même, il semble que vous deviez être prudent lorsque vous spécifiez une liste ou un dictionnaire comme valeur d'argument par défaut. (Utilisation et précautions des arguments par défaut dans les fonctions Python | note.nkmk.me)

Contre-mesures pour les valeurs d'argument par défaut de Python

Ensuite, ce qu'il faut faire est de définir «Aucun» sur la valeur d'argument par défaut, et s'il s'agit de «Aucun», remplacez la valeur que vous vouliez à l'origine définir comme valeur d'argument par défaut.

Voici l'exemple de code.

import time
from datetime import datetime


def show_second(dt=None):
    if dt is None:
        dt = datetime.now()
    print(dt.second)

show_second()  #=> 23
time.sleep(3)
show_second()  #=> 26

C'est pourquoi je parlais de prêter attention aux valeurs d'argument par défaut de Python.

Recommended Posts

⚠️ Méfiez-vous des valeurs d'argument par défaut de Python ⚠️
Soyez prudent avec la méthode append de Python
[Introduction à Udemy Python3 + Application] 51. Soyez prudent avec les arguments par défaut
Soyez prudent avec les références de méthodes faciles
(Note) Soyez prudent avec python argparse
Soyez prudent lorsque vous exécutez CakePHP3 avec PHP7.2
Je voulais faire attention au comportement des arguments par défaut de Python
Soyez prudent lorsque vous travaillez avec des fichiers texte compressés au format gzip
Soyez prudent lors de la lecture de données avec des pandas (spécifiez dtype)
piège d'argument par défaut de python
[Python3] Soyez prudent avec le décapage (strip, lstrip, rstrip)