使用defaultdict替换python中的try和/或if语句

时间:2013-12-18 17:36:45

标签: python try-catch defaultdict

我最近发现并开始使用默认词典来替换几个更庞大的构造。我读过'蟒蛇的禅',蟒蛇的关键点之一就是“应该有一个 - 最好只有一个 - 明显的方式来做它。”

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

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循环或其他条件,而不是简单地计算单个iterable中的泛型值,因为这显然会有不同的特性。

2 个答案:

答案 0 :(得分:3)

如果你坚持使用字典或defaultdict,第一个是最好的。然而,为了计算,在集合中有一个名为Counter的可爱类:

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

甚至更短:

>>> c = Counter(iterable)

答案 1 :(得分:2)

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

from collections import Counter
my_dict = Counter(iterable)

就是这样。

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

现在当collections.Countercollections.defaultdict都没有解决您的问题时,您有三种可能的模式:

  • 前看
  • 尝试/除了KeyError
  • dict.setdefault(key, value)

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

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

dict.setdefault()解决方案的成本与“前一个”解决方案的成本大致相同,但是您也有不变的默认对象实例,通常会立即崩溃。几年前这是一种常见的模式,但是自collection.defaultdict出现以来它的使用相当少,而不是说大多数都没用。