在一个完美的世界中,我们的所有代码都可以无缺地运行,而无需考虑将代码投入生产时可能出现的问题。然而,我们并不生活在一个完美的世界中。正如你可以想象的,您的软件或应用在执行过程中可能会发生许多问题:
- 用户输入了错误类型的信息(可能是一个字符串,但期望的是整数)
- 用户名和/或密码不正确
- 应用程序无法连接到数据库
- 某个设备连接失败
- 用户失去了与网络或互联网的连接
- 资源(文件、数据库表等)不可用
- 存在内存冲突
- 还有很多其他问题
这并不总是意味着您的代码存在问题。但是您需要通过使用异常来处理这些可能的问题。如果您刚开始使用python进行编码,您可能没有很多机会使用异常处理。
如果是这种情况,不用担心。我们将深入研究python中的异常处理,并通过一些简单的示例来解释。让我们开始吧!
python中的异常处理:错误与异常的区别
在我们深入了解异常之前,我们需要澄清一件事:一个错误和一个异常之间有一个明显的区别。
在编码过程中,您会遇到错误,由于代码语法的问题,这些错误会导致软件无法正常运行。而异常则会在运行时发生。
无论您是初级还是高级的软件开发人员,在测试代码时都会遇到python中的错误。不要感到难过。这只是游戏的一部分。重要的是您如何处理它们。
在编写程序时,您偶尔会遇到三种类型的错误。让我们依次看看它们。
语法错误
当python解释器无法理解您的代码时,就会发生这种错误。简单地说,这意味着您没有遵循编程语言的语法规则。
例如,如果您打印一个简单的字符串,可能会忘记在括号内的字符串周围加上引号。您将收到一个语法错误,并且必须在运行之前修复您的代码。
异常(或运行时错误)
在应用程序运行期间发生异常时,会出现异常。在这种情况下,您的语法可能绝对完美,但您可能拼错了您定义的某个内容,或者在代码运行时遇到了意外情况。
逻辑错误
这种类型的错误很难识别,因为程序在没有任何错误消息或异常警告的情况下运行。然而,当程序运行时,它会给出错误的结果。
这可能是由于代码中编写的错误逻辑导致的。避免这种情况的一种方法是在编写代码时测试每个代码段,并确保在产生正确结果之前不继续进行。
python中的内置异常处理类型
内置异常是编程语言中内置的一种运行时错误形式。我们没有足够的空间在这里介绍python中的每个内置异常,但我们将简要讨论最常用的异常,并展示它们在代码中的示例。
1. 属性错误(attributeerrors)
简单地说,属性是属于该类的所有实例的类的变量。如果在代码中使用了所有适当的属性,那么您将没有机会看到它是如何工作的。
然而,在某些时候,您会拼写错误属性或忘记将特定属性放入类中,所以您需要在代码中处理这些可能性。请参见下面的示例。
python中异常处理的示例,显示attributeerror异常。
©jingzhengli.com
在这个简短的代码片段中,我们创建了一个名为“animal”的类,具有三个属性:name、age和species。在我们的主要代码中,我们实例化了“newanimal”,它将预期的参数发送给该类。
在下面,我们创建了一个称为try/except块的块。在块的“try”部分,我们告诉python在其范围内“尝试”执行代码。
在此块中,如果代码执行不成功,python将控制转移到“except”块,该块在本例中是描述出了什么错误的错误消息。如果您运行此代码,并且属性与程序中的属性不完全相同,它将抛出此attributeerror。
2. nameerrors
这种类型的内置异常与python的attributeerror类似;然而,它有一个细微的差别。nameerrors表示我们正在尝试访问当前范围中不存在的变量或函数。
看下面的例子,以及输出:
尝试调用不存在的变量或函数是一个常见的错误。
©jingzhengli.com
这样做将导致nameerror,并且python会警告您该变量或函数未定义。
©jingzhengli.com
顶部的代码是一个简单的函数,通过将两个数字的和除以2来返回它们的平均值。然而,您可以在我们的代码的主要区域中清楚地看到函数的调用是不正确的。
由于我们的语法没有问题,编译器会尝试执行代码,但由于函数定义与函数调用之间存在不匹配,它遇到了nameerror。
当编码时,这样简单的东西很难被忽视,因为您可以清楚地看到红色的下划线,表示我们的代码有问题。在这里使用的ide是pycharm,但您使用的任何其他ide都应该表现类似。
3. typeerrors
这是许多初学者和有经验的python开发人员看到的另一个常见异常。它只是表示python期望接收一个它没有收到的类型。
例如,也许它期望一个浮点值(或变量),而您使用了一个字符串。这听起来难以置信,但您将在下面的示例中看到,这种错误并不难发生!
typeerror异常很方便,在您使用不正确的类型时提醒您。
©jingzhengli.com
在这个简短的程序中,我们正在要求用户输入两个数字,以便进行简单的计算。然而,如果您不考虑python如何存储输入数据,就会出现问题。
您看,用户输入的任何内容都将作为字符串存储在内存中。因此,如果您需要它以整数形式,您必须将其转换为整数。
我们已经在“try”块的第一行中适当地进行了处理。但是,在第二行中,我们将其保留为字符串,以演示将存储为字符串的数字进行计算时会发生什么。
由于“y”变量被存储为字符串,所以“try”块会将控制权交给except块,因为它检测到了typeerror异常。而且你应该记住,任何其他类型的异常都会导致终端输出错误消息,因为它在代码中未被处理。
因此,如果我们在这里得到了一个nameerror异常(但不是typeerror),那么“except”块将不会执行,并且程序将停止执行,并在终端上抛出typeerror消息。
4. 索引错误
另一个常见的异常是在使用数据集合时,尝试访问不存在的元素。
这将导致一个indexerror异常,我们强烈建议在处理数据集合时始终计划处理这种类型的异常。
下面是一个在python中使用列表的示例:
一旦输入的数字大于索引值,就会引发一个indexerror。
©jingzhengli.com
在这里,我们在顶部有一个包含五只动物的列表。我们设置一个布尔变量来控制用户是否想要再次游戏,然后进入try-except块来检查可能发生的任何异常。
如果用户输入0、1、2、3或4(记住:列表编号从0开始),那么相应的动物将打印到屏幕上。然而,我们必须考虑到超过这些数的任何数字,因为用户很可能也会输入更大的数字。
一旦输入的数字大于4,控制权就会转移到“except”块,因为我们遇到了一个indexerror。
从那里,我们告诉用户发生了什么,并询问他们是否想要再玩一次。如果不想玩,我们将布尔值切换为true,然后程序结束。
否则,我们循环再次检查另一个数字。无论“except”块是否执行,我们都会继续询问他们是否想要输入另一个数字,直到他们最终放弃并输入“n”表示不想要。
更多内置异常
上述异常并不是您将遇到的所有可能的运行时错误的详尽列表,但它们是最常见的。您可能还希望熟悉以下内置异常:
- zerodivisionerror:程序尝试除以零时发生
- eoferror:在没有读取任何数据的情况下到达文件结尾时发生
- importerror:在编译器加载尝试导入的模块时发生问题
- filenotfounderror:无法找到指定的文件或目录时发生
- keyerror:在字典中找不到键时发生
- runtimeerror:当异常不适合任何其他类别时发生
python中的异常处理:自定义异常
除了python的内置异常之外,您还可以创建自定义异常。一旦开始构建需要与最终用户良好通信的真实应用程序,您将发现这种能力非常有用。
用户自定义异常最困难的部分在于知道你的程序需要哪种类型的异常。随着你开发更复杂的算法并积累更多的python经验,你会逐渐了解到这些知识。
但是,在你工作的每个单独程序中,一旦你对代码的行为进行了彻底的测试,你就能够确定创建哪种类型的异常。
用户自定义异常的示例
如果你想创建自己的异常,你需要首先定义一个继承自内置的exception类的类。让我们看看如何做到这一点。
在下面的示例代码中,我们创建了一个简短的算法,用于测试用户的电子邮件和密码是否与数据库中的信息匹配。
在你太兴奋之前,请记住,在实际应用中,这将会更加复杂,包括使用哈希算法加密敏感信息等等。
从exception类继承一个类是创建用户自定义异常的第一步。
©jingzhengli.com
这段代码的执行从第17行开始,我们在这里创建了用户名和密码的字典。如你所见,每个用户都有一个对应的密码,我们的算法将会进行检查。
接下来,我们要求用户输入他们的用户名和密码,并将其存储在自己的字符串变量中。这允许我们执行下一步,即调用“login”函数,发送用户名和密码以便我们可以检查是否匹配。
在代码顶部的类定义中,我们创建了一个自定义异常类,基于python的内部异常类。这里没有执行任何代码,所以我们使用“pass”进行了文档化并表示我们不需要在这里做任何事情。
因为我们告诉编译器“invalidlogin”基于“exception”类,所以它知道要继承原始类的所有元素和行为。
修复用户自定义异常
现在,让我们看看我们的“login”函数。它从主代码接收用户名和密码,并检查字典以查看是否匹配。
该函数的算法检查用户名是否存在。如果不存在,它会引发我们定义的函数“invalidlogin”。如果存在,它会继续检查密码以确保它是该用户的密码。
但是,如果两个条件都满足,则用户将收到一个简单的打印消息“登录成功”,程序结束。否则,python会引发一个异常,用户会看到这个消息:“invalidlogin:无效的用户名或密码。”
在实际应用中,你可能会有一个单独的文件来存放所有的异常,以保持你的主应用代码干净和易读。如果在这种情况下,我们需要在程序的顶部导入异常文件,以便编译器知道从哪里获取这些类定义。
了解python中的异常处理:总结
通过这些示例的工作和进行一些自己的测试,你现在应该对python错误、异常有了更好的理解,并知道如何在代码中最好地处理它们。
当创建用于生产的应用程序时,这是一个你需要完全理解并熟练掌握的概念,以使你的软件对各种用户都有用。
就像任何其他类型的业务沟通一样,使用异常和异常处理将帮助您建立软件产品与每天使用它的用户之间更好的关系。现在,让我们回答一些关于python异常处理的常见问题。