Better to 'try' something and catch the exception or test if it's possible first to avoid an exception?
我应该测试
- 是否有可靠的文件表明首选一种方法?
- 还有一条路比Python多吗?
例如,我应该:
1 2 3 4 | if len(my_list) >= 4: x = my_list[3] else: x = 'NO_ABC' |
或:
1 2 3 4 | try: x = my_list[3] except IndexError: x = 'NO_ABC' |
一些想法…PEP 20表示:
Errors should never pass silently.
Unless explicitly silenced.
使用
我不是指你只能以一种方式做事的情况;例如:
1 2 3 4 | try: import foo except ImportError: import baz |
如果这导致
- 加速(例如通过防止额外查找)
- 更清晰的代码(行数更少/更易于阅读)
通常情况下,这些都是同时进行的。
提速
如果试图通过以下方式在长列表中查找元素:
1 2 3 4 | try: x = my_list[index] except IndexError: x = 'NO_ABC' |
尝试,除了当
python鼓励使用异常,您处理的异常是一个短语,从dive into python开始。您的示例不仅处理异常(优雅地),而不是让它安静地传递,而且异常只发生在未找到索引的异常情况下(因此出现了单词exception!).
清洁码
官方的python文档提到eafp:请求宽恕比请求许可更容易,rob knight注意到捕获错误而不是避免错误,会导致代码更干净、更易于阅读。他的例子是这样说的:
更糟(lbyl"三思而后行"):
1 2 3 4 5 6 7 | #check whether int conversion will raise an error if not isinstance(s, str) or not s.isdigit: return None elif len(s) > 10: #too many digits for int conversion return None else: return int(str) |
更好(EAFP:请求宽恕比请求允许更容易):
1 2 3 4 | try: return int(str) except (TypeError, ValueError, OverflowError): #int conversion failed return None |
在这种特定的情况下,您应该完全使用其他的东西:
1 | x = myDict.get("ABC","NO_ABC") |
不过,一般来说:如果您希望测试经常失败,请使用
如果有可能出现种族状况,应始终直接使用
1 2 3 4 5 6 7 | import os, sys if not os.path.isdir('foo'): try: os.mkdir('foo') except OSError, e print e sys.exit(1) |
如果另一个线程或进程在
1 2 3 4 5 6 7 | import os, sys, errno try: os.mkdir('foo') except OSError, e if e.errno != errno.EEXIST: print e sys.exit(1) |
只有在无法创建"foo"目录时才会退出。
如果在你做某件事之前检查它是否会失败是很琐碎的,那么你可能会赞成这一点。毕竟,构造异常(包括其关联的回溯)需要时间。
例外情况应用于:
请注意,通常情况下,真正的答案是"两者都不是"—例如,在第一个示例中,您真正应该做的是使用
1 | x = myDict.get('ABC', 'NO_ABC') |
Should using a try instead of an if be interpreted as an error passing silently? And if so, are you explicitly silencing it by using it in this way, therefore making it OK?
使用
在
"错误永远不应该无声地传递"的警告是,代码可能会引发一个您知道的异常,并且您的设计允许这种可能性,但您还没有以某种方式设计来处理该异常。在我看来,在
但是,在您的特定示例中,这两者都不适用:
1 | x = myDict.get('ABC', 'NO_ABC') |
每个人都指出这一点的原因——即使你承认你总的来说有理解的愿望,并且不能想出一个更好的例子——是在很多情况下实际上存在着对等的边步骤,寻找它们是解决问题的第一步。
正如其他帖子所提到的,这取决于具体情况。使用Try/Except来代替提前检查数据的有效性有一些危险,尤其是在大型项目中使用它时。
- try块中的代码可能有机会在捕获异常之前造成各种破坏-如果预先使用if语句进行检查,可以避免这种情况。
- 如果在try块中调用的代码引发了一个常见的异常类型,如typeerror或valueerror,则实际上您可能无法捕获预期捕获的同一个异常-它可能是在到达可能引发异常的行之前或之后引发同一个异常类的其他东西。
例如,假设您有:
1 2 3 4 | try: x = my_list[index_list[3]] except IndexError: x = 'NO_ABC' |
indexError没有说明在尝试获取index_list或my_list的元素时是否发生了这种情况。
当你使用
如果这些问题中的一个或多个的答案是"不",可能会有很多宽恕的要求;最有可能是来自你未来的自我。
一个例子。我最近在一个更大的项目中看到了这样的代码:
1 2 3 4 | try: y = foo(x) except ProgrammingError: y = bar(x) |
与编程人员交谈后发现,预期的控制流程是:
If x is an integer, do y = foo(x)
and if x is a list of integers, do y = bar(x).
这是因为
在这里使用
对于一般意义,您可以考虑在python中阅读习语和反习语:例外。
在您的特定情况下,如其他人所述,您应该使用
get(key[, default])
Return the value for key if key is in the
dictionary, else default. If default is not given, it defaults to
None, so that this method never raises a KeyError.