教师妹学python之六:异常处理
对于小白而言,运行编写的程序遇到报错,往往不知所措,不清楚什么原因造成的。完美的程序是不存在的,程序有异常才是常态,所以遇到缺陷不要慌,找到错误根因解决它就行了。 本节就专门介绍一下编程过程可能遇到的一些错误,如果你能识别这些异常原因并fix,那么你就掌握了异常处理方法。
6.1 错误类型
简单来说,Python中存在两种错误类型:语法错误和程序异常。
6.1.1 语法错误
语法错误即开发者没有按照Python要求的编程规范进行编程,导致语法错误。为了避免语法错误,建议使用Pycharm IDE,IDE的语法分析器可以实时check编写程序过程中的语法错误,并给出提示。
语法错误示例:
while True print('Hello world') >>File "/Users/demo.py", line 1 while True ^ SyntaxError: invalid syntax
例子中函数 while True 被检查到有错误,是它前面缺少了一个冒号 : 。
语法分析器指出了出错的一行,并且在最先找到的错误的位置标记了一个小小的箭头。
⚠️ SyntaxError: invalid syntax 即语法错误:语法无效
6.1.2 程序异常
掌握了编程规范,开发程序过程就能避免语法错误的出现,即使你的程序没有语法错误,运行程序过程仍会发生错误,程序运行期间发生的错误程序为程序异常。处理异常前必须找到异常根因,对症下药解决问题。下面给出几种异常示例,主要是教大家如何识别这种异常。
示例一:
10 * (1/0) >> Traceback (most recent call last): File "/Users/demo.py", line 1, in <module> 10 * (1/0) ZeroDivisionError: division by zero # 0 不能作为除数,触发异常
示例二:
'2' + 2 >> Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate str (not "int") to str # int 不能与 str 相加,触发异常
示例三:
dict = {} dict['hello'] >> Traceback (most recent call last): File "/Users/demo.py", line 2, in <module> dict['hello'] KeyError: 'hello' #键错误
示例四:
list = [1, 2] list[2] >>Traceback (most recent call last): File "/Users/demo.py", line 2, in <module> list[2] IndexError: list index out of range #索引超出限制
通过示例你也看到了,异常会以不同的类型出现,这些类型都作为信息的一部分打印出来: 例子中的类型有 ZeroDivisionError、TypeError 、KeyError和IndexError。错误信息的前面部分显示了异常发生的上下文,并以调用栈的形式显示具体错误信息。
程序异常类型千千万,但所有的错误都是从BaseException类派生的,常见的错误类型和继承关系看这里:
附:Python内置异常类型 Built-in Exceptions — Python 3.10.3 documentation
当然,初级编程者无需专门学习这些异常,可以通过不断的编程,发现这些异常并解决。
6.2 处理异常
程序中遇到异常意味着会中断运行下面的程序,这显然不是我们想看到的。由于没有完美的程序,我们期望在程序运行过程可以自动忽略一些无关紧要的异常,而不影响整体程序的运行。而Python也提供了一种try/except机制来帮助我们处理这些异常。
6.2.1 try/except语句
try/except即:如果在try程序块遇到错误,则会执行except程序块的程序,这样避免了程序中断。
示例:
while True: try: x = int(input("请输入一个数字: ")) break except ValueError: print("您输入的不是数字,请再次尝试输入 >> 请输入一个数字: a 您输入的不是数字,请再次尝试输入! 请输入一个数字:
这个例子要求用户从键盘输入一个数字,如果用户输入的不是数字则会继续让你输入一个数,直到输入的是数字为止。
当然,在一个大型项目中,不仅仅只有某种异常,往往是有很多异常,所以一个try语句可能包含多个except子句,分别来处理不同的特定的异常,而最多只有一个分支会被执行。
try: xxx except OSError as err: print("OS error: {0}".format(err)) except ValueError: print("Could not convert data to an integer.") except: print("Unexpected error:", sys.exc_info()[0]) raise
6.2.3 try/except...else 语句
try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。
else 子句将在 try 子句没有发生任何异常的时候执行。
示例:
try: x = int(input("请输入一个数字: ")) except ValueError: print("您输入的不是数字,请再次尝试输入!") else: print("输入数字且没有异常") >> 请输入一个数字: 1 没有异常
使用 else 子句比把所有的语句都放在 try 子句里面要好,这样可以避免一些意想不到,而 except 又无法捕获的异常。
6.2.3 try-finally 语句
try-finally 语句无论是否发生异常都将执行最后的代码。
示例:
try: x = int(input("请输入一个数字: ")) except ValueError: print("您输入的不是数字,请再次尝试输入!") else: print("输入数字且没有异常") finally: print("不管是否异常,我都会执行") >>请输入一个数字: q 您输入的不是数字,请再次尝试输入! 不管是否异常,我都会执行
重点说一下finally语句的使用场景,作为测试岗位,会经常使用Python处理一些数据文件,需要对文件进行读写操作,当你读写操作进行完毕后,这时候建议使用finally语句对这些文件进行关闭。
try: with open('demo.py', 'r') as f: f.readlines() except: print("打开文件异常") finally: f.close()
6.3 抛出异常
上述的内容讲述了如何处理异常,那么为什么还要抛出异常呢?因为有时候你开发程序的过程并不知道程序在执行过程会遇到什么的异常,如果单纯的except处理掉,你并不能发现程序异常的根因,这时候可以使用raise语句抛出一个指定的异常。示例如下:
while True: try: x = int(input("请输入一个数字: ")) except Exception: raise >>请输入一个数字: a Traceback (most recent call last): File "/Users/demo.py", line 3, in <module> x = int(input("请输入一个数字: ")) ValueError: invalid literal for int() with base 10: 'a'
假如你并不知道这段程序在执行过程会遇到何种异常,那么可以使用raise语句抛出异常根因。
往期文章:
更多文章欢迎关注公众号: