我应该测试if
某些内容是否有效,或仅try
来执行此操作并捕获异常?
例如,我应该:
if len(my_list) >= 4:
x = my_list[3]
else:
x = 'NO_ABC'
或者:
try:
x = my_list[3]
except IndexError:
x = 'NO_ABC'
一些想法......
PEP 20说:
错误不应该默默地传递。
除非明确地保持沉默。
使用try
代替if
是否应该被解释为默默传递的错误?如果是这样,您是否通过这种方式使用它来明确地对其进行静音,从而使其正常?
我 不 指的是你只能单向做事的情况;例如:
try:
import foo
except ImportError:
import baz
答案 0 :(得分:138)
如果结果为try/except
,您应该更喜欢if/else
通常,这些都是相辅相成的。
速度起坐
在尝试通过以下方式在长列表中查找元素的情况下:
try:
x = my_list[index]
except IndexError:
x = 'NO_ABC'
try,当index
可能在列表中并且通常不引发IndexError时,除了是最佳选项。这样您就无需if index < len(mylist)
进行额外查找。
Python鼓励使用异常,您处理的 是来自Dive Into Python的短语。您的示例不仅处理异常(优雅地),而不是让它静默传递,而且仅在未找到索引的例外情况下发生异常(因此例外!)。
清洁代码
官方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)
更好(EAFP:更容易请求宽恕而非许可):
try:
return int(str)
except (TypeError, ValueError, OverflowError): #int conversion failed
return None
答案 1 :(得分:17)
在这种特殊情况下,你应该完全使用别的东西:
x = myDict.get("ABC", "NO_ABC")
通常,但是:如果您希望测试频繁失败,请使用if
。如果测试相对于仅尝试操作而言是昂贵的,并且如果失败则捕获异常,请使用try
。如果这些条件都不适用,那么更容易阅读。
答案 2 :(得分:7)
如果在做之前检查某些事情是否会失败是微不足道的,那么你应该赞成这一点。毕竟,构建异常(包括相关的追溯)需要时间。
例外情况应该用于:
break
无法让您足够远的地方),或者...... 请注意,通常情况下,真正的答案是“不” - 例如,在您的第一个示例中,您真正应该做的只是使用.get()
来提供默认值:
x = myDict.get('ABC', 'NO_ABC')
答案 3 :(得分:7)
直接使用try
和except
而不是if
后卫,如果有可能出现竞争条件,总是 。例如,如果要确保存在目录,请不要这样做:
import os, sys
if not os.path.isdir('foo'):
try:
os.mkdir('foo')
except OSError, e
print e
sys.exit(1)
如果另一个线程或进程在isdir
和mkdir
之间创建了目录,您将退出。相反,这样做:
import os, sys, errno
try:
os.mkdir('foo')
except OSError, e
if e.errno != errno.EEXIST:
print e
sys.exit(1)
只有在无法创建'foo'目录时才会退出。
答案 4 :(得分:4)
应该使用try而不是if被解释为默认传递的错误吗?如果是这样,您是否通过这种方式使用它来明确地对其进行静音,从而使其正常?
使用try
确认错误可能会通过,这与静默通过相反。使用except
导致它根本无法通过。
在try: except:
逻辑更复杂的情况下,首选使用if: else:
。简单比复杂更好;复杂比复杂更好;要求宽恕比获得许可更容易。
什么“错误不应该默默地传递”是警告,代码可以引发你知道的异常,以及你的设计承认可能性,但你没有设计的方式来处理例外。在我看来,明确地消除错误会在pass
块中执行类似except
的操作,这应该只是理解“无所事事”确实是特定的错误处理情况。 (这是我觉得可能真的需要在编写良好的代码中发表评论的少数几次之一。)
但是,在您的特定示例中,两者都不合适:
x = myDict.get('ABC', 'NO_ABC')
每个人都指出这一点的原因 - 即使你承认你想要理解一般,并且无法提出一个更好的例子 - 在很多情况下实际存在相同的副步骤,并寻找他们是解决问题的第一步。
答案 5 :(得分:4)
正如其他帖子所述,这取决于具体情况。使用try / except会有一些危险,而不是提前检查数据的有效性,尤其是在大型项目中使用时。
try:
x = my_list[index_list[3]]
except IndexError:
x = 'NO_ABC'
IndexError没有说明在尝试获取index_list或my_list元素时是否发生。
答案 6 :(得分:1)
每当您使用try/except
进行控制时,请问自己:
try
块何时成功以及何时失败?try
块内的所有副作用?try
块引发异常的所有 情况?try
块的实现发生了变化,您的控制流是否仍将按预期运行?如果对这些问题中的一个或多个的回答为“否”,则可能会有很多宽恕的要求;
一个例子。 我最近在一个更大的项目中看到了如下代码:
try:
y = foo(x)
except ProgrammingError:
y = bar(x)
与程序员交谈时,发现原来的控制流程是:
如果x是整数,则执行y = foo(x)。
如果x是整数列表,则y = bar(x)。
之所以可行,是因为foo
进行了数据库查询,如果x
是整数,则查询成功,如果ProgrammingError
是列表,则抛出x
。
在这里使用try/except
是一个错误的选择:
ProgrammingError
并没有给出实际的问题(x
不是整数)。这使得很难弄清发生了什么。ProgrammingError
,这不必要地浪费时间。如果事实证明foo
会在引发异常或更改某些其他系统的状态之前将某些内容写入数据库,那么事情将变得非常可怕。ProgrammingError
都是由x
作为列表引起的。例如,假设foo
的数据库查询中有一个错字。这也可能会引发ProgrammingError
。结果是,如果bar(x)
是整数,那么现在也将调用x
。这可能会引发神秘的异常或产生无法预料的结果。try/except
块为foo
的所有将来实现添加了要求。每当我们更改foo
时,我们现在都必须考虑它如何处理列表,并确保它抛出ProgrammingError
而不抛出AttributeError
或根本没有错误。答案 7 :(得分:0)
对于一般含义,您可以考虑阅读Idioms and Anti-Idioms in Python: Exceptions。
在您的特定情况下,正如其他人所述,您应该使用dict.get()
:
get(key [,default])
如果键在,则返回key的值 字典,否则默认。如果未给出default,则默认为 无,因此此方法永远不会引发KeyError。