Same data structure, different output, depending on initialization method

Hi, I’ve been trying to initialize a list of empty dictionaries and then loop through them to add some keys to each dictionary, unfortunately it seems that I get different output based on how I initialize my data structure. Here is a simplified example:

rows=[{},{},{}]
print(rows)
print('****************************************')

for i in range(len(rows)):
    rows[i][i]=i+1
    print(rows)
    print('****************************************')

#OUTPUT:
#[{}, {}, {}]
#****************************************
#[{0: 1}, {}, {}]
#****************************************
#[{0: 1}, {1: 2}, {}]
#****************************************
#[{0: 1}, {1: 2}, {2: 3}]
#****************************************

The example above, where I’ve initialized my list of empty dictionaries with ‘[{ },{ },{ }]’ works as expected, I loop through my list and on each loop I add an item to the next dictionary. This is the intended behaviour. However, when I try to initialize with ‘[{ }]*3’ I get the following output:

#rows=[{},{},{}]
rows=[{}]*3
print(rows)
print('****************************************')

for i in range(len(rows)):
    rows[i][i]=i+1
    print(rows)
    print('****************************************')

#OUTPUT:
#[{}, {}, {}]
#****************************************
#[{0: 1}, {0: 1}, {0: 1}]
#****************************************
#[{0: 1, 1: 2}, {0: 1, 1: 2}, {0: 1, 1: 2}]
#****************************************
#[{0: 1, 1: 2, 2: 3}, {0: 1, 1: 2, 2: 3}, {0: 1, 1: 2, 2: 3}]
#****************************************

Here whenever I try to add an item to one dictionary instead it gets added to all dictionaries in a list and I cant figure out why?

The only difference between the examples above is how I’ve initialized my data structure, but It shouldn’t matter since I’ve ended up with the same structure at the start of the loop.

My guess is this does not create 3 unique objects in a list. Instead, it creates 3 elements with references to the same object.

I think that’s it. I’ve found something like this on geeksforgeeks:

Blockquote
This task can be performed using the “*” operator. We can create a list containing single empty dictionary and then multiply it by Number that is size of list. The drawback is that similar reference dictionaries will be made which will point to similar memory location.

Although I don’t really understand what similar means in the context of the last sentence. Anyway it seems that I can use this method instead:

rows=[{} for sub in range(3)]
print(rows)
print('****************************************')

for i in range(len(rows)):
    rows[i][i]=i+1
    print(rows)
    print('****************************************')

It seems to work, but do you know what are things like ‘[{ }] * 3’ or ‘[0] * 3’ called? Is it operator overloading for ‘*’ operator?

Right, ultimately it’s either different which shouldn’t be a problem or the same which is.