当前位置: 首页 > 面试题库 >

Python-为什么“ except:pass”是不好的编程习惯?

刘凡
2023-03-14
问题内容

我经常看到有关except: pass不鼓励使用的其他Stack Overflow问题的评论。为什么这样不好?有时我只是不在乎错误是什么,我只想继续编写代码。

try:
    something
except:
    pass

为什么使用except: pass积木不好?是什么让它不好?是我pass出错还是我except出错了?


问题答案:

正如你正确猜到的那样,它有两个方面:通过在后面不指定任何异常类型来捕获任何错误except,并在不采取任何操作的情况下简单地传递它。

我的解释要“长一点”,因此tl; dr可以细分为:

不要发现任何错误。始终指定你准备从哪些异常中恢复并仅捕获这些异常。
尽量避免传入除了blocks。除非明确要求,否则通常不是一个好兆头。
但是,让我们详细介绍一下:

不要发现任何错误
使用try块时,通常这样做是因为你知道有可能引发异常。这样,你还已经大概知道了哪些会中断,哪些异常会引发。在这种情况下,你会捕获异常,因为你可以从中积极地恢复过来。这意味着你已经为例外做好了准备,并有一些替代计划,在发生这种例外的情况下你将遵循该计划。

例如,当你要求用户输入数字时,你可以使用int()可能引起的转换输入ValueError。你只需要求用户再试一次即可轻松恢复,因此捕获ValueError并提示用户将是一个适当的计划。一个不同的例子是,如果你想从文件中读取某些配置,而该文件恰好不存在。因为它是一个配置文件,所以你可能具有一些默认配置作为后备,因此该文件不是完全必要的。因此,FileNotFoundError在此处捕获并简单地应用默认配置将是一个不错的计划。现在,在这两种情况下,我们都期望有一个非常具体的例外,并且有一个同样具体的计划可以从中恢复。因此,在每种情况下,我们只明确except 某些 例外。

但是,如果我们要抓住一切,那么除了准备好从中恢复的异常之外,还有机会获得我们没有想到的异常,而我们确实无法从中恢复。或不应从中恢复。

让我们以上面的配置文件示例为例。如果文件丢失,我们将应用默认配置,并可能在以后决定自动保存配置(因此下次该文件存在)。现在想象我们得到一个IsADirectoryError或一个PermissionError代替。在这种情况下,我们可能不想继续。我们仍然可以应用默认配置,但是以后将无法保存文件。而且用户可能也打算具有自定义配置,因此可能不希望使用默认值。因此,我们希望立即将其告知用户,并且可能也中止程序执行。但这不是我们想要在某些小代码部分的深处做的事情;这在应用程序级别上很重要,因此应该在顶部进行处理-因此让异常冒出来。

Python 2习惯用法文档中还提到了另一个简单的示例。此处,代码中存在一个简单的错字,导致其中断。因为我们正在捕获每个异常,所以我们也捕获了NameErrorsSyntaxErrors。两者都是编程时我们所有人都会遇到的错误。两者都是我们在交付代码时绝对不希望包含的错误。但是,因为我们也抓住了它们,所以我们甚至都不知道它们在那里发生,并且失去了正确调试它的任何帮助。

但是,还有一些危险的例外情况,我们不太可能为此做好准备。例如,SystemError通常很少发生,我们无法真正计划。这意味着发生了更复杂的事情,有可能阻止我们继续当前的任务。

无论如何,你几乎不可能为代码中的一小部分做好一切准备,因此,实际上,你应该只捕获准备好的那些异常。有人建议至少要抓住Exception它,因为它不会包含类似的内容,SystemExitKeyboardInterrupt这种情况在设计上是要终止你的应用程序的,但是我认为这仍然过于具体。我个人只在一个地方接受捕捞活动,Exception或者在任何地方异常,并且在单个全局应用程序级异常处理程序中,该异常处理程序的唯一目的是记录我们没有准备好的任何异常。这样,我们仍然可以保留有关意外异常的尽可能多的信息,然后我们可以使用这些信息扩展代码以显式处理这些异常(如果可以从异常中恢复),或者在发生错误的情况下创建测试用例以确保它不会再发生。但是,当然,只有当我们只捕获到我们已经期望的异常时,这才起作用,所以我们没想到的异常自然会冒出来。

尽量避免传入除了块

当显式地捕获少量特定异常时,在许多情况下,只要不执行任何操作就可以了。在这种情况下,拥有except SomeSpecificException: pass就好。但是,在大多数情况下,情况并非如此,因为我们可能需要一些与恢复过程相关的代码(如上所述)。例如,这可以是再次重试操作的内容,也可以是设置默认值的内容。

如果不是这种情况,例如,因为我们的代码已经被构造为可以重复执行直到成功,那么仅传递就足够了。从上面的示例中,我们可能需要询问用户输入数字。因为我们知道用户不想按照我们的要求去做,所以我们可能首先将其放入循环中,因此看起来可能像这样:

def askForNumber ():
    while True:
        try:
            return int(input('Please enter a number: '))
        except ValueError:
            pass

因为我们一直努力直到没有异常抛出,所以我们不需要在except块中做任何特殊的事情,所以这很好。但是,当然,有人可能会认为我们至少要向用户显示一些错误消息,以告诉他为什么他必须重复输入。

但是,在许多其他情况下,仅传递except一个信号就表明我们并未真正为所捕获的异常做好准备。除非这些异常很简单(如ValueErrorTypeError),并且我们可以通过的原因很明显,否则请尝试避免仅通过。如果真的无事可做(而且你对此绝对有把握),请考虑添加注释,为什么会这样;否则,展开except块以实际包括一些恢复代码。

except: pass

不过,最严重的罪犯是两者的结合。这意味着我们乐于捕捉任何错误,尽管我们绝对没有为此做好准备,并且我们也不对此做任何事情。你至少要记录该错误,还可能重新引发该错误以仍然终止应用程序(在出现MemoryError后,你不太可能像往常一样继续)。只是传递信息不仅可以使应用程序保持一定的生命(当然,这取决于你捕获的位置),而且还会丢弃所有信息,从而无法发现错误-如果你不是发现错误的人,则尤其如此。

因此,底线是:仅捕获你真正期望并准备从中恢复的异常;其他所有问题都可能是你应该纠正的错误,或者你没有准备好应对。如果你真的不需要对异常进行处理,则传递特定的异常很好。在所有其他情况下,这只是推定和懒惰的标志。你肯定想解决该问题。



 类似资料:
  • 问题内容: 为什么捕获使用不被视为良好的编程习惯?什么是处理RuntimeException的正确方法? 另外,为什么不赶上?如何执行此行为? 问题答案: 通常,a 表示编程错误(在这种情况下,您无法“处理”该错误,因为如果您知道期望发生错误,则可以避免该错误)。 捕获任何这些常规异常(包括)都是一个坏主意,因为这意味着您声称自己了解所有可能出错的情况,尽管如此,您仍然可以继续。有时(而不是通常)

  • 问题内容: 我一直认为函数式编程可以在Python中完成。因此,令我感到惊讶的是,Python在这个问题上没有得到太多提及,而当它被提及时,通常不是很积极。但是,没有给出很多原因(缺少模式匹配和代数数据类型)。所以我的问题是:为什么Python对于函数式编程不是很好?除了缺少模式匹配和代数数据类型之外,还有其他原因吗?还是这些概念对函数式编程如此重要,以致于不支持它们的语言只能被归类为一流的函数式

  • 问题内容: 建议不要中使用。 可以分享原因,以便下次避免这样做吗? 问题答案: 因为它将很多东西放到你的命名空间中(可能会遮盖以前导入的其他对象,你对此一无所知)。 因为你不完全知道要导入的内容,而且不容易找到从哪个模块导入的特定内容(可读性)。 因为你不能使用像静态检测代码中的错误之类的出色工具。

  • 问题内容: 为什么全局变量是不好的?[closed] 问题答案: 这与Python无关。全局变量在任何编程语言中都是不好的。 但是,全局常量在概念上与全局变量并不相同。全局常数完全无害。只是在Python中没有强制性差异,只有约定是。 它们不好的原因是它们使函数具有隐藏的(非显而易见的,令人惊讶的,难以检测的)副作用,从而导致复杂性的增加,并有可能导致产生Spaghetti代码。 但是,即使在函数

  • 本文向大家介绍学编程选什么语言好?是PHP、Python还是Ruby?,包括了学编程选什么语言好?是PHP、Python还是Ruby?的使用技巧和注意事项,需要的朋友参考一下 简单地一句话总结: 1.假如你想帮他尽快找个活儿,赚到钱,推荐PHP。 2.假如你想让他成为一个高效工程师,推荐 Python。 3.假如你想让他爱上他的工作,推荐 Ruby。 语言的选择: 编程语言非常重要,不要认为他们都

  • 问题内容: 我的建筑师总是说 永远不要同步布尔值 我无法理解原因,如果有人可以举例说明为什么这不是一个好习惯,我将不胜感激。 参考样本代码 问题答案: 我不明白为什么我们应该“从不同步布尔值” 你应该始终synchronize在一个常量对象实例上。如果你在分配的任何对象上进行同步(即,将对象更改为新对象),则该对象不是恒定的,并且不同的线程将在不同的对象实例上进行同步。由于它们在不同的对象实例上进