《疯狂Python讲义》之异常处理

异常概述

异常机制已经成为衡量一门编程语言是否成熟的标准之一,使用异常处理机制的Python程序有更好的容错性,更加健康。

异常处理机制

Python的异常处理机制可以让程序具有极好的容错性。

使用try…except捕获异常

语法结构如下:

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

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

异常类的继承体系

Python的所有异常类的基类是BaseException,但如果用户要实现自定义异常,应该继承Exception。

BaseException的主要子类就是Exception,不管是系统的异常类,还是用户自定义的异常类,都应该从Exception派生。

import sys
try:
    a = int(sys.argv[1])
    b = int(sys.argv[2])
    c = a / b
    print("您输入的两个数相除的结果是:", c )
except IndexError:
    print("索引错误:运行程序时输入的参数个数不够")
except ValueError:
    print("数值错误:程序只能接收整数参数")
except ArithmeticError:
    print("算术错误")
except Exception:
    print("未知异常")

实际编程时一定要记住:先捕获小异常,再捕获大异常!

多异常捕获

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

import sys
try:
    a = int(sys.argv[1])
    b = int(sys.argv[2])
    c = a / b
    print("您输入的两个数相除的结果是:", c )
except (IndexError, ValueError, ArithmeticError):
    print("程序发生了数组越界、数字格式异常、算术异常之一")
except:
    print("未知异常")
else块

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

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

使用finally回收资源

为了保证一定能回收在try块中打开的资源,异常处理机制提供了finally块,不管try块中的代码是否出现异常,也不管哪一个except块被执行,甚至在try块或except块中执行了return语句,finally块总会被执行。Python完整的异常处理语法结构如下:

try:
    业务实现代码
except SubException as e:
    异常处理块1
except SubException2 as e:
    异常处理块2
...
else:
    正常处理块
finally:
    资源回收块
异常处理嵌套

在try块、except块、finally块中包含一个完整的异常处理流程的情形称为异常处理嵌套。

使用raise引发异常

引发异常

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

  • raise:单独一个raise。该语句引发当前上下文中捕获的异常或默认引发runtimeError异常
  • raise异常类:raise后带一个异常类。该语句引发指定异常类的默认实例
  • raise异常对象:引发指定的异常对象
自定义异常类

用户自定义异常都应该继承Exception基类或Exception子类,在自定义异常类时只需要指定自定义异常类的父类即可

except和raise同时使用

在异常出现的当前方法中,程序只对异常进行部分处理,还有些处理需要在该方法的调用中才能完成,所以应该再次引发异常,让该方法的调用者也能捕获到异常。为了实现这种通过多个方法协作处理同一个异常的情形,可以在except块中结合raise语句来完成。

这种except和raise结合使用的情况再实际应用中非常常用。实际应该对异常处理通常分为两个部分:1、应用后台需要通过日志来记录异常发生的详细情况;2、应用还需要根据异常向应用使用者传达某种提示。

raise不需要参数

使用raise语句时可以不带参数,此时raise语句处于except块中,它将会自动引发当前上下文激活的异常;否则,通常默认引发runtimeError异常

Python的异常传播轨迹

Python专门提供了traceback模块来处理异常传播轨迹,导入traceback模块之后,提供了如下两个常用方法。

  • traceback.print_exc():将异常传播轨迹信息输出到控制台或指定文件中
  • format_exc():将异常传播轨迹信息转换成字符串

异常处理规则

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

  • 使程序代码混乱最小化
  • 捕获并且保留诊断信息
  • 通知合适的人员
  • 采用合适的方式结束异常活动
不要过度使用异常

过度使用异常主要表现在两个方面:

  • 把异常和普通错误混淆在一起,不再编写任何错误处理代码,而是以简单地引发异常来代替所有的错误处理
  • 使用异常处理来代替流程控制
不要使用过于庞大的try块

try块里的代码过于庞大,业务过于复杂,就会造成try块中出现异常的可能性大大增加,从而导致分析异常原因的难度也大大增加。

不要忽略捕获到的异常

不要忽略异常!既然已捕获到异常,那么except块理应做处理并修复异常。

  • 处理异常
  • 重新引发新异常
  • 在合适的层处理异常

练习题

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

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

except ValueError:
    print("请输入正整数!")
finally:
    print("最终的结果列表是:%s" % num_list)

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

n = input("请输入一个整数:")
try:
    num = int(n)
    while (num >= 0):
        if num % 2 != 0:
            print("有趣")
        elif num % 2 == 0 and num >= 2 and num <= 5:
            print("没意思")
        elif num % 2 == 0 and num >= 2 and num <= 5:
            print("有趣1")
        else:
            print("没意思1")
    else:
        print("不能输入负数")
except ValueError:
    print("请输入整数!")

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

str = ("Python语言学习","疯狂Python学习","学习","23")
for i in str:
    if len(i)>=5 and len(i)<=20:
        print(i)
    else:
        print("元素:'%s' 长度必须在5~20之间!" % i)

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('输入的坐标必须为数字!')
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值