异常处理

任何语言,异常都包括2种:

  • 编译期异常: 自己的错误,如参数传递错误,类型不匹配,指针越界,变量名,方法名写错,除以0的操作,读取不存在的文件
  • 运行期异常:断网

python是如何处理异常的?

python处理异常的方法有2种:

  • 捕获
  • 抛出

1. try..except...捕获异常

try:
    代码块1
except:
    代码块2

执行流程:从try下面的代码块1开始执行,如果发生异常,则会直接跳入代码块2;如果未发生异常,则只会执行代码块1

fruit = ["apple","pear"]

try:
    f = fruit[2]
    print(f)
except:
    print("列表索引越界啦")

以上代码不回报错,会输出

列表索引越界啦

再来个例子:

fruit = ["apple","pear"]

try:
    f = fruit[1]
    print(f)
except:
    print("列表索引越界啦")

则永远不会执行代码块2

捕获指定异常

try:
    代码块1
except 异常X as e:
    代码块2

举例:


fruit = ["apple","pear"]

try:
    f = fruit[2]
    print(f)
except IndexError as e:
    print("列表索引越界啦:",e)
列表索引越界啦: list index out of range

捕获指定的多个异常

try:
    代码块1
except (异常X,异常Y,异常Z) as e:
    代码块2

等价于

try:
    代码块1
except 异常X as e:
    代码块2
except 异常Y as e:
    代码块3
except 异常Z as e:
    代码块4

第一种是把异常放在一个except下处理,第二种,是把异常放在不同的except下处理。无论用哪种方式,当程序发生异常时,python会根据异常类型去匹配对应的except语句,然后执行其中的代码块。

若异常没有匹配到,则会继续抛出。那么这2种方式有什么区别呢?

  • 第一种方式适用于多种异常可以用相同的代码块去处理
  • 第二种方式适用于不同的异常需用不同的代码去处理

try-except-finally 语句

try:
    代码块1
except Exception as e:
    代码块2
finally:
    代码块3

它的执行流程是:

1. 先执行代码块1
2. 如果代码块1出现异常,则跳转到代码块2;如果代码块1未出现异常,则代码块1执行完之后,不回执行代码块2
3. 最后执行代码块3

finally到底有什么用?

打个比方,举个例子,我们有时会在 try 下使用一些资源(比如文件、网络连接),而无论过程中是否有异常产生,我们在最后都应该释放(归还)掉这些资源,这时就可以将释放资源的代码放在 finally 语句下。

2.raise语句主动抛出异常

之前的示例中,异常是在程序遇到错误无法继续执行时,由解释器所抛出,我们也可以选择自己主动抛出异常。

主动抛出异常的方法是使用 raise 语句:

raise ValueError()

也可以同时指明错误原因:

raise ValueError("输入值不符合要求")

我们用示例来学习为什么要主动抛出异常,以及如何主动抛出异常。

之前我们在学习函数的时候写过这样一个函数:

def stage_of_life(age):
    if age <= 6:
        return '童年'
    elif 7 <= age <=17:
        return '少年'
    elif 18 <= age <= 40:
        return '青年'
    elif 41 <= age <= 65: 
        return '中年'
    else:
        return '老年'

显然这个函数没有应对可能出错的情况。比如函数的 age 参数不能任意取值,要符合人类的年龄范围才行,如果取值超出范围就需要向函数调用方报告错误,这时就可以采取主动抛出异常的方式。

我们在函数内检验输入值的有效性,若输入有误则向外抛出异常,新增第 2 和第 3 行代码:

def stage_of_life(age):
    if age < 0 or age > 150:
        raise ValueError("年龄的取值不符合实际,需要在 0 到 150 之间")

    if age <= 6:
        return '童年'
    elif 7 <= age <=17:
        return '少年'
    elif 18 <= age <= 40:
        return '青年'
    elif 41 <= age <= 65: 
        return '中年'
    else:
        return '老年'

stage_of_life(180)

这里检查 age 的范围是否在 0~150 之间,若不是则使用 raise 抛出 ValueError 异常,表示取值错误。

Traceback (most recent call last):
  File "a.py", line 16, in <module>
    stage_of_life(180)
  File "a.py", line 3, in stage_of_life
    raise ValueError("年龄的取值不符合实际,需要在 0 到 150 之间")
ValueError: 年龄的取值不符合实际,需要在 0 到 150 之间

results matching ""

    No results matching ""