Why did dict.get(key) work but not dict[key]?

The problem is mutability:

one_groups = dict.fromkeys(range(5), []) - this passes the same list as value to all keys. So if you change one value, you change them all.

It's basically the same as saying:

tmp = []
one_groups = dict.fromkeys(range(5), tmp)
del tmp

If you want to use a new list, you need to do it in a loop - either an explicit for loop or in a dict comprehension:

one_groups = {key: [] for key in range(5)}

This thing will "execute" [] (which equals to list()) for every key, thus making the values with different lists.


Why does get work? Because you explicitly take the current list, but + makes a new result list. And it doesn't matter whether it's one_groups[x.count('1')] = one_groups.get(x.count('1')) + [x] or one_groups[x.count('1')] = one_groups[x.count('1')] + [x] - what matters is that there's +.

I know how everybody says a+=b is just a=a+b, but the implementation may be different for optimisation - in case of lists, += is just .extend because we know we want our result in the current variable, so creating new list would be waste of memory.


The problem is using one_groups = dict.fromkeys(range(5), [])

(This passes the same list as value to all keys. So if you change one value, you change them all)


You can use this instead: one_groups = {i:[] for i in range(5)}

(This thing will "execute" [] (which equals to list()) for every key, thus making the values with different lists.)


This is the help on dict's fromkeys method.

Help on built-in function fromkeys:

fromkeys(iterable, value=None, /) method of builtins.type instance Create a new dictionary with keys from iterable and values set to value

That says that fromkeys will accept a value, and even it is a callable, it will evaluate it first, and then assign that value to all the dict keys.

Lists are mutable in Python, and so it will assign the same empty list reference and one change will affect them all.

Use defaultdict instead as so:

>>> from collections import defaultdict
>>> one_groups = defaultdict(list)
>>> for x in binaries:
      one_groups[x.count('1')] += [x]
>>> one_groups = dict(one_groups) # to stop default dict behavior

This will accept assignments to non-existing keys and values will default to empty lists (in this case).