如果首先可以避免异常,最好"尝试"某些东西并捕获异常或测试?

cho*_*own 125 python if-statement exception-handling try-catch pep

我应该测试if某些东西是有效的还是只是try为了捕获异常?

  • 有没有可靠的文件说一种方式是首选的?
  • 一种方式更pythonic

例如,我应该:

if len(my_list) >= 4:
    x = my_list[3]
else:
    x = 'NO_ABC'
Run Code Online (Sandbox Code Playgroud)

要么:

try:
    x = my_list[3]
except IndexError:
    x = 'NO_ABC'
Run Code Online (Sandbox Code Playgroud)

一些想法......
PEP 20说:

错误不应该默默地传递.
除非明确沉默.

应该使用a try而不是if被解释为默认传递的错误?如果是这样,你是否通过这种方式使用它来明确地对它进行静音,从而使它成为可能?


不是指的情况下,你只能做的事情1路; 例如:

try:
    import foo
except ImportError:
    import baz
Run Code Online (Sandbox Code Playgroud)

Rem*_*emi 149

你应该更喜欢try/except,if/else如果这导致

  • 加速(例如通过防止额外的查找)
  • 更清洁的代码(更少的行/更容易阅读)

通常,这些都是相辅相成的.


速度起坐

在尝试通过以下方式在长列表中查找元素的情况下:

try:
    x = my_list[index]
except IndexError:
    x = 'NO_ABC'
Run Code Online (Sandbox Code Playgroud)

try,除了是index可能在列表中并且通常不会引发IndexError 的最佳选项.这样您就可以避免额外查找if index < len(mylist).

Python鼓励使用异常,你处理的Dive Into Python中的一个短语.您的示例不仅处理异常(优雅地),而不是让它以静默方式传递,而且只有在未找到索引的异常情况下才会发生异常(因此单词exception!).


清洁代码

官方Python文档提到EAFP:比请求更容易请求宽恕Rob Knight注意到捕获错误而不是避免错误,可以使代码更清晰,更易于阅读.他的例子是这样说的:

更糟糕的是(LBYL'先看看你的飞跃'):

#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)
Run Code Online (Sandbox Code Playgroud)

更好(EAFP:更容易请求宽恕而不是许可):

try:
    return int(str)
except (TypeError, ValueError, OverflowError): #int conversion failed
    return None
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说是一个引人注目的论据,感谢雷米! (4认同)
  • 这是有道理的,但是我在哪里可以找到明确说明 int() 可能引发哪些异常的文档。https://docs.python.org/3/library/functions.html#int 我无法在这里找到此信息。 (3认同)

dus*_*uff 19

在这种特殊情况下,您应该完全使用其他东西:

x = myDict.get("ABC", "NO_ABC")
Run Code Online (Sandbox Code Playgroud)

但是,一般情况下:如果您希望测试频繁失败,请使用if.如果测试相对于仅尝试操作而言是昂贵的,并且如果失败则捕获异常,请使用try.如果这些条件都不适用,请更容易阅读.

  • 我认为很明显这不是他所要求的,他现在编辑了这篇文章,使其更加清晰. (3认同)
  • +1 用于代码示例下的解释,这是正确的。 (2认同)

Joh*_*wan 9

如果存在任何竞争条件,应始终使用try并且except直接在if防护装置内部使用.例如,如果要确保存在目录,请不要这样做:

import os, sys
if not os.path.isdir('foo'):
  try:
    os.mkdir('foo')
  except OSError, e
    print e
    sys.exit(1)
Run Code Online (Sandbox Code Playgroud)

如果另一个线程或进程在isdir和之间创建目录mkdir,则退出.相反,这样做:

import os, sys, errno
try:
  os.mkdir('foo')
except OSError, e
  if e.errno != errno.EEXIST:
    print e
    sys.exit(1)
Run Code Online (Sandbox Code Playgroud)

只有在无法创建'foo'目录时才会退出.


Amb*_*ber 7

如果在你做之前检查某些东西是否会失败是微不足道的,你应该赞成这一点.毕竟,构造异常(包括其相关的追溯)需要时间.

例外情况应该用于:

  1. 意想不到的事情,或......
  2. 你需要跳过多个逻辑级别的东西(例如,哪个break不能让你足够远),或......
  3. 你不确切知道将要提前处理异常的事情,或者......
  4. 提前检查故障的事情是昂贵的(相对于只是尝试操作)

请注意,通常情况下,真正的答案是"不" - 例如,在您的第一个示例中,您真正应该做的只是.get()用来提供默认值:

x = myDict.get('ABC', 'NO_ABC')
Run Code Online (Sandbox Code Playgroud)

  • @Remi``get()`的缓慢部分是Python级别的属性查找和函数调用开销; 在内置插件上使用关键字基本上是正确的C.我不认为它会很快变得太快.至于`if`与`try`,读[dict.get()方法返回一个指针(http://stackoverflow.com/questions/7153893/dict-get-method-returns-a-pointer),其有一些表现信息.命中与未命中的比例(如果键几乎总是存在,则"try"可以更快)和字典的大小一样. (2认同)

Pet*_*ter 6

正如其他帖子所提到的,这取决于情况。使用 try/except 代替提前检查数据的有效性存在一些危险,尤其是在大型项目中使用它时。

  • try 块中的代码可能有机会在异常被捕获之前造成各种破坏 - 如果您事先使用 if 语句进行检查,则可以避免这种情况。
  • 如果在 try 块中调用的代码引发了一个常见的异常类型,例如 TypeError 或 ValueError,则您实际上可能不会捕获到您期望捕获的相同异常 - 它可能是在到达之前或之后引发相同异常类的其他东西可能引发异常的行。

例如,假设你有:

try:
    x = my_list[index_list[3]]
except IndexError:
    x = 'NO_ABC'
Run Code Online (Sandbox Code Playgroud)

IndexError 没有说明它是否在尝试获取 index_list 或 my_list 的元素时发生。