0

As shown by the following two code snippets, the order of the chained assignment matters (i.e. node = node[ch] = {} is not equivalent to node[ch] = node = {}.

trie = {}
node = trie
for ch in "word":
    if ch in node:
        node = node[ch]
    else:
        node = node[ch] = {} # chained assignment #1
print(trie) # {}
trie = {}
node = trie
for ch in "word":
    if ch in node:
        node = node[ch]
    else:
        node[ch] = node = {} # chained assignment #2
print(trie) # {'w': {'o': {'r': {'d': {}}}}}

Why does the order matter?


According to another SO question, the chained assignment

a = b = c

is equivalent to:

tmp = c
a = c
b = c

and I verified that the equivalent forms produced the same behavior. I.e.

        # node = node[ch] = {} # chained assignment #1
        tmp = {}
        node = tmp
        node[ch] = tmp

leads to a print(trie) of {}.

Meanwhile

        node[ch] = node = {} # chained assignment #2
        tmp = {}
        node[ch] = tmp
        node = tmp

leads to a print(trie) of {'w': {'o': {'r': {'d': {}}}}}.

joseville
  • 685
  • 3
  • 16
  • 3
    Backing up from your "why" question, what's the behavior you _want_? – Charles Duffy Jun 02 '21 at 21:42
  • 3
    In particular, do you want `node` and `node[ch]` to point to the same dict instance, or do you want them each to have a separate dict? When you have `a = b = {}`, there's only one new dict created. – Charles Duffy Jun 02 '21 at 21:43
  • 1
    I suspect that using `defaultdict` may make a lot of sense in your use case, insofar as your goal is being able to tersely define nested dictionaries. – Charles Duffy Jun 02 '21 at 21:44
  • 1
    `def dict_of_dicts(): return collections.defaultdict(dict_of_dicts)` means that if you specify `trie = dict_of_dicts()`, you can then run `trie['a']['b']['c'] = {}` without previously initializing `trie['a']` or `trie['a']['b']`. – Charles Duffy Jun 02 '21 at 21:48
  • @CharlesDuffy thanks! I wanted the behavior of the second chained assignment. (Sorry for the delay in replying.) – joseville Jun 15 '21 at 18:02

1 Answers1

4

You basically answered your question at the end.

node = tmp
node[ch] = tmp

and

node[ch] = tmp
node = tmp

are not equivalent. As soon as you do node = tmp, you lose the previous contents of node, and replace them with a new dict. That means that in the first case, you immediately lose the reference to trie inside the loop, and can no longer mutate it. In the second case, you alter the old results, then reassign node to the new dictionary.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117