这个Python 2.7 setdefault / defaultdict代码如何给出嵌套结果?

时间:2016-12-04 05:53:17

标签: python python-2.7 dictionary nested defaultdict

这似乎是$Class->select_string('Some String')->SomeFunction()->AnotherFunction(); setdefault非常直接的使用,我无法理解,如果有人可以解释为什么"那将会很棒。以下代码有效。

defaultdict

我无法理解这段代码是如何工作的。当行d = {} for name in ['foo', 'bar', 'bars']: t = d for char in name: t = t.setdefault(char,{}) # Should be a empty {} print d # Prints {'b': {'a': {'r': {'s': {}}}}, 'f': {'o': {'o': {}}}} 执行时,它应该为t分配一个空字典,但它如何影响d使d最终成为嵌套字典?

此外,如果我使用t = t.setdefault(char,{}),那么上述内容将等同于什么。我想出了这个错误:

defaultdict

如果有人可以指出应该如何理解默认值

,那将会很棒

3 个答案:

答案 0 :(得分:1)

我将逐步完成循环,并解释如何分配嵌套的词组:

name = 'foo'
    t = d  # both t and d point to the same empty dict object
    char = 'f'
        t = t.setdefault(char,{})  
        # the first thing evaluated is the right hand side:
        # now d['f'] = {}, since that key wasn't in the dict
        # t points to the same object here
        # now the result of the left side (a new empty dict) is assigned to `t`.
        # this empty dict is also the exact *same* object referenced by d['f'] as well though!
        # so at this point d['f'] = {}, and t = {}, and both those dicts are the same!
    char = 'o'
        t = t.setdefault(char,{})  
        # eval the right side again, so now t['o'] = {}, but remember d['f'] == t
        # so really d['f'] = {'o':{}}
        # and again we assign the result of the right side to a brand new `t`
        # so now d['f']['o'] = {}, and t['o'] = {}, and these empty dicts are 
        # again referencing the same object
    char = 'o'
        t = t.setdefault(char,{})  
        # our `t` from last time is empty, so it gets assigned the same as before
        # and now d['f']['o']['o'] = {}
name = 'bar'
    t = d  # re-start this, but with d['f']['o']['o'] = {}
    char = 'b'
    #...everything proceeds as before - since 'b' is not in `d`, 
    # we start generating nested dicts again
    # ...
...
name = 'bars'
    # main difference here is that d['b']['a']['r'] exists, 
    # so we end up just adding the 's':{} to the end

至于defaultdict等价物,这有点棘手。 问题是你需要defaultdict的所有向下

我通过一个小函数here

找到了一种方法
from collections import defaultdict

def fix(f):
    return lambda *args, **kwargs: f(fix(f), *args, **kwargs)

d1 = fix(defaultdict)()

for name in ['foo', 'bar', 'bars']:
    t1 = d1
    for char in name:
        t1 = t1[char]

print d1

答案 1 :(得分:0)

对于第一部分,行t = d不会复制d。它只会创建对d的新引用,并将其存储在t中。 td现在指的是同一个对象;换句话说,您只有一个对象,但该对象有两个名称。由于该对象是一个可变对象(在这种情况下是一个dict),因为只有一个对象,更改t也会更改d。虽然这里有必要,但如果由于某种原因在其他代码中你想制作一个可变对象的副本并在副本上操作而不修改原文,你需要import copy并使用{{1} }。

第二,copy.deepcopy()构造函数需要一个不接受任何参数并返回默认值的callable作为其第一个参数。但是,对于这种情况,该返回值需要是另一个defaultdict,其中可调用返回另一个defaultdict,其中可调用返回另一个......等等。它是无限递归。

因此没有与此代码等效的defaultdict。相反,原始版本defaultdict()和简单的dicts可能是最好和最Pythonic的方式。

答案 2 :(得分:0)

setdefault如何在字典中工作

# case 1
d = {}
temp = d.setdefault("A")
print "d = ", d
print "temp = ", temp
print "id of d = ", id(d), "id of temp = ", id(temp)
# output
d = {'A': None}
temp = None
id of d = 140584110017624, id of temp = 9545840 # memory locations of d, temp

# case 2
d = {}
temp = d.setdefault("A", "default Value")
print "d = ", d
print "temp = ", temp
print "id of d = ", id(d), "id of temp = ", id(temp)
# output
d = {'A': "default Value"}
temp = "default Value"
id of d = 140584110017624, id of temp = 9545840 # memory locations of d, temp

我的代码t=d表示t和d的内存位置都相同 因此,当代码t = t.setdefault(char,{})执行首先t.setdefault(char,{})执行并更改t的内存位置中的内容时,它会返回内容,然后将新内存位置分配给名称t并将返回的值赋给它。 td的内存位置与d受影响的原因相同。