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

简介: 我时常在StackOverflow上看到有人评论关于 except: pass 的使用,他们都提到这是一个不好的Python编程习惯,应该避免。可我想知道为什么?有时候我并不在意出现的错误,而是只想让我的程序继续进行下去。就像这样:

问题:为什么“except:pass”是一个不好的编程习惯?

我时常在StackOverflow上看到有人评论关于 except: pass 的使用,他们都提到这是一个不好的Python编程习惯,应该避免。可我想知道为什么?有时候我并不在意出现的错误,而是只想让我的程序继续进行下去。就像这样:

try:

   something

except:

   pass

为什么这么使用 except:pass 不好?这背后的原因是什么,是不是因为这样我会放掉一些本该被处理的错误?还是这样我会捕获到所有类型的错误?


最佳回答:

正如你所猜测的那样,这么做的确有两个不好的地方。首先,因为没有指定任何异常类型,所以会捕获到任何类型的错误。其次,捕获到错误之后只会简单地让它通过而不是采取必要的处理措施。

我接下来的解释或许会有点长,所以将重点总结如下:

  1. 不要将任意类型的错误作为捕获对象。必须明确你想要捕获的错误类型,并且写明只捕获它们。
  2. 不要试图简单地敷衍错误处理动作。除非这么做是有目的的,但这通常都不太好。

那么接下来让我们更深入一些:


不要将任意异常作为捕获目标

当在代码中的某个地方使用异常捕获语句块时,你通常知道这个地方可能会抛出异常,并且你也知道这个地方可能会发生什么样的问题进而抛出何种异常,一旦异常被抛出,你将捕获到这个异常并使程序回到正轨上来。这就意味着你一定对这种异常有所准备,并能够在它发生的时候及时采取措施进行处理。


举个例子,你需要用户输入一个数字,并且使用int()函数将用户输入的字符串转换为整数类型,这时候你一定会想到如果输入的字符串并不是数字,那么就会发生值错误(ValueError)。如果真的发生了错误,那么你可以通过简单的让用户重新输入来让程序回到正轨,所以捕获值错误以及促使用户重新输入就是一个比较合理的处理策略。再举一个例子,如果你想从一个文件中读取配置信息,但正巧这个文件不存在。那么因为这是一个配置文件,如果它不存在你会返回一些默认的配置选项,所以这个文件就不是这么必要了。在这个例子中,捕获文件未找到错误(FileNotFoundError)以及返回默认配置项则是一个比较合适的处理策略。通过以上两个例子可以看到,我们都是在等待捕获特定的错误,并且针对每种错误都有特定的处理策略。


然而,如果我们在这里捕获所有的异常,那么为特定异常准备的那些处理策略就会因为遇到非正常类型的异常而失效,这将会使得正常的程序流程中断并且无法恢复。


让我们还是举配置文件的那个例子。正常的处理策略是如果发现文件并不存在,我们将使用默认的配置项,并可能在稍后决定是否将当前的配置项自动保存为配置文件(这样的话下一次文件就肯定存在了)。现在让我们假定我们捕获到了一个IsADirectoryError或是PermissionError错误,在这种情况下,我们可能不想让程序继续执行,我们仍然能够使用默认的配置参数,但是随后我们就不能保存文件了。也有可能用户希望使用自定义的配置项,所以这样的话就不能使用默认配置项了。所以我们这时候可能需要立即告知用户并停止当前程序。也有可能我们并不想在这么一小块代码中做这么多的事情,而是让应用层面的部分去关心它,所以我们也可能让这个错误浮到顶层,让顶层的业务逻辑去处理。


Python 2 idioms document 文档中也提到了一个简单的例子:如果在我们的代码中出现了一个简单的拼写错误而导致程序错误。在这种情况下因为我们捕获所有的异常,所以我们将会捕获到名称错误(NameErrors)以及语法错误(SyntaxErrors)。两者都是常见的错误,并且两者都是不希望出现在我们最终代码中的。但是因为我们什么异常都逮,当异常发生时我们将无法区分具体的错误类型并且无法进行调试。


但是也存在这样一些并未预先准备的危险异常,诸如系统错误(SystemError)就很少发生以至于我们根本没有准备;这些异常通常需要更复杂的处理操作,这些操作通常可能会要求我们停止当前的工作。


在任何情况下,通过局部代码实现对所有异常的处理基本上都是不可能的,所以你应该有针对性的去处理那些经过准备的特定异常。有些人曾建议至少应该明确指明基本异常(Exception)这样的不包含诸如系统退出(SystemExit)和键盘中断(KeyboardInterrupt)这样设计用来终止应用程序的异常。但是我想说这样还是不够明确,并且我个人认为只有在一个地方才能仅仅只捕获Exception或是任何类型的异常,那就是一个单独的,应用程序层面的异常捕获器,并且这个捕获器唯一的任务就是去捕获任何可能出现的未经准备的漏网异常。这样的话我们仍然能够保留意外发生异常的相关信息作为进一步的代码扩展的依据(让然如果我们能让程序恢复的话),这样下一次我们就能够把这个异常在合适的地方显式地指定出来或是指导我们撰写测试用例以保证错误不再发生(当然了,这一切还是要当我们对特定异常有所准备时,没有准备的异常还是会溜掉)。


在异常处理的逻辑中,不要什么都不做

当显式地捕获到有限的几个异常之后,很多时候我们的确不需要做什么特别的处理。这种情况下,except SomeSpecificException: pass这么做是可以的。但是大多数情况下,我们还是需要一些与错误恢复相关的代码,例如重复尝试的动作以及设置默认值。


同时也考虑到其它情况,例如如果我们的代码结构已经确定了必须不断尝试直到成功才能继续,那么什么也不做就已经够了。具体来说,我们需要用户输入一个数字,因为我们知道用户可能不会按照我们设计的那样做,所以我们会将这个部分放入一个循环,比如像这样:

defaskForNumber ():

   whileTrue:

       try:

           returnint(input('Please enter a number: '))

       except ValueError:

           pass

因为我们会不断让用户输入直到没有异常抛出为止,这种情况下我们就不需要在except块中做其他任何特别的操作,这样就够了。当然了,有人会说你至少应该让用户得到一些错误信息以明确他们为什么在此被反复地要求输入。


在其他一些情况下,except块中的passing语句显示了我们并没有真正的对异常做好准备。除非是一些简单的异常(诸如值错误ValueError或类型错误TypeError)我们都应该做一些操作,原因也很明显,避免简单的passing。如果真没什么可做的(如果你真的确定),那么考虑加一些解释性的注释在此;否则,请扩展except块添加一些恢复性的代码。


except: pass

最不能容忍的就是两者的结合了。这意味着我们自愿捕获任何异常(包括那些我们没有准备的)并且对它们视而不见。你应该至少在日志中记录一下这个错误并且向上提出来终止当前程序(我就不信出现MemoryError你的程序依然能正常运行)。放过这些异常将会使程序在错误的轨道上继续运行下去并且丢掉了关键的错误信息从而使得错误不易被发现,特别是当不是你亲自遇到它的时候。


所以,底线是去捕获那些经过准备的特定异常;其他发生的异常要么是等着你去修复的错误,要么是你无法处理的。当真的没有什么可做的时候放过某些特定异常是可以的,其他情况如果这么做就只能被认为是怠工或偷懒了。你的确应该去处理这些异常的。

相关文章
|
5天前
|
存储 数据挖掘 开发者
Python编程入门:从零到英雄
在这篇文章中,我们将一起踏上Python编程的奇幻之旅。无论你是编程新手,还是希望拓展技能的开发者,本教程都将为你提供一条清晰的道路,引导你从基础语法走向实际应用。通过精心设计的代码示例和练习,你将学会如何用Python解决实际问题,并准备好迎接更复杂的编程挑战。让我们一起探索这个强大的语言,开启你的编程生涯吧!
|
11天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
11天前
|
机器学习/深度学习 数据挖掘 Python
Python编程入门——从零开始构建你的第一个程序
【10月更文挑战第39天】本文将带你走进Python的世界,通过简单易懂的语言和实际的代码示例,让你快速掌握Python的基础语法。无论你是编程新手还是想学习新语言的老手,这篇文章都能为你提供有价值的信息。我们将从变量、数据类型、控制结构等基本概念入手,逐步过渡到函数、模块等高级特性,最后通过一个综合示例来巩固所学知识。让我们一起开启Python编程之旅吧!
|
11天前
|
存储 Python
Python编程入门:打造你的第一个程序
【10月更文挑战第39天】在数字时代的浪潮中,掌握编程技能如同掌握了一门新时代的语言。本文将引导你步入Python编程的奇妙世界,从零基础出发,一步步构建你的第一个程序。我们将探索编程的基本概念,通过简单示例理解变量、数据类型和控制结构,最终实现一个简单的猜数字游戏。这不仅是一段代码的旅程,更是逻辑思维和问题解决能力的锻炼之旅。准备好了吗?让我们开始吧!
|
2天前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
5天前
|
存储 人工智能 数据挖掘
Python编程入门:打造你的第一个程序
本文旨在为初学者提供Python编程的初步指导,通过介绍Python语言的基础概念、开发环境的搭建以及一个简单的代码示例,帮助读者快速入门。文章将引导你理解编程思维,学会如何编写、运行和调试Python代码,从而开启编程之旅。
27 2
|
6天前
|
存储 Python
Python编程入门:理解基础语法与编写简单程序
本文旨在为初学者提供一个关于如何开始使用Python编程语言的指南。我们将从安装Python环境开始,逐步介绍变量、数据类型、控制结构、函数和模块等基本概念。通过实例演示和练习,读者将学会如何编写简单的Python程序,并了解如何解决常见的编程问题。文章最后将提供一些资源,以供进一步学习和实践。
16 1
|
13天前
|
设计模式 算法 搜索推荐
Python编程中的设计模式:优雅解决复杂问题的钥匙####
本文将探讨Python编程中几种核心设计模式的应用实例与优势,不涉及具体代码示例,而是聚焦于每种模式背后的设计理念、适用场景及其如何促进代码的可维护性和扩展性。通过理解这些设计模式,开发者可以更加高效地构建软件系统,实现代码复用,提升项目质量。 ####
|
9天前
|
存储 网络协议 IDE
从零起步学习Python编程
从零起步学习Python编程
|
12天前
|
机器学习/深度学习 存储 算法
探索Python编程:从基础到高级应用
【10月更文挑战第38天】本文旨在引导读者从Python的基础知识出发,逐渐深入到高级编程概念。通过简明的语言和实际代码示例,我们将一起探索这门语言的魅力和潜力,理解它如何帮助解决现实问题,并启发我们思考编程在现代社会中的作用和意义。
下一篇
无影云桌面