python dict setdefault,困惑

use*_*583 8 python

python新手.我今天看了一个算法,我无法弄清楚为什么dict d中有值,而curr没有.对我来说,似乎没有任何事情要做到dict d.

>>> def what(*words):
...     d = {}
...     print d
...     for word in words:
...     print 'word: ' + word
...         curr = d
...         for letter in word:
...             curr = curr.setdefault(letter, {})
...         curr = curr.setdefault('.', '.')
...     print d
...     print '?'
...     print curr
...     return 1
... 
>>> what('foo') 
{}
word: foo
{'f': {'o': {'o': {'.': '.'}}}}
?
.
1
Run Code Online (Sandbox Code Playgroud)

Bak*_*riu 11

阅读文档dict.setdefault:它就像是,get但如果密钥不存在,那么它也设置:

>>> my_dict = {}
>>> my_dict.setdefault('some key', 'a value')
'a value'
>>> my_dict
{'some key': 'a value'}
>>> my_dict.get('some key2', 'a value2')
'a value2'
>>> my_dict
{'some key': 'a value'}
Run Code Online (Sandbox Code Playgroud)

修改一下你的例子:

>>> def what(*words):
...     d = dict()
...     for word in words:
...             curr = d
...             for letter in word:
...                     curr = curr.setdefault(letter, {})
...             curr = curr.setdefault('.', '.')
...             print 'curr is now: %r while d is %r' % (curr, d)
... 
>>> what('foo')
curr is now: '.' while d is {'f': {'o': {'o': {'.': '.'}}}}
Run Code Online (Sandbox Code Playgroud)

正如您可以看到curr更改,因为setdefault有时(在您的示例中始终)调用它时,创建一个new dict并将其设置为值curr,同时d始终引用原始值dict.正如你所看到的,它在循环之后修改,因为它的值与{'f': {'o': {'o': {'.': '.'}}}}它完全不同{}.

也许你的困惑是由于这样的事实,curr = curr.setdefault(letter, {}) 总是创建一个新的空的 dict,然后将其分配给curr(从而为每一个字母你一个嵌套级别添加到原来dict的而不是覆盖值).

看到这个:

>>> my_dict = {}
>>> curr = my_dict
>>> for letter in 'foo':
...     print 'my_dict is now %r. curr is now %r' % (my_dict, curr)
...     curr = curr.setdefault(letter, {})
... 
my_dict is now {}. curr is now {}
my_dict is now {'f': {}}. curr is now {}
my_dict is now {'f': {'o': {}}}. curr is now {}
>>> my_dict
{'f': {'o': {'o': {}}}}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,每个级别my_dict都有一个新的嵌套级别.

也许,但我只是猜测,你想获得类似的东西'foo' -> {'f': {}, 'o': {}},在这种情况下你应该这样做:

>>> my_dict = {}
>>> for letter in 'foo':
...     my_dict.setdefault(letter, {})
... 
>>> my_dict
{'o': {}, 'f': {}}
Run Code Online (Sandbox Code Playgroud)


小智 5

d = dict()--> 初始化一个空字典并将其绑定到名称d;所以你有一个按名称引用的字典对象 ( {})d

在外部 for 循环内
curr = d--> 将另一个名称绑定curr到同一个对象。所以,名称(dcurr引用同一个对象)

在内部 for 循环
中 在第一次迭代期间letter = 'f'

curr = curr.setdefault(letter, {})
Run Code Online (Sandbox Code Playgroud)

上面的语句中发生了两件事,

A) curr.setdefault(letter, {})--> 根据文档:

“如果key在字典中,则返回它的值。如果没有,则插入值为default的key并返回default。default默认为None。”。

由于字母 'f' 不在初始字典对象中,因此它会将初始对象更改为{'f':{}}并返回 value {},该值不是初始字典对象,而是由于 setdefault 语句而创建的一个新对象。此时 和currd指的是初始字典对象,该对象已变异为{'f':{}}

B) 将名称重新分配curr给上面提到的返回值。现在,名称currd的是不同的对象。d指的是对象{'f':{}},而curr指的是一个空字典对象,它实际上是 的值d['f']。这就是当我们进行循环时嵌套发生在原始字典对象中的原因。