【问题标题】:fill a dictionary without using try except填写字典而不使用 try except
【发布时间】:2016-02-24 20:42:31
【问题描述】:

假设我有字典,我想用一些键和值填充它,第一个字典是空的,假设我需要这个字典作为计数器,例如计算字符串中的一些键,我有这种方式:

myDic = {}
try :
    myDic[desiredKey] += 1
except KeyError:
    myDic[desiredKey] = 1

或者有时值应该是一个列表,我需要将一些值附加到我拥有的值列表中:

myDic = {}
try:
    myDic[desiredKey].append(desiredValue)
except KeyError:
    myDic[desiredKey] = []
    myDic[desiredKey].append(desiredValue)

对于不使用try except 部分的这部作品(两者)是否有更好的替代方案?

【问题讨论】:

    标签: python dictionary try-catch


    【解决方案1】:

    您可以使用collections.defaultdict(),它允许您提供一个函数,每次访问缺少的键时都会调用该函数。

    对于您的第一个示例,您可以将 int 作为缺少的函数传递给它,该函数在第一次被访问时将被评估为 0。

    第二个你可以传递list

    例子:

    from collections import defaultdict 
    my_dict = defaultdict(int)
    
    >>> lst = [1,2,2,2,3] 
    >>> for i in lst:
    ...      my_dict[i]+=1
    ... 
    >>> 
    >>> my_dict
    defaultdict(<type 'int'>, {1: 1, 2: 3, 3: 1})
    >>> my_dict = defaultdict(list)
    >>> 
    >>> for i,j in enumerate(lst):
    ...     my_dict[j].append(i)
    ... 
    >>> my_dict
    defaultdict(<type 'list'>, {1: [0], 2: [1, 2, 3], 3: [4]})
    

    【讨论】:

    • 您应该使用list 默认值添加一个示例,并且还可能提到int 默认值意味着默认值是0——也许不明显。
    • 是否可以将所有字典方法应用到 defaultdic ?
    • @Two-BitAlchemist 是的,刚刚添加。
    • @Arman 确实是内置dict类的子类,继承了所有字典属性。
    【解决方案2】:

    我建议collections.defaultdict

    from collections import defaultdict
    myDic = defaultdict(int)
    myDic[key] = value
    

    正如 Two-Bit Alchemist 所说,defaultdict 的最佳之处在于您需要多个值键(不必先将值定义为列表)。再次使用d["key"] = value 只会重置旧值,所以:

    myDic = defaultdict(list)
    for key in keys_list:
        myDic[key].append(value)
    

    【讨论】:

    • 使用列表一做一个例子。这就是这个解决方案真正闪耀的地方。 (你也可以解释一下defaultdict(int)的意思是默认值是0)
    【解决方案3】:

    最好的方法是使用python的优秀in

    myDic = {}
    if desiredKey in myDict:
        myDic[desiredKey] += 1
    else:
        myDic[desiredKey] = 1
    

    【讨论】:

    • 对我来说这与 try/catch 没有什么不同。它只是LBYL instead of EAFP,其中EAFP 在Python 中是usually preferred
    • @zondo:虽然get 可以很方便,但实际上不如Will 的基于in 的方法高效。在我的 timeit 测试中,使用 get 会慢约 40%,尽管可以通过缓存 get 方法将速度降低到 20%。
    • @Two-BitAlchemist:EAFP 很好,Python 中的异常非常有效。但是,如果引发异常,它们比基于 if 的等效代码要慢得多,尽管在不引发异常时它们肯定会更快。一般而言,try..except 只有在引发异常的时间少于 5-10% 时才会更快。
    • @PM2Ring 听起来像是对我添加字典的微优化,但我的评论并不是关于效率,只是 Python 的典型样式指南。
    • @Two-BitAlchemist:当条件实际上异常时,异常非常好,但如果它们被频繁引发,它们会严重影响性能。如果速度不是问题,那么请随时使用 EAFP。当然,如果速度一个问题,那么也许应该使用编译语言,而不是 Python。 :)
    【解决方案4】:

    试试这个:

    myDic = {}
    myDic['desiredKey'] = myDic.get('desiredKey', 0) + 1
    

    您的列表案例也类似:

    myDic = {}
    myDic['desiredKey'] = myDic.get('desiredKey', []) + [desiredValue]
    

    dict 的.get 方法将返回值并默认为None,而不是抛出异常。也可以将默认返回值指定为第二个参数.get(key, default)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-30
      • 1970-01-01
      • 1970-01-01
      • 2018-08-10
      • 2016-04-06
      • 2019-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多