在简单的情况下,除了&恢复或避免例外?

时间:2011-01-30 22:16:41

标签: python list exception dictionary

考虑:

categories = {'foo':[4], 'mer':[2, 9, 0]}

key = 'bar'
value = 5

我们可以通过以下任一方式安全地追加存储在字典中的列表:

  1. 谨慎,我们总是在追加列表之前检查列表是否存在。

    if not somedict.has_key(key):
        somedict[key] = []
    somedict[key].append(value)
    
  2. 如果有异常,我们只需要清理。

    try:
        somedict[key].append(value)
    except KeyError:
        somedict[key] = [value]
    
  3. 在这两种情况下,结果可能是:

    {'foo':[4], 'mer':[2, 9, 0], 'bar':[5]}
    

    重述我的问题:在这样的简单例子中,谨慎或直接地更好(在风格,效率和哲学方面)?

7 个答案:

答案 0 :(得分:3)

你会发现你的选择1“谨慎”往往非常缓慢。此外,它会受到模糊错误的影响,因为您尝试编写的“避免”异常的测试不正确。

你会发现你的选择2“直接”通常要快得多。它也更可能是正确的,也更快更容易让人们阅读。

为什么呢?在内部,Python经常使用“contains”或“has_key”之类的东西作为异常测试。

def has_key( self, some_key ):
    try:
        self[some_key]
    except KeyError:
        return False
    return True

由于这通常是如何实现has_key类型的方法,因此除了Python已经做的事情之外,没有理由让代码浪费时间。

更基本的是,存在正确性问题。许多预防或避免异常的尝试都是不完整的。

例如,尝试确定字符串是否可能是浮点数,这充满了许多异常和特殊情况。关于正确做到这一点的唯一方法就是这个。

try:
    x= float( some_string )
except ValueError: 
    # not a floating-point value

只需执行算法而不必担心“阻止”或“避免”异常。

答案 1 :(得分:2)

在一般情况下,Python中首选EFAP(“更容易请求宽恕而不是许可”)。当然,经验法则“例外情况应该是特殊情况”仍然存在(如果您希望频繁发生异常,那么您可能“在您跳跃之前”) - 即它取决于。在效率方面,它在大多数情况下不应该产生太大的差异 - 当它发生时,考虑到try块没有例外是便宜的,并且总是检查条件。

请注意,两者都没有必要(至少你不必自己/明确地做)某些情况,包括这个例子 - 在这里,你应该只使用collections.defaultdict

答案 2 :(得分:1)

您不需要强有力的理由来使用异常 - 它们在Python中并不是非常昂贵。以下是一些可能的原因,为您的特定示例选择其中一个:

  • 异常版本需要更简单的API。任何支持项目查找和分配(__getitem____setitem__)的容器都可以使用。非例外版本还要求has_key实施。
  • 如果密钥通常存在,异常版本可能稍快一些,因为它只需要单个dict查找。 has_key版本至少需要两个 - 一个用于has_key,另一个用于实际查找。
  • 非异常版本具有更一致的代码路径:它始终将数组中的值放在同一位置。相比之下,异常版本为每种情况都有一个单独的代码路径。

除非性能特别重要(在这种情况下,您将进行基准测试和分析),这些都不是非常强大的原因;只需使用看起来更自然的东西。

答案 3 :(得分:1)

try足够快,except(如果它发生)可能不是。如果这些列表的平均长度为1.1,请使用check-first方法。如果它将成千上万,请使用try / except。如果你真的很担心,可以选择替代方案。

确保您对最佳替代方案进行基准测试。 d.has_key(k)是一个缓慢的旧的has_been;您不需要属性查找和函数调用。请改用k in d。还可以使用else在第一次旅行中保存浪费的append

而不是:

if not somedict.has_key(key):
    somedict[key] = []
somedict[key].append(value)

这样做:

if key in somedict:
    somedict[key].append(value)
else:
    somedict[key] = [value]

答案 4 :(得分:0)

您可以将setdefault用于此特定情况:

somedict.setdefault(key, []).append(value)

见这里:http://docs.python.org/library/stdtypes.html#mapping-types-dict

答案 5 :(得分:0)

这取决于,例如,如果键是一个将由其他程序员使用的函数的参数,我会使用第二种方法,因为我无法控制输入,并且它实际上对它有用的异常信息一个程序员。但是如果它只是一个函数内部的一个进程而且它只是来自数据库的一些输入,例如,第一种方法更好,那么如果出现问题,可能会显示异常信息根本没有帮助。如果要对异常信息进行处理,请使用异常方法。

答案 6 :(得分:-1)

EFAP是养成Python的好习惯。

一个原因是,如果有人想在多线程应用中使用您的代码,它可以避免竞争条件