Python对控制流使用异常被认为是错误的?

Python对控制流使用异常被认为是错误的?,python,try-catch,generator,Python,Try Catch,Generator,好, 我在过去见过很多次,但最近的一次是。所以,我很好奇为什么在python中会出现这种情况,因为生成器使用异常来指示数据的结束 如果这对所有使用python的人来说都很糟糕,那么为什么该语言将其包含在基本的控制结构中呢?对于那些想要阅读相关PEP的人来说。因为异常是在堆栈上提出的,所以它们适用于某些情况,您希望使用其他代码的代码能够捕获异常。例如,考虑要创建一个迭代器的情况,该迭代器使用另一个迭代器的一部分“手动”,有一个例外,您可以从较高的堆栈中捕获一个异常并插入您自己的逻辑。因为堆栈中出现

好,

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


如果这对所有使用python的人来说都很糟糕,那么为什么该语言将其包含在基本的控制结构中呢?对于那些想要阅读相关PEP的人来说。

因为异常是在堆栈上提出的,所以它们适用于某些情况,您希望使用其他代码的代码能够捕获异常。例如,考虑要创建一个迭代器的情况,该迭代器使用另一个迭代器的一部分“手动”,有一个例外,您可以从较高的堆栈中捕获一个异常并插入您自己的逻辑。

因为堆栈中出现异常,它们适用于您希望使用其他代码的代码能够捕获异常的某些情况。例如,考虑要创建一个迭代器的情况,该迭代器使用另一个迭代器的“手动”,有一个例外,您可以从较高的堆栈中捕获并插入自己的逻辑。

,因为结束生成器不是一个常见事件(我知道它总是会发生,但它只发生一次)。抛出异常被认为是昂贵的。如果一个事件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]
现在,
do stuff to the file
中的任何内容都可能引发异常,我们将捕获它。通常,由于这个原因,您会尝试在try中保留尽可能少的代码。Python为try提供了一个可选的
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标准库函数调用,您只捕获特定的异常。

因为结束生成器不是常见事件(我知道它总是会发生,但只发生一次)。抛出异常被认为是昂贵的。如果一个事件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]
现在,
do stuff to the file
中的任何内容都可能引发异常,我们将捕获它。通常,由于这个原因,您会尝试在try中保留尽可能少的代码。Python为try提供了一个可选的
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:
      throw NeedToDoSomethingElseException
    try:
      # stuff
    except NeedToDoSomethingElseException:
      # other stuff
  except NeedToDoSomethingElseException:
    # other stuff
except NeedToDoSomethingElseException:
  # other stuff

撇开性能问题不谈,这不是很优雅。因此,有时使用
try
是非常合适的,但不是所有的都适用。

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

try:
  # stuff
  try:
    if userCondition:
      throw NeedToDoSomethingElseException
    try:
      # stuff
    except NeedToDoSomethingElseException:
      # other stuff
  except NeedToDoSomethingElseException:
    # other stuff
except NeedToDoSomethingElseException:
  # other stuff

撇开性能问题不谈,这不是很优雅。因此,有时使用
try
是非常合适的,但不是所有的方法都适用。

实用性战胜了纯洁性。实用性战胜了纯洁性。但性能不应该决定什么是惯用的,什么不是(相反,它应该是相反的——其实,应该是,对于习语来说是优化的。)除了C++,这是一个很好的答案。我完全同意你的观点,尽管我很好奇为什么你没有包括一些类似的东西。“代码是为程序员编写的,而不是为计算机编写的。因此,它应该是为人编写的,而异常作为控制流是不明确的”。我认为性能,特别是在python中,每天都是一个比代码库可读性小得多的问题。@Spencer Rathbun主要是因为我有点不连贯地混淆了两点(一个是关于性能的,一个是关于可读性)。Jonathan Sternberg Ah,解释它。然后我会接受它作为答案。但是性能不应该决定什么是习惯的,什么不是(相反,它应该是相反的——其实,应该是,对于习惯用法来说是优化的)。除了C++,这是。一个很好的答案。我完全同意你的观点,尽管我很好奇为什么你没有包括“代码是为程序员而不是计算机编写的。因此它应该为人编写,而异常与控制流一样是不明确的”。我想