Python使用异常控制流被认为是坏的



好的,

在过去我已经见过很多次了,但是最近我的问题是这样的。所以,我很好奇为什么会出现这种情况,python中的因为生成器使用异常来指示数据的结束。

如果这对每个使用python的人来说都很糟糕,为什么python语言将其包含在被认为是基本控制结构的内容中呢?

因为结束生成器不是一个常见的事件(我知道它总是会发生,但它只发生一次)。抛出异常被认为代价高昂。如果一个事件99%的概率成功,1%的概率失败,使用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/只是一个小小的补充,除了它极大地帮助了可读性问题之一。

考虑从文件中读取。

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标准库函数调用,你只捕获特定的异常。

因为异常是在堆栈中上升的,所以它们适用于一些情况,当您希望使用其他代码的代码能够捕获异常时。例如,如果你想创建一个迭代器,该迭代器更"手动"地使用另一个迭代器的一部分,那么有一个异常可以从堆栈的上层捕获并插入你自己的逻辑,这是很有价值的。

始终使用try块进行流量控制可能产生如下代码:

try:
  # stuff
  try:
    if userCondition:
      raise NeedToDoSomethingElseException
    try:
      # stuff
    except NeedToDoSomethingElseException:
      # other stuff
  except NeedToDoSomethingElseException:
    # other stuff
except NeedToDoSomethingElseException:
  # other stuff
撇开性能问题不谈,这不是很优雅。所以,有时使用try是完全合适的,但不是所有的。