python dict setdefault,困惑

时间:2013-03-21 18:45:45

标签: python

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

>>> def what(*words):
...     d = dict()
...     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

3 个答案:

答案 0 :(得分:9)

阅读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'}

稍微修改一下你的例子:

>>> 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': {'.': '.'}}}}

正如您可以看到curr更改一样,因为在调用setdefault时,有时会(在您的示例中始终)创建新的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': {}}}}

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

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

>>> my_dict = {}
>>> for letter in 'foo':
...     my_dict.setdefault(letter, {})
... 
>>> my_dict
{'o': {}, 'f': {}}

答案 1 :(得分:2)

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

引用的字典对象(d

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

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

期间
curr = curr.setdefault(letter, {})

上述陈述中有两件事情发生,

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

  

“如果密钥在字典中,则返回其值。如果不是,请插入值为default的密钥并返回默认值。默认默认为无。”。

因为字母'f'不在初始字典对象中,它将初始对象变为{'f':{}}并返回值{},它不是初始字典对象,而是新字典对象由于setdefault语句而创建的。此时,currd都引用了从而变异为{'f':{}}的初始字典对象。

B)将名称curr重新分配给上述返回值。现在,名称currd引用不同的对象。 d引用对象{'f':{}},而curr引用空字典对象,实际上是d['f']的值。 这就是为什么嵌套发生在原始字典对象中,因为我们经历了循环。

答案 2 :(得分:0)

setdefault(key[, default)

来自the docs

  

如果key在字典中,请返回其值。如果不是,请插入值为key的{​​{1}}并返回defaultdefault默认为default

用法示例

None

在您的代码中

我认为您很困惑,因为>>> d = {'a': 1, 'b': 2, 'c': 3} >>> d.setdefault('a') # returns the corresponding value for key 'a' 1 >>> d.setdefault('a', 10) # returns the corresponding value for key 'a' 1 >>> d.setdefault('b') # returns the corresponding value for key 'b' 2 >>> d.setdefault('c', 100) # returns the corresponding value for key 'c' 3 >>> type(d.setdefault('z')) # because 'z' is not a key of d, None is returned which is the default value of default <class 'NoneType'> >>> d.setdefault('z', 666) # returns 666 since key 'z' is not in d 666 总是创建一个新的空字典,然后将其分配给curr = curr.setdefault(letter, {})。这意味着您要覆盖curr中的每个元素,而不是覆盖值,而是向原始字典添加嵌套级别。

我还认为,您要用代码实现的目标是创建一个字典,将words中的每个元素作为键,并以words作为值,因此您可以使用以下代码来实现使用 dict-comprehension

{}

注意:,我已经添加了def what(*words): return {word: {} for word in set(words)} 的说明,因为您的问题已特别针对此情况进行了查看,但我也想涵盖您的特定问题。