Cer*_*rno 46 python dictionary get setdefault
以下两个表达式似乎与我相同.哪个更好?
data = [('a', 1), ('b', 1), ('b', 2)]
d1 = {}
d2 = {}
for key, val in data:
# variant 1)
d1[key] = d1.get(key, []) + [val]
# variant 2)
d2.setdefault(key, []).append(val)
Run Code Online (Sandbox Code Playgroud)
结果是一样的,但哪个版本更好或更富有pythonic?
就个人而言,我觉得版本2难以理解,因为对我而言,setdefault非常难以掌握.如果我理解正确,它会在字典中查找"key"的值,如果不可用,则在"dict"中输入"[]",返回对值或"[]"的引用,并在其中附加"val"参考.虽然顺利但它至少不是直观的(至少对我而言).
在我看来,版本1更容易理解(如果可用,获取"key"的值,如果没有,获取"[]",然后加入由[val]组成的列表并将结果放在"key"中).但是,虽然更直观地理解,但我担心这个版本的性能会降低,所有这些列表都会创建.另一个缺点是"d1"在表达式中出现两次,这是相当容易出错的.可能有一个更好的实现使用get,但目前它没有我.
我的猜测是版本2虽然对于没有经验的人来说更难掌握,但速度更快,因此更可取.意见?
agf*_*agf 25
你的两个例子做了同样的事情,但这并不意味着get
和setdefault
做.
两者之间的差异基本上是每次手动设置d[key]
指向列表,而不是仅在未设置时setdefault
自动设置d[key]
到列表.
让这两种方法尽可能相似,我跑了
from timeit import timeit
print timeit("c = d.get(0, []); c.extend([1]); d[0] = c", "d = {1: []}", number = 1000000)
print timeit("c = d.get(1, []); c.extend([1]); d[0] = c", "d = {1: []}", number = 1000000)
print timeit("d.setdefault(0, []).extend([1])", "d = {1: []}", number = 1000000)
print timeit("d.setdefault(1, []).extend([1])", "d = {1: []}", number = 1000000)
Run Code Online (Sandbox Code Playgroud)
得到了
0.794723378711
0.811882272256
0.724429205999
0.722129751973
Run Code Online (Sandbox Code Playgroud)
所以setdefault
比get
此目的快10%左右.
该get
方法允许您尽可能少地使用setdefault
.KeyError
即使您不想设置密钥,也可以使用它来避免在密钥不存在时(如果这种情况经常发生).
请参阅"setdefault"dict方法的用例,dict.get()方法返回指针,以获取有关这两种方法的更多信息.
关于setdefault
大多数时候,你想要使用的结论defaultdict
.线程get
得出的结论是它很慢,并且通常你最好(速度明智)做双重查找,使用defaultdict或处理错误(取决于字典的大小和你的用例).
Dun*_*can 16
agf接受的答案并不是与之相比.后:
print timeit("d[0] = d.get(0, []) + [1]", "d = {1: []}", number = 10000)
Run Code Online (Sandbox Code Playgroud)
d[0]
包含一个包含10,000个项目的列表,而在:
print timeit("d.setdefault(0, []) + [1]", "d = {1: []}", number = 10000)
Run Code Online (Sandbox Code Playgroud)
d[0]
很简单[]
.即d.setdefault
版本永远不会修改存储的列表d
.代码应该是:
print timeit("d.setdefault(0, []).append(1)", "d = {1: []}", number = 10000)
Run Code Online (Sandbox Code Playgroud)
事实上比错误的setdefault
例子更快.
这里的区别实际上是因为当你使用串联追加时,每次都会复制整个列表(并且一旦你有10,000个元素开始变得可测量.使用append
列表更新是分摊O(1),即有效的恒定时间.
最后,在原始问题中还没有考虑其他两个选项:defaultdict
或者只是测试字典以查看它是否已包含密钥.
所以,假设 d3, d4 = defaultdict(list), {}
# variant 1 (0.39)
d1[key] = d1.get(key, []) + [val]
# variant 2 (0.003)
d2.setdefault(key, []).append(val)
# variant 3 (0.0017)
d3[key].append(val)
# variant 4 (0.002)
if key in d4:
d4[key].append(val)
else:
d4[key] = [val]
Run Code Online (Sandbox Code Playgroud)
变体1是迄今为止最慢的,因为它每次复制列表,变量2是第二慢,变体3是最快的但是如果你需要早于2.5的Python则不会工作,而变体4只比变体3略慢.
如果可以的话,我会说使用变体3,变量4作为选项,适用于那些defaultdict
不太合适的偶然地方.避免使用两种原始变体.
pyA*_*ict 11
对于那些仍在努力理解这两个术语的人,让我告诉您 get() 和 setdefault() 方法之间的基本区别 -
场景一
root = {}
root.setdefault('A', [])
print(root)
Run Code Online (Sandbox Code Playgroud)
场景 2
root = {}
root.get('A', [])
print(root)
Run Code Online (Sandbox Code Playgroud)
在场景 1 中的输出将{'A': []}
在场景 2 中{}
因此setdefault()
,在字典中设置不存在的键,同时get()
只为您提供默认值,但不会修改字典。
现在让我们来看看这将是有用的 - 假设您正在字典中搜索其值为列表的元素,并且您想要修改该列表,如果找到,则使用该列表创建一个新键。
使用 setdefault()
def fn1(dic, key, lst):
dic.setdefault(key, []).extend(lst)
Run Code Online (Sandbox Code Playgroud)
使用 get()
def fn2(dic, key, lst):
dic[key] = dic.get(key, []) + (lst) #Explicit assigning happening here
Run Code Online (Sandbox Code Playgroud)
现在让我们检查时间 -
dic = {}
%%timeit -n 10000 -r 4
fn1(dic, 'A', [1,2,3])
Run Code Online (Sandbox Code Playgroud)
耗时 288 纳秒
dic = {}
%%timeit -n 10000 -r 4
fn2(dic, 'A', [1,2,3])
Run Code Online (Sandbox Code Playgroud)
花了 128 秒
因此,这两种方法之间存在非常大的时序差异。
gri*_*ton 10
您可能希望defaultdict
在collections
模块中查看.以下等同于您的示例.
from collections import defaultdict
data = [('a', 1), ('b', 1), ('b', 2)]
d = defaultdict(list)
for k, v in data:
d[k].append(v)
Run Code Online (Sandbox Code Playgroud)
还有更多的在这里.
1.在此处用一个很好的例子进行解释:http :
//code.activestate.com/recipes/66516-add-an-entry-to-a-dictionary-unless-the-entry-is-a/
字典 setdefault典型用法
somedict.setdefault(somekey,[]).append(somevalue)
字典 获得典型用法
theIndex[word] = 1 + theIndex.get(word,0)
2.更多说明:http : //python.net/~goodger/projects/pycon/2007/idiomatic/handout.html
dict.setdefault()
等于get
或set & get
。或者set if necessary then get
。如果您的字典键计算起来很昂贵或键入时间很长,则特别有效。
dict.setdefault()的唯一问题是,是否需要始终评估默认值。这只是重要的如果默认值是计算昂贵。在这种情况下,请使用defaultdict。
3.最后,不同之处的官方文档突出显示了 http://docs.python.org/2/library/stdtypes.html
get(key[, default])
如果key在字典中,则返回key的值,否则返回默认值。如果未提供default,则默认为None,因此此方法永远不会引发KeyError。
setdefault(key[, default])
如果key在字典中,则返回其值。如果不是,请插入具有默认值的密钥,然后返回默认值。默认默认为无。
归档时间: |
|
查看次数: |
37064 次 |
最近记录: |