I have been doing Django again for a personal project recently and found a very interesting thing about Python that I didn’t know.
If you know Python you probably also know that you can assign default values for method arguments, like so:
def file_path(name='default'):
return '/home/salva/' + name + '.csv'
You can either call this method with a parameter name or rely on the default value for it, which is ‘default’.
Cool! It can be very useful sometimes. Not all languages have this feature.
But there is something behind this feature that might not be very intuitive, at least it was not intuitive to me.
Let’s go a bit deeper, same example but now we will add a second argument, a date that defaults to now:
from datetime import datetime
import time
def file_path(name='default', date=datetime.now()):
day = date.strftime("%Y-%m-%d")
return '/home/salva/' + name + '-' + day + '.csv'
Now if we call this method without arguments, instead of returning ‘/home/salva/default.csv’ it should return something like ‘/home/salva/default-2020-12-21.csv’.
And it does, it works fine. The thing is, and here comes the fun part if you do this: that default date is only calculated once, even if you call this method multiple times. Look:
And if your program is a Django server that runs for days and days, that default date will always be the day when you restarted the server for the last time.
I had no idea default parameters worked like that!
What to do instead: default to None and add an if to handle the assignment inside the method manually. Yes it is sad but it works:
from datetime import datetime
import time
def file_path(name='default', date=None):
if date is None:
date = datetime.now()
day = date.strftime("%Y-%m-%d")
return '/home/salva/' + name + '-' + day + '.csv'
In fact there is more: default arguments in Python are mutable. Or more precisely, if the argument is a mutable type (like a list or a dict for example) you can actually change it in runtime. Yep, you can mutate default arguments in runtime 🤯
Well that’s it, be careful when using mutable default arguments in Python.