Ciao ... †
I've recently been plagued by unintended behavior with Python's default argument values, so I'd like to share information here so I don't repeat the same mistakes. This environment is Python 3.7.7 and 3.8.3.
Refers to dt = datetime.now ()
in the code below.
from datetime import datetime
def show_second(dt=datetime.now()):
print(dt.second)
I messed with the previous code to call the show_second
function once and then call the show_second
function again three seconds later.
import time
from datetime import datetime
def show_second(dt=datetime.now()):
print(dt.second)
show_second() #=> 23
time.sleep(3)
show_second() #=> 23
Then what do you mean! Even though I slept for 3 seconds, the value printed when calling the show_second
function for the second time was the same as 3 seconds ago ...! ?? Has time stopped? the world? ?? ?? Are you using a new stand? ?? ??
Well, when I read the Python documentation to see what this means, I found the following description.
The default argument value is evaluated from left to right when the function definition is executed. This means that the default argument expression is evaluated only once when the function is defined and the same "calculated" value is used for each call. from: https://docs.python.org/ja/3/reference/compound_stmts.html#function-definitions
In other words, the default argument value is evaluated once when the function is defined, the result is saved in the memory, and after that, when the default argument value is used no matter how many times the function is called, the evaluation result at the time of function definition is used. It seems that it is a mechanism.
Therefore, it is dangerous to use something like datetime.now ()
that gives a different result each time you call and / or something that requires real-time performance as the default argument value ⚠️
Similarly, it seems that you need to be careful when you specify a list or dictionary as the default argument value. (Usage and notes on default arguments in Python functions | note.nkmk.me)
Then, what to do is to set None
to the default argument value, and if it is None
, substitute the value that you originally wanted to set as the default argument value.
Below is the example 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
That's why I was talking about paying attention to Python's default argument values.
Recommended Posts