Python程序设计 - 错误与异常

学习目标:

本章知识导图:

9.1 基本概念

日常生活中,经常容易把错误和异常相混淆,下面分别看一下什么是错误和异常。

9.1.1 什么是错误

对编程而言,错误分两类:语法错误(Syntax Error)和逻辑错误(Logical Error)。

一、语法错误
语法错误是指不遵循语言的语法规则而引起的错误,通常表现为程序无法正常编译或运行。

在Python中,常见的语法错误有:

  1. 遗漏了某些必要的符号(冒号、逗号或括号等)
  2. 关键字拼写错误
  3. 缩进不正确
  4. 空语句块(需要用 pass 语句避免该错误)

二、逻辑错误
逻辑错误又称语义错误,是指程序语法上是正确,可以正常运行,但会产生错误的运行结果。

逻辑错误和编程语言无关,常见的逻辑错误有:

  1. 运算符优先级考虑不周
  2. 变量名使用不正确
  3. 语句块缩进层次不对
  4. 使用布尔表达式中出错等

9.1.2 什么是异常

在程序设计中语句或者表达式在·语法上正确·,但是执行时候可能会发生错误而停止。异常是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行。

Python用异常对象来表示异常情况。遇到错误后会引发异常。如果异常对象未被处理和捕捉,程序就会以堆栈回溯终止执行。

在Python中,常见的异常如下(括号中为触发的系统异常名称):

  1. 使用未定义的标识符(NameError)

异常通常有以下特点:

  1. 偶然性。程序运行中,异常并不总是会发生。
  2. 可预见性。异常的存在和出现是可以预见的。
  3. 严重性。一旦异常发生,程序可能终止,或者运行的结果不可预知。

9.2 Python中的异常

根据异常定义的主体不同,Python中的异常分为内置异常和用户自定义异常。

常见的内置异常:

9.2.1 内置异常

在实际开发中,大部分接触到的异常都是Exception的子类。一般情况下,在Python无法正常处理程序时就会触发一个异常。

当发生异常时,开发者需要捕获并处理它,否则程序会终止执行。

在Python程序异常终止时,解释器会以“堆栈回溯”(Traceback)的方式提示出异常信息。

9.2.2 用户自定义异常

9.3 Python中异常的检测与处理

在Python中,异常检测和处理最常用的方式是使用try-except、try-except-else和try-finally语句。另外,Python还提供了强制触发异常raise、断言机制assert和预定义的清理行为with等多种异常检测和处理机制。

9.3.1 try-except

try-except语句用来检测try语句块中的错误,在except语句中捕获异常信息并进行处理。
(1)处理单个异常
try-except语句处理单个异常的语法如下:

try:
#检测的语句
except Error[ as Target]:
# 处理异常的语句

首先执行try子句中的程序,在执行过程中如果没有异常,跳过except子句;如果发生了异常,则中断当前try子句中的执行,剩余try子句中的语句被跳过,跳转到异常处理块中开始执行。
例如:

try:
a = 20 / 2
print(a)
b = 4 * 2
print(b)
c = 4 / 0
print(c)
except Exception as error:
print(error)

结果:

10.0
8
pision by zero

从输出结果上可以看出,try语句中的print(a)和print(b)都正常执行了,但当执行c=4/0时发生了错误,因为0不能作为除数,此时如果没有try-except语句的话,程序执行到这就会报错了,如下:

a = 20 / 2
print(a)
b = 4 * 2
print(b)
c = 4 / 0
print(c)

结果:

10.0
8
Traceback (most recent call last):
File "D:/python_spider/python_demo/demo_2.py", line 5, in
c = 4 / 0
ZeroDivisionError: pision by zero

但是,因为有try-except语句,所以没有报错,只是打印了一个错误信息出来,程序并未发生异常中断执行,而是正常执行结束。

如果异常发生但没有匹配到except后的异常类型,那么异常抛到外层try语句;如果异常得不到处理,该异常成为未处理异常,导致程序终止并且打印异常信息,如下所示:

list2=[1,2,3,4]
try:
list2[4]
except KeyError as e:
print(e)

执行结果:

Traceback (most recent call last):
File "D:/python_spider/python_demo/demo_2.py", line 3, in
list2[4]
IndexError: list index out of range

(2)处理多个异常

try-except语句处理多个异常的语法如下:

try:

exceptError1 [ as Target]:

exceptError2 [ as Target]:

首先执行try子句中的程序,在执行过程中,如果没有异常,跳过except子句;如果发生了异常,则中断当前try子句中的执行,剩余try子句中的语句被跳过,跳转到对应的异常处理块中开始执行。

一个try语句可以有多个except子句,为不同的异常类型指定不同的处理方法。注意,不管有多少个except子句,本次运行至多只能有一个except子句被执行。

处理多个异常时,也可以把多个异常合并到一个except子语句中,使用带括号的元组方式列出多个异常类型,含义为对这些异常执行统一的处理方式,具体语法如下:

try:

except(Error1, Error2,...) [ as Target]:

处理多个异常时,也可以用Exception表示抓住所有异常,一般情况下建议在异常最后面用,用在最后抓未知的异常。具体语法如下:

try:

except(Error1, Error2,...) [ as Target]:

except Exception[ as Target]: #用Exception表示抓住所有异常

9.3.2 try except -else

另一种异常处理结构是try-except-else语句,其具体语法如下:

try:

exceptError1 [ as Target]:

exceptError2 [ as Target]:

else: #try子句中无异常,执行else子句

try-except-else语句是一种特殊的选择结构,如果try子句中的代码发生异常,并被某个except子句捕捉,则执行异常处理代码,此时,else子句不执行;如果try子句正常执行,没有异常发生,则执行else子句。

else子句的存在必须以except子句为前提,如果在没有except子句的try 语句中使用else子句会引发语法错误。

9.3.3 try-finally

try-finally语句,try子句无论是否有异常发生,finally子句在离开try语句之前总是会执行,其具体语法如下:

try:

finally: # try子句中有无异常,均执行finally子句
< finally块>

对于当try子句中有异常发生并且没有被except子句处理,或是异常发生在except子句或else子句时,在finally子句执行之后,这些异常会重新抛出。

list2=[1,2,3,4]
try:
list2[4]
finally:
pass

结果:

Traceback (most recent call last):
File "D:/python_spider/python_demo/demo_2.py", line 3, in
list2[4]
IndexError: list index out of range

9.3.4 try except-else-finally

在实际开发中,经常把try-except和try-finally混合使用,其语法结构如下:

try:

except Error1 [as Target]:

except Error2 [as Target]:

else: # try子句无异常,执行else子句

finally: # try 子句有无异常,均执行finally子句

在使用完整的try/except/else/finally语句时,出现的顺序必须是try-- >except-->else-->finally。

当try语句的其它子句通过break、continue或者return语句离开时,finally子句也会执行,但原来的异常将被丢失且无法重新触发。

在实际开发中,finally子句常用来释放外部资源,如文件和网络连接等,不论资源的使用是否成功

9.3.5 强制触发异常raise

不管是使用try-except语句还是try-finally语句,出现的异常都是由解释器自动引发的。在实际项目中,比如对一些不合法输入要立即处理,这需要一种可以主动触发异常的机制。在Python中,用raise语句强制触发异常,其语法结构如下:

raise [Exception [, args [, traceback]]]

当 Python 解释器接收到开发者自行引发的异常时,会中止当前的执行流,跳到该异常对应的 except 块,由该 except 块来处理该异常。

不管是系统自动引发的异常,还是程序员手动引发的异常,Python 解释器对异常的处理没有任何差别。

9.3.6 断言机制assert

在没完善一个程序之前,不确定程序在哪里会出错,与其让它在运行时崩溃,不如在出现错误条件时就崩溃,这时候就需要assert断言的帮助,其语法结构如下:

assert expression [, arguments]

如果expression结果为真,什么都不做;如果expression结果为假,触发异常。
例如:

assert 0*2

结果:

Traceback (most recent call last):
File "D:/python_spider/python_demo/demo_2.py", line 1, in
assert 0*2
AssertionError

assert逻辑上等同于raise-if-not;
arguments是在断言表达式后添加字符串信息,用来解释断言并更好的知道是哪里出了问题。

if not condition:
raise AssertionError()

9.3.7 预定义的清理行为with

程序运行时,当不再需要一些对象时,系统会自动执行清理动作,而不论对象操作是否成功,开发者都不用手动执行对象清理动作。但是在某些条件下会有问题,如下所示:

for line in open("t.txt"):
print(line, end="")

上述代码中,假设文件"t.txt"存在,程序会读取该文件并打印内容到显示器,之后文件会保留打开状态并持续一段不确定的时间。这在简单的脚本中不是什么大问题,但是在大型的应用程序中就会出现问题,因为在此期间可能有其它代码使用该文件。
此时就需要用with,例如:

with open('t.txt') as file:
file.readlines()

这样就不用自己去清理内存了,当with语句执行完后,自动销毁内存。

9.4 总结

展开阅读全文

页面更新:2024-03-13

标签:异常   错误   子句   断言   开发者   程序设计   语句   语法   逻辑   发生   程序

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top