疯狂Python讲义学习笔记(含习题答案)之 异常处理

Python的异常机制主要依赖try、except、else、finally和raise五个关键字,其中try块中放置的是可能引发异常的代码;except后对应处理这种异常的代码;在多个except块之后可以放一个else,表明程序不出现异常时还要执行else;最后还可以跟一个finally,用于回收在try块里打开的物理资源,异常机制会保证finally块总是被执行;而raise用于引发一个实际的异常,raise可以单独作为语句使用。

一、异常概述

错误处理机制,主要有如下两个缺点:

● 无法穷举所有的异常情况。因为人类知识的限制,异常情况总比可以考虑到的情况多,总有“漏网之鱼”的异常情况,所以程序总是不够健壮。

● 错误处理代码和业务实现代码混杂。这种错误处理和业务实现混杂的代码严重影响程序的可读性,会增加程序的维护难度。

二、异常处理机制

当程序运行出现意外情况时,系统会自动生成一个Error对象来通知程序,从而实现将“业务实现代码”和“错误处理代码”分离.

异常处理机制的语法结构:

try:
    # 业务实现代码
    ...
except (Error1, Error2, ...) as e:
    alert 输入不合法
    goto retry

如果在执行try块里的业务逻辑代码出现异常,系统自动生成一个异常对象,该异常对象被提交给Python解释器,这个过程被称为引发异常。

当Python解释器收到异常对象时,会寻找能处理该异常对象的except块,如果找到合适的except块,则把该异常对象交给该except块处理,这个过程被称为异常捕获。

如果Python解释器找不到异常捕获的except块,则运行环境终止,Python解释器也将退出。

 

 

Python的所有异常类的基类是BaseException,但如果用户要实现自定义异常,则不应该继承这个基类,而是继承Exception类。不管是系统异常类,还是用户自定义异常类都应该从Exception派生。

虽然Python语法没有要求,但在实际编程时一定要记住先捕获小异常,再捕获大异常。

在使用一个except块捕获多种类型的异常时,只要将多个异常类用圆括号括起来,中间用逗号隔开即可——其实就是构建多个异常类的元组。

所有的异常对象都包含了一下几个常用的属性和方法:

● args:该属性返回异常的错误编号和描述字符串。

● errno:该属性返回异常的错误编号

● strerror:该属性返回异常的描述字符串

● with_traceback():通过该方法可处理异常的传播轨迹信息。

在Python的异常处理流程中还可以添加一个else块,当try块没有出现异常时,程序会执行else块。

如果希望某段代码的异常能被后面的except块捕获,那么就应该将这段代码放在try块的代码之后;如果希望某段代码的异常能向外传播(不被except块捕获),就应该将这段代码放在else块中。

不管try块中的代码是否出现异常,也不管哪一个except块被执行,甚至try块或except块中执行了return语句,finally块总会被执行。

在异常处理语法结构中,只有try块是必须的。

不要在finally块中使用如return或raise等导致方法中止的语句,一点在finally块中使用了return或raise语句,将会导致try块、except块中的return、raise语句失效。

异常可以被嵌套,在try块、except块或finally块中包含完整的异常处理流程的情形被称为异常处理嵌套。

对异常处理嵌套的深度没有明确的限制,但通常没有必要使用超过两层的嵌套异常处理。

三、使用raise引发异常

如果需要在程序中自行引发异常,则应使用raise语句。raise语句有如下三种常用的用法:

● raise:单独一个raise,该语句引发当前上下文中捕获的异常(比如在except块中),或默认引发RuntimeError异常。

● raise 异常类:raise后带一个异常类。该语句引发指定异常类的默认实例。

● raise 异常对象:引发指定的异常对象。

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

四、Python的异常传播轨迹

异常对象提供了一个with_traceback用于处理异常的传播轨迹,查看异常的传播轨迹可追踪异常触发的源头,也可看到异常一路触发的轨迹。

只要异常没有被完全捕获(包括异常没有被捕获,或者异常被处理后重新引发了新异常),异常就从发生异常的函数或方法逐渐向外传播,首先传给该函数或方法的调用者,再传给其他调用者,直至最后传到Python解释器,此时Python解释器会终止程序,并打印异常的传播轨迹信息。

Python专门提供了traceback模块来处理异常传播轨迹。

● traceback.print_exec():将异常传播轨迹信息输出到控制台或指定文件中。

● format_exec():将异常传播轨迹信息转换成字符串。

五、异常处理规则

成功的异常处理应该实现如下4个目标:

● 是程序代码混乱最小化

● 捕获并保留诊断信息

● 通知合适的人员

● 采用合适的方式结束异常活动

异常只应该用于处理非正常的情况,不要使用异常处理来代替正常的流程控制。

通常建议对异常采取适当措施,如:

● 处理异常。对异常进行合适的修复,然后绕过异常发生的地方继续运行;或者用别的数据进行计算,以代替期望的方法返回值:或者提示用户重新操作

● 重新引发新异常。把在当前运行环境下能做的事情尽量做完,然后进行异常转译,把异常包装成当前层的异常,重新传给上层调用者。

● 在合适的层处理异常。如果当前层不清楚如何处理异常,就不要在当前层使用except语句来捕获异常,让上层调用者来负责处理该异常。

 

习题:

1. 提示用户输入一个N , 表示用户接下来要输入N 个宇符串,程序尝试将用户输入的每一个字符串用空格分割成两个整数,并结算这两个整数整除的结果。要求: 使用异常处理机制来处理用户输入的各种错误情况,并提示用户重新输入。

n = input('请输入一个整数:')
try:
    num = int(n)
    i = 0
    while(True):
        num_str = input('请输入以空格分隔的两个整数:')
        try:
            a, b = num_str.split(' ')
            print("%d整除%d的结果为:%d" % (int(a), int(b), int(a) // int(b)))
            i += 1
            if i >= num:
                break
        except ValueError:
            print("必须输入两个以空格隔开的数字,请重新输入!")
            continue
except ValueError:
    print("请输入一个数字")

2. 提示用户输入一个整数,如果用户输入的整数是奇数,则输出“有趣”;如果用户输入的整数是偶数,且在2~5 之间,则打印“没意思”;如果用户输入的整数是偶数,且在6~20 之间,则输出“有趣”;如果输入的整数是其他偶数,则打印“没意思”。要求:使用异常处理机制来处理用户输入的各种错误情况。

n = input('请输入一个整数:')
try:
    n = int(n)
    if (n % 2 == 0) and (n >= 2) and (n <= 5):
        print('没意思!')
    elif (n % 2 == 0) and (n >= 6) and (n <= 20):
        print('有趣!')
    elif (n % 2 != 0):
        print('有趣!')
except ValueError:
    print('输入的必须是一个数字!')

3 . 提供一个字符串元组,程序要求元组中每一个元素的长度都在5~20 之间:否则, 程序引发异常。

temp_str = ('this is test', 'test the str', 'test')
for s in temp_str:
    if (len(s) < 5) or (len(s) > 20):
        raise ValueError('元组的每个元素长度必须在5~20之间')

4. 提示用户输入x1, y1, x2, y2, x3, y3 六个数值,分别代表三个点的坐标,程序判断这三个点是否在同一条直线上。要求: 使用异常处理机制处理用户输入的各种错误情况,如果三个点不在同一条直线上,则程序出现异常。

try:
    x1, y1, x2, y2, x3, y3 = input('请依次输入6个坐标点以空格隔开').split(' ')
    x1 = float(x1)
    y1 = float(y1)
    x2 = float(x2)
    y2 = float(y2)
    x3 = float(x3)
    y3 = float(y3)
    if x1 == 0 and x2 == 0 and x3 == 0:
        print('三个点在一条直线上')
    elif 0 in (x1, x2, x3):
        raise Exception('三个点不在同一直线上')
    elif y1 / x1 == y2 / x2 and y1 / x1 == y3 / x3:
        print('三个点在同一直线上')
    else:
        raise Exception('三个点不在同一直线上')
except ValueError:
    print('输入的坐标必须为数字!')

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值