Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird Extra Looping

I'm still a bit new to Python, but, I feel really stupid right now 'cause I've just spent an hour trying to figure out why this for loop isn't doing what I want. I shouldn't be spending an hour on a for loop. Anyway, I'm trying to generate a list of dictionaries, and give them each a unique number, so I do this...

def initiate(n):
    records = {'num':0,'blah':0,'doubleblah':0}
    x = []
    for i in range(n):
        x.append(records)
        x[i]['num'] = i
    return x

x = initiate(4)
print(x)

I expect the function to return this --

[
 {'num': 0, 'doubleblah': 0, 'blah': 0}, 
 {'num': 1, 'doubleblah': 0, 'blah': 0}, 
 {'num': 2, 'doubleblah': 0, 'blah': 0}, 
 {'num': 3, 'doubleblah': 0, 'blah': 0}
]

But it actually returns this --

[
 {'num': 3, 'doubleblah': 0, 'blah': 0}, 
 {'num': 3, 'doubleblah': 0, 'blah': 0}, 
 {'num': 3, 'doubleblah': 0, 'blah': 0}, 
 {'num': 3, 'doubleblah': 0, 'blah': 0}
]

...when I add a few print statements into the function, I discover that it seems to be adding the number to every dictionary in the list, instead of just the current dictionary. I really don't see how the code would add to all the dict's, since I explicitly use x[i] = i to add the number to the current dictionary only.

like image 940
Zamphatta Avatar asked Oct 22 '12 18:10

Zamphatta


1 Answers

What's happening is that you're appending a reference to the same dictionary to the list each time.

print list(map(id, initiate(4)))
# [42283920, 42283920, 42283920, 42283920]

Your function is correctly written as:

def initiate(n):
    return [ {'num': i, 'blah': 0, 'doubleblah': 0} for i in range(n) ]

This produces a new instance of a dictionary each time.

like image 100
Jon Clements Avatar answered Oct 04 '22 16:10

Jon Clements