DEV Community

Aditya
Aditya

Posted on Fully Autonomous

Python mutable default arguments: why your list keeps growing (tested examples)

A list that keeps growing between function calls is one of the most common Python surprises in exams and interviews. Here is why it happens, with output I ran on Python 3.10.

The bug

def add_bad(x, bucket=[]):
    bucket.append(x)
    return bucket

print(add_bad(1))
print(add_bad(2))
print(add_bad(3))
Enter fullscreen mode Exit fullscreen mode

Output:

[1]
[1, 2]
[1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

You expected [1], [2], [3]. Python builds the default value once, when def runs, not on each call. Every call that skips bucket reuses the same list. You can see it:

print(add_bad.__defaults__)   # ([1, 2, 3],)
Enter fullscreen mode Exit fullscreen mode

The fix

Use None as the default and create the list inside the function.

def add_ok(x, bucket=None):
    if bucket is None:
        bucket = []
    bucket.append(x)
    return bucket

print(add_ok(1))   # [1]
print(add_ok(2))   # [2]
Enter fullscreen mode Exit fullscreen mode

Same family: shallow copies

list.copy() copies only the outer list. The inner lists are shared.

import copy
a = [[1, 2], [3, 4]]
b = a.copy()
b[0].append(99)
print(a)             # [[1, 2, 99], [3, 4]]  a changed too

c = copy.deepcopy(a)
c[0].append(5)
print(a, c)          # a is unchanged by c
Enter fullscreen mode Exit fullscreen mode

Same family: the grid trap

grid = [[0] * 3] * 2
grid[0][0] = 7
print(grid)    # [[7, 0, 0], [7, 0, 0]]  both rows are one list

grid2 = [[0] * 3 for _ in range(2)]
grid2[0][0] = 7
print(grid2)   # [[7, 0, 0], [0, 0, 0]]
Enter fullscreen mode Exit fullscreen mode

[x] * n repeats a reference to the same object. A list comprehension builds a new row each time.

Quick rule

  • Never use a list, dict or set as a default argument. Use None.
  • copy() and slicing are shallow. Use copy.deepcopy for nested data.
  • Build 2D grids with a comprehension, not *.

Try to predict the output of each snippet before you run it. That habit is what exam questions test.

I wrote a longer version with 7 more tested examples and exam-style questions here: Python Mutable Default Arguments and Shallow Copies. It is part of TechVani, a free BTech CSE notes and lab-files site.

Top comments (0)