You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python递归字典创建疑问:setdefault方法作用解析

Understanding dict.setdefault() Behavior in Trie Construction

The Code in Question

class StreamChecker(object):
    def __init__(self, words):
        """ :type words: List[str] """
        print(words)
        self.waitlist = []
        self.trie = dict()
        for word in words:
            temp_dict = self.trie
            for letter in word:
                temp_dict = temp_dict.setdefault(letter, dict())
            temp_dict['#'] = '#'
if __name__ == '__main__':
    a = StreamChecker(['abc', 'wef', 'ykj'])
    print(a.trie)

User's Confusion

After initialization, print(a.trie) outputs:
{'a': {'b': {'c': {'#': '#'}}}, 'w': {'e': {'f': {'#': '#'}}}, 'y': {'k': {'j': {'#': '#'}}}}

I'm confused by the line temp_dict = temp_dict.setdefault(letter, dict()): I thought setdefault always returns an empty dictionary {}, so why does self.trie keep getting updated? I expected self.trie to be {'a': {}, 'w': {}, 'y': {}} instead. Please explain.


Explanation

Hey there! The core of your confusion is a misunderstanding of what dict.setdefault() actually returns—it doesn't always give you an empty dictionary. Let's break this down step by step to see how the trie gets built correctly.

1. What setdefault() Really Does

dict.setdefault(key, default) has two key behaviors:

  • If the key already exists in the dictionary, it returns the existing value tied to that key.
  • If the key doesn't exist, it adds key: default to the dictionary, then returns the default value.

So the return value depends entirely on whether the key was present before the call—not just a blank dict every time.

2. Walkthrough of Trie Construction (Take 'abc' as an Example)

Let's trace how the first word 'abc' builds out self.trie:

  • Start with temp_dict = self.trie (which is an empty dict at first).
  • First letter 'a':
    • temp_dict.setdefault('a', dict()) sees that 'a' isn't in the empty dict, so it adds 'a': {} to self.trie and returns this new empty dict. Now temp_dict points to self.trie['a'], and self.trie becomes {'a': {}}.
  • Second letter 'b':
    • Now temp_dict is self.trie['a'] (still empty). setdefault('b', dict()) adds 'b': {} to this sub-dict and returns it. temp_dict now points to self.trie['a']['b'], and self.trie updates to {'a': {'b': {}}}.
  • Third letter 'c':
    • temp_dict is self.trie['a']['b']. setdefault('c', dict()) adds 'c': {} to this sub-dict and returns it. temp_dict points to self.trie['a']['b']['c'], making self.trie {'a': {'b': {'c': {}}}}.
  • Final step: temp_dict['#'] = '#' adds the end-of-word marker to self.trie['a']['b']['c'], turning it into {'#': '#'}.

3. Why self.trie Gets Modified

In Python, dictionaries are mutable objects—variables like temp_dict store references to the actual dict object, not a copy. When you operate on temp_dict, you're directly modifying the original dict (whether that's self.trie or one of its nested sub-dicts).

For example, when temp_dict = self.trie, both variables point to the same empty dict. Calling temp_dict.setdefault('a', dict()) modifies that shared dict, so self.trie immediately reflects the change. Later, when temp_dict points to a nested sub-dict, modifying it still alters the larger self.trie structure because it's all part of the same nested object.

4. Why Your Expected Result Was Wrong

You thought self.trie would only have empty sub-dicts because you assumed setdefault always returns a new blank dict. But in reality, after the first letter of each word, temp_dict is pointing to a nested sub-dict inside self.trie. Each subsequent setdefault fills in that sub-dict, building out the nested trie structure instead of leaving it empty.

内容的提问来源于stack exchange,提问作者Wenbin Xu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 17:18:13