When I write the following code, my IDE warns about a "mutable default argument":
VALUES = [ 1, 2, 3 ]
def f(values=VALUES):
print(values)
It proposes to write this instead:
VALUES = [ 1, 2, 3 ]
def f(values=None):
if values is None:
values = VALUES
print(values)
Of course, this avoids having a (mutable) list as a default argument, and my IDE doesn't complain anymore. It appears to be an improvement.
But on the other hand, what was the original risk? The original risk was that f()
could modify the list in its code, e. g. like this:
VALUES = [ 1, 2, 3 ]
def f(values=VALUES):
values.append(4)
print(values)
This would have changed the value of VALUES
permanently (i. e. not just locally) and later calls to f()
would still have the changed value as a default which is probably not intended. Furthermore, given the code above, VALUES
would grow by one 4
with each call to f()
. So this situation probably isn't as intended unless values
in f()
isn't changed which is hard to enforce.
But does the IDE-proposed "fix" solve the issue?
I think not because if the code of f()
now contained a values.append(4)
, the same thing would happen again:
def f(values=None):
if values is None:
values = VALUES
values.append(4)
print(values)
Again, each call would make VALUES
grow by one 4
.
A real fix would be this:
def f(values=None):
if values is None:
values = VALUES.copy() # or VALUES[:] or similar
values.append(4)
print(values)
But this the IDE does not propose and of course it would be costly because copies are made each time.
Other questions already deal with this problem (e. g. Why does using None fix Python's mutable default argument issue?) but in that ticket they do not use a constant like VALUES
but a literal []
which creates a new value each time the code is executed, so it is similar to the .copy()
approach.
Now the questions:
Why does any IDE propose this fix (in this case with a constant)? Does it maybe fix other aspects of this problem I haven't thought about?
Is there a better way to fix the original problem which doesn't have at least one of the two problems (① default value might change unexpectedly, ② costly copying of a value)?