Python 2.7 setdefault/ defaultdict 代码如何给出嵌套结果?
How is this Python 2.7 setdefault/ defaultdict code giving a nested result?
这似乎是 setdefault
和 defaultdict
的一种非常直接的用法,我无法理解,如果有人能解释 "why" 下面的代码有效,那就太好了.
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 = t.setdefault(char,{})
执行时,它应该为 t 分配一个空字典,但它如何影响 d 以至于 d 最终成为一个嵌套字典?
此外,如果我要使用 defaultdict
,上面的等价物是什么?我想出这个是错误的:
d1 = defaultdict(dict)
for name in ['foo', 'bar', 'bars']:
t1 = d1
for char in name:
t1 = t1[char]
print d1
如果有人能指出应该如何理解 defaultdicts,那就太好了
对于第一部分,行 t = d
没有复制 d
。它只会创建对 d
的新引用并将其存储在 t
中。 t
和 d
现在指的是同一个对象;换句话说,您只有一个对象,但该对象有两个名称。由于该对象是一个可变对象(在本例中为字典),更改 t
也会更改 d
,因为只有一个对象。虽然这在这里是必要的,但如果出于某种原因在其他代码中您想要制作可变对象的副本并在不修改原始对象的情况下对副本进行操作,则需要 import copy
并使用 copy.deepcopy()
.
在第二个方面,defaultdict()
构造函数期望作为其第一个参数的可调用对象不接受任何参数,并且 return 是默认值。但是,对于这种情况,return 值需要是另一个带有可调用 returning 的 defaultdict 和另一个带有可调用 returning 的 defaultdict……等等。这是无限递归。
所以没有与此代码等效的 defaultdict。相反,带有 setdefault
和普通字典的原始版本可能是最好和最 Pythonic 的方式。
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
的内存位置中的内容,然后它 returns 内容然后它将新的内存位置分配给名称t
并将返回值赋给它。
t
和 d
的内存位置相同,这就是 d
受到影响的原因。
我将一步一步地完成循环,并解释它如何继续分配嵌套的字典:
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
这似乎是 setdefault
和 defaultdict
的一种非常直接的用法,我无法理解,如果有人能解释 "why" 下面的代码有效,那就太好了.
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 = t.setdefault(char,{})
执行时,它应该为 t 分配一个空字典,但它如何影响 d 以至于 d 最终成为一个嵌套字典?
此外,如果我要使用 defaultdict
,上面的等价物是什么?我想出这个是错误的:
d1 = defaultdict(dict)
for name in ['foo', 'bar', 'bars']:
t1 = d1
for char in name:
t1 = t1[char]
print d1
如果有人能指出应该如何理解 defaultdicts,那就太好了
对于第一部分,行 t = d
没有复制 d
。它只会创建对 d
的新引用并将其存储在 t
中。 t
和 d
现在指的是同一个对象;换句话说,您只有一个对象,但该对象有两个名称。由于该对象是一个可变对象(在本例中为字典),更改 t
也会更改 d
,因为只有一个对象。虽然这在这里是必要的,但如果出于某种原因在其他代码中您想要制作可变对象的副本并在不修改原始对象的情况下对副本进行操作,则需要 import copy
并使用 copy.deepcopy()
.
在第二个方面,defaultdict()
构造函数期望作为其第一个参数的可调用对象不接受任何参数,并且 return 是默认值。但是,对于这种情况,return 值需要是另一个带有可调用 returning 的 defaultdict 和另一个带有可调用 returning 的 defaultdict……等等。这是无限递归。
所以没有与此代码等效的 defaultdict。相反,带有 setdefault
和普通字典的原始版本可能是最好和最 Pythonic 的方式。
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
的内存位置中的内容,然后它 returns 内容然后它将新的内存位置分配给名称t
并将返回值赋给它。
t
和 d
的内存位置相同,这就是 d
受到影响的原因。
我将一步一步地完成循环,并解释它如何继续分配嵌套的字典:
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