摘要:在前面介绍语法的过程中,我们已经接触到了解释器给的错误和异常,但并没有详细讲解它们。解释器这样报出的好处是告诉我们哪一行代码出错了错误的类型是什么。
在前面介绍Python语法的过程中,我们已经接触到了解释器给的错误和异常,但并没有详细讲解它们。现在我们就全面的来学习Python是对语法错误等错误进行定义和处理的,这包括至少有两种可以区分的错误,它们是语法错误和异常。
语法错误Python的语法错误就是不符合Python语法的错误,又称为解析错误。这种错误是初学Python对语法不是很熟悉时经常犯的。比如下面的例子:
In [1]: if 2 == 3 print("imposible") File "", line 1 if 2 == 3 print("imposible") ^ SyntaxError: invalid syntax
解释器在解释上面的代码时,就会发现表达式2 == 3后面少了一个冒号:,这时它就会报出一个错误SyntaxError: invalid syntax,并且输出出现语法错误的那一行,并显示一个“箭头”,指向这行里面检测到第一个错误。 错误是由箭头指示的位置上面的 token 引起的(或者至少是在这里被检测出的)。文件名和行号也会被输出,以便输入来自脚本文件时你能知道去哪检查。
解释器这样报出的好处是:
(1)告诉我们哪一行代码出错了;
(2)错误的类型是什么。
这样非常有利于我们排除错误,修正程序。
异常(Exception)如果我们对语法很熟悉,写出来的代码在语法上都是正确的,但也不能保证在执行时程序不会引发错误。在执行时检测到的错误被称为异常,异常不一定会导致严重后果,但我们不在代码中对它们进行处理,就可能会导致程序中断执行。下面是一些常见的错误异常信息:
In [2]: 5 / 0 ---------------------------- ZeroDivisionError Traceback (most recent call last)in ----> 1 5 / 0 ZeroDivisionError: division by zero In [3]: a + 3 ------------------------------ NameError Traceback (most recent call last) in ----> 1 a + 3 NameError: name "a" is not defined In [4]: 10 + "1" -------------------------------- TypeError Traceback (most recent call last) in ----> 1 10 + "1" TypeError: unsupported operand type(s) for +: "int" and "str"
我们看到,异常有不同的类型,其类型名称会作为错误信息的一部分中打印出来,上述示例中的异常类型分别是:ZeroDivisionError,NameError和TypeError。对于所有内置异常,打印出来的字符串是内置异常的名称。对于用户定义的异常则不一定如此,但我们自定义异常时最好按照内置异常那样去定义,这是一个很有用的规范。标准的异常类型是内置的标识符,而不是保留关键字。
打印出来的异常名称后面是异常发生的原因。错误信息的前一部分以堆栈回溯的形式显示发生异常时代码的上下文。一般它包含列出源代码行的堆栈回溯;但是它不会显示从标准输入中读取的行。
Python内置了很多异常,它们都从BaseException继承而来,下面是内置异常的继承关系:
异常处理既然程序会抛出异常,那我们就可以编写代码处理这些异常。先看下面的例子,它会让用户一直输入,直到输入的是一个有效的整数。我们也可以使用Control-C来中断程序;这个Control-C引起的中断会引发 KeyboardInterrupt 异常。
In [6]: while 1: ...: try: ...: n = int(input("input a number:")) ...: print("You typed number:", n) ...: break ...: except ValueError: ...: print("Nooo! It is not a number, Try agin") ...: input a number:a Nooo! It is not a number, Try agin input a number:b Nooo! It is not a number, Try agin input a number:3 You typed number: 3
当我们输入a时,它不能转换成整数就会报错异常ValueError。转换为整数的那条语句报出了异常,它后面的语句就不再执行,而是跳到except那里去执行它里面的语句。
try语句的工作原理如下:
首先,执行try 子句,即try和except关键词之间的(一行或多行)语句;
如果没有发生异常,则跳过except子句并完成try子句的执行;
如果执行try子句是发生了异常,则跳过该子句的剩下部分。然后,去匹配异常的类型和except关键字后面的异常,如果异常类型匹配则执行except子句,之后继续执行try语句后面的代码。
如果发生的异常和except后面的异常不匹配,则将其传递到外部的try语句,如果没有找到处理代码,则它是一个未处理异常,执行将停止并显示错误信息。
一个try语句可以有多个except子句,以便不同的异常用不同的处理程序进行处理。每次遇到异常最多会执行一个except子句,也就是说,处理程序只处理相应的异常,而不处理同一try语句内其它处理程序的异常。但是,一个except子句可以将多个异常包含在一个元组内,例如:
try: ... except (RuntimeError, TypeError, NameError): pass
异常都是继承于BaseException,如果except子句中的类和发生的异常是同一个类,或者是异常的基类(父类),则异常和except子句中的类是兼容的。但是,反过来则不成立。我们看看下面的代码,它将一次打印B,C,D。
class B(Exception): pass class C(B): pass class D(C): pass for cls in [B, C, D]: try: raise cls() except D: print("D") except C: print("C") except B: print("B")
如果我把 except 子句颠倒过来,把 except B 放到第一个,猜猜它将会打印出什么?答案是它将打印 B,B,B。也就是第一个匹配的 except 子句被触发,因为B是C、D的父类。
最后的 except 子句可以省略异常名称,以用作通配符匹配所有的异常。这个要小心使用,因为这种方式很容易掩盖真正的编程错误!但是它可用于打印错误消息,然后重新引发异常(同样允许调用者处理异常):
import sys try: f = open("zzz.txt") s = f.readline() i = int(s.strip()) except OSError as err: print("OS error: {0}".format(err)) except ValueError: print("Could not convert string to integer.") except: print("Unexpected error:", sys.exc_info()[0]) raise
try 语句有一个可选的 else 子句,在使用时它必须放在所有的 except 子句后面。对于在try 子句不引发异常时必须执行的代码来说很有用。例如:
try: f = open("zzz.txt", "r") except OSError: print("cannot open", "zzz.txt") else: print("zzz.txt", "has", len(f.readlines()), "lines") f.close()
使用else子句的好处是,它避免了意外捕获由else子句引发的异常。也就是说,程序中我们只想捕获open引发的异常,而不捕获f.readlines()引发的错误。
异常在抛出时可能具有关联的值,称为异常参数。参数的存在和类型取决于异常类型。
except子句可以在异常名称后面指定一个变量,这个变量就是该异常的实例,它的参数存储在instance.args中。为了方便起见,异常实例定义了__str__(),因此可以直接打印参数而无需引用.args。也可以在抛出之前首先实例化异常,并根据需要向其添加任何属性。:
In [7]: try: ...: raise Exception("认真学", "Python") ...: except Exception as e: ...: print(type(e)) ...: print(e.args) ...: print(e) ...: a, b = e.args ...: print("a =", a) ...: print("b =", b) ...:("认真学", "Python") ("认真学", "Python") a = 认真学 b = Python
异常处理程序不仅可以处理try子句中遇到的异常,还可以处理try子句中调用的函数的内部发生的异常,例如:
In [8]: def func(): ...: return 10/0 ...: In [9]: try: ...: func() ...: except ZeroDivisionError as err: ...: print("run-time error:", err) ...: run-time error: division by zero
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/43850.html
摘要:语句就是帮助我们抛出知道异常的,比如的使用很简单,它的语法如下如果它后面不带表达式参数,它会重新引发当前作用域内最后一个激活的异常。,用于异常的串联。自定义的异常类的名称通常以错误结尾,类似与内置标准异常的命名。 前面我们讲到的Python编程过程中,在可能出现异常的地方使用尝试语句,来正确的处理一些异常,可以保证程序不中断继续运行。 showImg(https://segmentfa...
摘要:新的称为子类,而被继承的称为基类父类或超类。继承最大的好处是子类获得了父类的全部功能。在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。 在上一篇中我们介绍了模块和数据结构,这一篇将介绍面向对象编程。 面向对象编程 面向对象编程——Object Oriented Programming,简称 OOP,是一种程序设计思想。OOP 把对象作为程序的基本单元...
?前言 代码出现异常而报错再正常不过了,但为什么要处理异常? 由于异常的存在,代码运行时会出现一大堆的红色字体提示,对于程序员还好,见红色报错见多了习惯了,但如果你开发出来的东西要给别人看,那么不懂代码的人就会一脸懵逼,对产品的印象都不太好了。 比如我们经常简单网页丢失的情况,其实是就是网页代码执行时发生了异常,但有的网页还是很个性的,提示的信息可能是比较人性化的,比如CSDN你收藏的文章被后台删...
摘要:本文与大家分享一些编程语言的入门书籍,其中不乏经典。全书贯穿的主体是如何思考设计开发的方法,而具体的编程语言,只是提供一个具体场景方便介绍的媒介。入门入门容易理解而且读起来幽默风趣,对于编程初学者和语言新手而言是理想的书籍。 本文与大家分享一些Python编程语言的入门书籍,其中不乏经典。我在这里分享的,大部分是这些书的英文版,如果有中文版的我也加上了。有关书籍的介绍,大部分截取自是官...
阅读 3345·2023-04-25 14:07
阅读 3368·2021-09-28 09:35
阅读 2056·2019-08-30 15:55
阅读 1365·2019-08-30 13:48
阅读 2479·2019-08-30 13:16
阅读 3158·2019-08-30 12:54
阅读 3215·2019-08-30 11:19
阅读 1843·2019-08-29 17:17