I encountered this strange, counter-intuitive behaviour when assigning a default value to a dictionary parameter of a function. Suppose I have the following code:
def test_fn(d = dict()):
import time
for k, v in d.items():
print(f'{k}\t{v}')
d[time.ctime()] = 'AAAAAAAAAAGH'
Repeatedly running this function in my favourite IDE produces the following output:
>>> test_fn()
>>> test_fn()
Fri Dec 7 21:35:31 2018 AAAAAAAAAAGH
>>> test_fn()
Fri Dec 7 21:35:31 2018 AAAAAAAAAAGH
Fri Dec 7 21:35:32 2018 AAAAAAAAAAGH
>>> test_fn()
Fri Dec 7 21:35:31 2018 AAAAAAAAAAGH
Fri Dec 7 21:35:32 2018 AAAAAAAAAAGH
Fri Dec 7 21:35:34 2018 AAAAAAAAAAGH
>>> test_fn()
Fri Dec 7 21:35:31 2018 AAAAAAAAAAGH
Fri Dec 7 21:35:32 2018 AAAAAAAAAAGH
Fri Dec 7 21:35:34 2018 AAAAAAAAAAGH
Fri Dec 7 21:35:35 2018 AAAAAAAAAAGH
et cetera. Now, to my intuition, explicitly assigning d = dict()
as a default parameter should create a new instance of the dict
class every time the function is run, and certainly this variable should only exist locally. Indeed, if I try and access d
outside of test_fn
, I of course get a NameError
:
>>> d
Traceback (most recent call last):
File "<ipython-input-9-e983f374794d>", line 1, in <module>
d
NameError: name 'd' is not defined
And yet clearly Python is treating d
as a global object in some sense, because it grows whenever the function is run.
Does anyone have any explanation for this behaviour? It seems quite non-Pythonic to me. Is this a deliberate design feature? Regardless of whether it is good practice to silently pass an empty dict
as default, is there a way to actually force Python to create a new one every time the function runs?