My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more
The List Mutability Pitfall in Python

The List Mutability Pitfall in Python

Maria Charman's photo
Maria Charman
·Aug 16, 2016

The other day, one of my friends asked me for help in debugging some Python code that she wrote. All she had to do was implement a triangle() function to make the following test pass.

def test_triangle():
    expected = [
        ['a'],
        ['aw'],
        ['awe'],
        ['awes'],
        ['aweso'],
        ['awesom'],
        ['awesome'],
    ]
    assert(triangle('awesome') == expected)

And this was her implementation of the triangle() function

def triangle(input_string):

    # constructing the base of the triangle
    triangle_list = [[] * len(input_string)]

    for index, element in enumerate(triangle_list):
        # element is the ith list in triangle_list
        element = [input_string[:index+1]]

    return triangle_list

She was having trouble with passing the test and was visibly frustrated with her inability to perceive her mistake. The output of her triangle() function was returning the following list, instead of what was expected in the above test.

[
    ['awesome'],
    ['awesome'],
    ['awesome'],
    ['awesome'],
    ['awesome'],
    ['awesome'],
    ['awesome']
]

Even after coding for quite a while in Python now, I had to look twice, scratch my head once, before I arrived at the correct solution, with a chuckle. Can you spot the mistake in her code?

The culprit is in the line with the initial triangle_list assignment

...
# constructing the base of the triangle
triangle_list = [[] * len(input_string)] 
...

This sort of a mistake happens more often than not, when you don't pay much attention to how you are manipulating your lists. What is happening in the above line of code is the same copy of the empty list object was being populated len("awesome"), i.e., 7 times, in triangle_list. You can verify it by checking the id of each object.

...
# constructing the base of the triangle
 triangle_list = [[] * len(input_string)] 

 for index, element in enumerate(triangle_list):
    # the following will print the same value for all elements in the loop    
    print(id(element))
    ...

Fortunately, as with everything else in Python, the fix was quite easy. Just had to make sure that a new "different" empty list was populated for every character in the string while # constructing the base of the triangle. Like so:

...
# constructing the base of the triangle
triangle_list = [[] for _ in range(len(input_string))]
...

This is my first story; and I would appreciate an upvote, if you have liked reading it. Thanks. :)