Tricked again by Python's mutable objects

& (verbiage overflow)Sun 18 March 2012RSS

In order to keep a running count of a group of things, I created a Python dictionary d, with its keys populated from unique members of a list list_of_counters and its values set uniformly to 0:

d = {}.fromkeys(set(list_of_counters), 0)

I used set() to ensure that only one unique copy of each element of list_of_counters was used, and all went well. Each item in the dictionary functioned as an independent counter.

Later, I realized that I needed to keep track of two things for each counter, rather than one. No problem; I replaced the 0 above with a list [0, 0], one index for each thing to be kept track of.

d = {}.fromkeys(set(list_of_counters), [0, 0])

Disaster! Every time I updated one index for any particular item, the same index was changed for all the items.

My error was to use a list to populate a dictionary's values using a single list. Since lists are mutable objects in Python, they are passed by reference. So there was only a single list being used as the value for all the keys in the dictionary; when one copy of it was updated, all were changed to match it.

The solution is to populate the initial values using a loop, rather than all at once. For instance:

d = {}.fromkeys(set(list_of_counters))

for i in d:

    d[i] = [0, 0]

A comprehension can also be used. In the intial creation of the dictionary, the values can be left empty.

[end]

Comments are enabled.