在Python中使用异常控制流程是否被认为是不好的?
3 个回答
一直使用try
块来控制程序的流程可能会导致代码变成这样:
try:
# stuff
try:
if userCondition:
raise NeedToDoSomethingElseException
try:
# stuff
except NeedToDoSomethingElseException:
# other stuff
except NeedToDoSomethingElseException:
# other stuff
except NeedToDoSomethingElseException:
# other stuff
除了性能问题,这样的写法也不太优雅。所以,有时候使用try
是合适的,但并不是所有情况下都要用。
因为异常是从调用的代码层层抛出来的,所以在某些情况下,它们非常适合让使用其他代码的部分能够捕捉到这些异常。举个例子,假设你想创建一个迭代器,而这个迭代器需要更“手动”地使用另一个迭代器的部分,这时候能够从更高的层次捕捉到异常就很有用了,这样你就可以插入自己的处理逻辑。
因为结束生成器的情况并不常见(我知道它总会发生,但只发生一次)。抛出异常被认为是比较耗费资源的。如果一个事件有99%的成功率和1%的失败率,使用try/except可能比检查是否可以访问数据要快得多(有时候,事后求饶比事先请求许可更简单)。
另外,使用try/except的方式也有一些偏见,因为这样使用的try/except块可能很难理解。控制流程可能会很复杂,而if/else则更直接。使用try/except意味着你需要跟踪try里面的语句的控制流程,以及它调用的函数里面的控制流程(因为这些函数可能会抛出异常,异常可能会向上冒泡)。而if/else只在语句被评估时分支。
有时候使用try/except是正确的,有时候使用if/else更合适。它们各自也有性能上的差异。考虑一下:
a = <some dictionary>
if key in a:
print a[key]
与
a = <some dictionary>
try:
print a[key]
except KeyError:
pass
如果key在a里面不存在,第一种方式会更快;如果存在,速度只会稍微慢一点(几乎感觉不到)。第二种方式如果key存在会更快,但如果不存在就会慢很多。如果key几乎总是存在,那就用第二种方式。否则,第一种方式更好。
补充一下关于Python中try/except的小知识,这有助于解决可读性的问题。
考虑从文件中读取数据。
f = None
try:
f = open(filename, 'r')
... do stuff to the file ...
except (IOError, OSError):
# I can never remember which one of these Python throws...
... handle exception ...
finally:
if f:
f.close()
在这里,do stuff to the file
中的任何操作都可能抛出异常,我们会捕获这些异常。通常情况下,你会尽量在try中保持代码量尽可能少,这就是原因。Python有一个可选的else
子句,只有在try顺利完成且没有抛出异常时才会执行。
f = None
try:
f = open(filename, 'r')
except (IOError, OSError):
pass
else:
... do stuff to the file ...
finally:
if f:
f.close()
在这种情况下,你不会遇到可读性的问题,因为try中只有一条语句;这是一个Python标准库的函数调用,你只捕获特定的异常。