4

我最近发现并开始使用默认字典来替换几个更庞大的结构。我在“python 之禅”中读到,python 的关键点之一是“应该有一种——最好只有一种——明显的方式来做到这一点。”

基于该标准(或者可能更实际地基于内存使用或速度)以下哪个(或完全不同的东西)是最好的?我有一种预感,第一个是正确的,但想听听其他人的意见。

my_dict = defaultdict(int)
for generic in iterable:
    my_dict[generic] +=1

或者:

my_dict = {}
for generic in iterable:
    if generic not in my_dict:
        my_dict[generic] = 1
    else:
        my_dict[generic]+=1

或者:

my_dict = {}
for generic in iterable:
    try:
        my_dict[generic] += 1
    except(KeyError):
        my_dict[generic] = 1

使用 my_dict = defaultdict(list) 和使用 append 函数也是如此。假设使用了多个 for 循环或其他条件,而不是简单地从单个迭代中计算通用值,因为这显然具有不同的特性。

4

2 回答 2

3

如果你坚持使用字典或默认字典,第一个是最好的。然而,对于计数,集合中有一个可爱的类,称为 Counter:

>>> from collections import Counter
>>> c = Counter()
>>> for generic in iterable:
...     c.update(generic)

甚至更短:

>>> c = Counter(iterable)
于 2013-12-18T17:58:39.047 回答
2

正如 Paulo Almeida 评论的那样,对于您发布的“明显”解决方案的示例是使用collections.Counter

from collections import Counter
my_dict = Counter(iterable)

就是这样。

至于您发布的其他片段,并假设my_dict[key] += 1仅用于示例并且您的一般问题是关于“如何最好地填充字典”:collections.defaultdict对于类型相同的字典(所有键的值类型相同)是正确的选择有一个默认值(数字零、空字符串、空列表...)。我能想到的最常见的用例是填充列表(或集合或其他容器)的字典。

现在,当您的问题既不解决collections.Counter也不collections.defaultdict解决时,您有三种可能的模式:

  • 先看
  • 尝试/排除 KeyError
  • dict.setdefault(key, value)

如果您希望密钥已经存在,try/except 解决方案会更快 - try/except 块的设置非常快,但在引发异常时成本很高。就我而言,除非您非常非常确定您的数据现在是什么样子以及它们将来会是什么样子,否则我不推荐它。

“先看”解决方案的成本几乎不变,虽然不是免费的,但它仍然很便宜。这真的是你最安全的选择。

dict.setdefault()解决方案的成本与“前瞻”解决方案的成本大致相同,但您也有实例化默认对象的恒定成本,这通常会立即被推翻。几年前这是一种常见的模式,但自从collection.defaultdict出现以来,它的用途相当有限,并不是说大部分没用。

于 2013-12-18T17:59:03.753 回答