异常

例题引导:编写一个计算减法的方法,自己输入两个数,当第一个数小于第二个数时,抛出“被减数不能小于减数”的异常。

解题思路:首先需要一个判断的语句,比较两个数大小,其次需要定义异常,主要掌握try/except语句

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def jianfa(a,b):
if a<b:
raise BaseException('被减数不能小于减数')
#return 0
else:
return a-b
try:
a=int(input())
b=int(input())
print(jianfa(a, b))
print("没遇到自己定义的错误") #不打印
except:
print("被减数不能小于减数")
finally:
print("OK")

学习引导:

  • 语法错误
  • 处理异常
  • 异常else
  • 异常finally
  • 自定义异常

异常

在我们刚接触python的时候,肯定遇到过无数次的报错。
python中有两种错误很容易辨认:语法错误和异常

语法错误

python的语法错误又称为解析错,多数是语法格式上出现问题。比如:

1
print'Hello World'#这里的括号为中文格式下的,所以报错
1
2
3
4
  File "<ipython-input-1-f552c294b592>", line 1
print'Hello World'
^
SyntaxError: invalid character in identifier

处理异常

即使python程序的语法是正确的,在运行它时也可能报错。

运行过程中出现的错误称为异常。

大多数的异常不会被程序自动处理,因此产生错误信息(即报错)

异常捕捉可以用try/except语句:

1
2
3
4
5
6
while True:
try:
x=int(input('请输入一个数字:'))
break
except ValueError:
print('您输入的不是数字,请再次尝试输入!')
1
2
3
4
5
'''
请输入一个数字:s
您输入的不是数字,请再次尝试输入!
请输入一个数字:3
'''

try 语句按照如下方式工作;

  • 首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)。

  • 如果没有异常发生,忽略 except 子句,try 子句执行后结束。

  • 如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。

  • 如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。

捕获指定异常:
1
2
3
4
5
6
7
try:

<语句>

except<异常名>:

print('异常说明')

一个例子:

1
2
3
4
5
6
try:
f = open("file-not-exists", "r") #试图打开一个本不存在的文件

except IOError as e: #IOErro:指要打开的文件不存在的错误提示,Try语句的错误与expect匹配,执行print语句。

print("open exception: %s: %s" %(e.errno, e.strerror))
#open exception: 2: No such file or directory
捕获多个异常

捕获多个异常有两种方式,第一种是一个except同时处理多个异常,不区分优先级

1
2
3
4
5
6
try:
<语句>

except (<异常名1>, <异常名2>, ...):

print('异常说明')

第二种是区分优先级的:

1
2
3
4
5
6
7
8
9
10
11
try: <语句>

except <异常名1>:

print('异常说明1')
except <异常名2>:

print('异常说明2')
except <异常名3>:

print('异常说明3')

实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
import sys

try:
f = open('myfile.txt') #打开文件
s = f.readline() #按行读取
i = int(s.strip()) #都成整数类型
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
1
#OS error: [Errno 2] No such file or directory: 'myfile.txt'

该种异常处理语法的规则是:

  • 执行try下的语句,如果引发异常,则执行过程会跳到第一个except语句。

  • 如果第一个except中定义的异常与引发的异常匹配,则执行该except中的语句。

  • 如果引发的异常不匹配第一个except,则会搜索第二个except,允许编写的except数量没有限制。

  • 如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。

异常的else

如果判断完没有某些异常之后还想做其他事,就可以使用下面这样的else语句。

1
2
3
4
5
6
7
8
9
10
11
try:
<语句>

except <异常名1>:
print('异常说明1')

except <异常名2>:
print('异常说明2')

else:
<语句> # try语句中没有异常则执行此段代码

异常的finally

try…finally…语句无论是否发生异常都将会执行最后的代码。

1
2
3
4
5
6
7
try:

<语句>

finally:

<语句>

一个实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
str1 = 'hello world'
try:
int(str1)
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except ValueError as e:
print(e)
else:
print('try内没有异常')
finally:
print('无论异常与否,都会执行我')
1
2
#invalid literal for int() with base 10: 'hello world'
#无论异常与否,都会执行我

自定义异常

自定义类继承Exception

你可以通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承。

在try语句块中,抛出用户自定义的异常后执行except部分,变量 e 是用于创建MyError类的实例。

实例如下:

1
2
3
4
5
class MyError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
1
2
3
4
try:
raise MyError(2*2)
except MyError as e:
print('My exception occurred, value:', e.value)
1
#My exception occurred, value: 4
1
raise MyError('oops!')
1
2
3
4
5
6

MyError Traceback (most recent call last)

<ipython-input-16-3e3ae366964f> in <module>
----> 1 raise MyError('oops!')
MyError: 'oops!'

在上述例子中,类 Exception 默认的 __ init__() 被覆盖。

当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Error(Exception):
"""Base class for exceptions in this module."""
pass

class InputError(Error):
"""Exception raised for errors in the input.

Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""

def __init__(self, expression, message):
self.expression = expression
self.message = message

class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.

Attributes:
previous -- state at beginning of transition
next -- attempted new state
message -- explanation of why the specific transition is not allowed
"""

def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message

大多数的异常的名字都以”Error”结尾,就跟标准的异常命名一样。

raise自定义异常类

raise语法格式如下:

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

语句中Exception是异常的类型(例如ValueError),参数是一个异常参数值。该参数是可选的,如果不提供,异常的参数是”None”。最后一个参数是跟踪异常对象,也是可选的(在实践中很少使用)。

1
2
3
4
5
6
7
8
9
def not_zero(num):
try:
if num == 0:
raise ValueError('参数错误')
return num
except Exception as e:
print(e)
not_zero(0)

1
#参数错误

小作业:

  1. 简述如下各常见异常的含义并举例:SyntaxError、KeyError、IndexError、AttributeError、OSError、TypeError

评论