Python 字典中的列表追加操作

151

有没有更优雅的写法?

我的做法是:我有一些键和日期。一个键可以对应多个日期,因此我创建了一个字典来表示这些日期列表。下面的代码能够正常工作,但我希望有一种更加优雅和Pythonic的方法。

dates_dict = dict() 
for key,  date in cur:
    if key in dates_dict:
        dates_dict[key].append(date)
    else:
        dates_dict[key] = [date] 
我本以为下面的代码可以运行,但是却一直出现“NoneType”没有“append”属性的错误。
dates_dict = dict() 
for key,  date in cur:
    dates_dict[key] = dates_dict.get(key, []).append(date) 

这可能与事实有关

print([].append(1)) 
None 

但为什么?


4
你应该查看collections.defaultdict。它是Python的一个库,可以帮助你创建默认值为特定数据类型的字典。这可以使代码更加简洁和易于阅读。你可以在Python的文档中找到更多关于collections.defaultdict的信息。 - Cory Kramer
2
你可以尝试使用extend()而不是append()。 - weefwefwqg3
2
for key, date in cur: - cur 是什么? - Mawg says reinstate Monica
2
@Mawg 这是一段时间之前的事情了,但我可能正在使用与Python的sqlite3库相关联的游标对象。 - Michael Murphy
3个回答

241

list.append 返回 None,因为它是一个原地操作,并且您将其分配回 dates_dict[key]。所以,下一次当您执行 dates_dict.get(key, []).append 时,实际上是在执行 None.append。这就是它失败的原因。相反,您可以简单地进行以下操作:

dates_dict.setdefault(key, []).append(date)

但是,我们只需要使用 collections.defaultdict 就可以实现这个目的。你可以像这样做:

from collections import defaultdict
dates_dict = defaultdict(list)
for key, date in cur:
    dates_dict[key].append(date)

如果字典中不存在该key,则会创建一个新的列表对象。

注意:由于defaultdict会在字典中找不到键时创建一个新列表,因此这可能会产生意外的副作用。例如,如果您只想获取不存在的键的值,则会创建一个新列表并返回它。


2
请注意,__missing __()仅适用于__getitem __()之外的任何操作。这意味着get()将像普通字典一样返回None作为默认值,而不是使用default_factory,即key in dates_dictdates_dict.get(key)按预期工作。 - jfs
1
作为后续。最终我使用了 setdefault,这样可以在不需要额外导入的情况下获得我想要的准确结果。感谢帮助。 - Michael Murphy
1
你对于[].append返回None的解释让我感到困惑。如果你立即进行赋值或打印,那么它是一个原地操作又有什么关系呢?除非dates_dict[key] == None,否则为什么dates_dict.get(key, []).append会产生None呢? - cfwschmidt
1
没错!在其中一个迭代中,append的结果存储在键值对中,然后使用get检索并进行了附加。但是这一次它不是列表,而是None。 - thefourtheye
7
使用defaultdict相对于使用setdefault的优点是什么? - mike_hornbeck

38

有没有更优雅的方法写这段代码?

使用 collections.defaultdict:

from collections import defaultdict

dates_dict = defaultdict(list)
for key, date in cur:
    dates_dict[key].append(date)

当我尝试使用for key, date_list in dates_dict:时,出现了error: too many values to unpack (expected 2)的错误。 - Mawg says reinstate Monica
1
@Mawg,请查看答案中的代码。我没有在那里看到你的例子。 - jfs
1
@Axl 看看答案和评论中的代码,你看到区别了吗?(注意:cur不同于dates_dict——它们是不同的对象) - jfs
1
@MawgsaysreinstateMonica 因为应该是 for key, date_list in dates_dict.items(): - Takamura
1
@Takamura:错误。cur是输入,dates_dict是结果。一开始它是空的。迭代它没有意义。答案中的代码是正确的。 - jfs
我不是在谈论答案中的代码,我认为@Mawg尝试的是在运行答案中的代码之后。 - Takamura

7

dates_dict[key] = dates_dict.get(key, []).append(date)dates_dict[key]设置为None,因为list.append返回None

In [5]: l = [1,2,3]

In [6]: var = l.append(3)

In [7]: print var
None

你应该使用collections.defaultdict

import collections
dates_dict = collections.defaultdict(list)

是的,这正是我想的。由于没有返回值,它将默认返回None。谢谢。 - Michael Murphy
@MichaelMurphy,使用defaultdict将是您想要做的最有效的方法。 - Padraic Cunningham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接