【问题标题】:Using defaultdict to replace try and/or if statements in python使用 defaultdict 替换 python 中的 try 和/或 if 语句
【发布时间】:2013-12-18 17:36:45
【问题描述】:

我最近发现并开始使用默认字典来替换几个更庞大的结构。我在《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 循环或其他条件,而不是简单地从单个迭代中计算通用值,因为这显然具有不同的特性。

【问题讨论】:

  • 对于您在这里所做的事情,请使用collections.Counter
  • defaultdict 是三者中最好的,但正如@PauloAlmeida 所说,如果您只使用整数,最好使用Counter。当你真正想调用默认类型d=defaultdict(list); d[0].extend([1,2,3])等的方法时使用defaultdict

标签: python try-catch defaultdict


【解决方案1】:

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

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

甚至更短:

>>> c = Counter(iterable)

【讨论】:

    【解决方案2】:

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

    from collections import Counter
    my_dict = Counter(iterable)
    

    就是这样。

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

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

    • 前瞻
    • 尝试/排除 KeyError
    • dict.setdefault(key, value)

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

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

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

    【讨论】:

    • 对于未来的读者,在 Python 2.7 中,如果您预计总共不到 25% 的键失败,try/except 的性能将优于 LBYLdict.get。 (如果平均而言,每个条目将被击中至少四次,则速度会更快。)EAFP 更快,并且只会随着比率的增加而变得更快(@ 1% 的未命中率,几乎是 40%)。话虽如此,defaultdict out 在所有情况下都以可观的优势(10-20%)执行 EAFP。见repl.it
    猜你喜欢
    • 2020-02-25
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-03
    • 2014-11-29
    • 2016-11-25
    相关资源
    最近更新 更多