从Scratch到Python 11 异常处理

在使用Scratch编程时,我们基本上不会遇到什么“错误”,除了极少数的情况(比如你调用了没有退出条件的递归函数),Scratch本身会出现问题之外,我们的程序不会说因为你写错了一点东西就停止运行,最多给你返回和预期不同的结果(比如,你非要让一个字符串和数字相加,Scratch只好忽略字符串)。毕竟Scratch面向的是刚刚开始学编程的孩子们,如果动不动就抛出一个错误,让程序停止运行,估计会让很多人放弃学习,这也是一种妥协的结果。

学了Python,大家的感觉就不同了,你发现Python的“脾气”没有Scratch那么好,你写错了一个函数的名字,Python会报告标识符未定义的错误;你少写了一个空格导致缩进问题,Python干脆不运行你的程序;你在运行的时候要把输入的汉字转换为数值,Python毫不客气地停止程序执行;你调用函数时参数写错了……总之,Python就像一位严格的老师,对约定的细节真是一丝不苟。

有的同学会感觉头疼,甚至觉得太难不想坚持下去。其实这是没有必要的。编程本身就是一件对逻辑要求非常严格的事情,绝不允许一丝一毫的马虎大意,这对我们思维的严密性、逻辑的严谨性都是很好的锻炼,只有迈过这个坎,你才真正走上了编程之路。

这一节,我们就来学习一下,如何应对编程中出现的各类错误。在Python中,这些错误统称为“异常”。

一、常见的异常

我们经常见到的异常可以分为两类,一类是语法的错误。如果你写错了,Python程序根本就不能执行。比如下面这段代码:

print('hello')
 print('world')

第二行代码之前多了一个空格,也就是有缩进的错误。运行结果是:

 

 

这个错误的最后一条信息是:

IndentationError: unexpected indent

翻译过来就是缩进错误的意思。你可以留意一下这类信息,慢慢熟悉了之后,一看就知道自己的程序出的是什么类型的问题。

第二类就不那么容易发现了:

a = int(input('请输入一个数字:'))
if a > 0:
    print('你输入的是正数')
else:
    pint('你输入的不是正数')

发现问题了吗?如果运行程序,输入一个正数,程序在控制台打印出“你输入的是正数”,完美!不过你如果输入的是0或负数,就会出错:

最后一行是:

NameError: name ‘pint’ is not defined

原来,你由于粗心把print()函数写成了pint(),Python并不在启动时检查这种错误,所以它还可以运行,甚至在某些情况下得到正确的结果。但在某些情况下程序要运行有问题的那部分代码时,就出错了。其实上面这段程序还隐藏着另一个问题:

这次我输入的不是数字,是字母“a”,Python报了下面的异常:

ValueError: invalid literal for int() with base 10: ‘a’

这个意思是“值错误:无效的十进制数’a’。原来,int函数要求你输入的内容必须是能转换为整数的数值,你输入的字母无法转换,参数无效,就出错了。

如何应对这些异常呢?首先你要会解读异常信息的提示。

二、异常信息解析

为了更好地说明异常信息,我们把上面的程序稍微改动一下,变成函数调用的形式:

def check_number():
    a = int(input('请输入一个数字:'))
    if a > 0:
        print('你输入的是正数')
    else:
        pint('你输入的不是正数')

check_number()

运行上面的代码,输入a,程序报出异常:

 

重点关注绿色框内的信息:

第一个绿色框内表示在文件“正数判断.py”这个Python文件中第9行check_number()时发生了错误,这个错误是怎么引发的呢?继续向下看,就看到原来还是同一个文件中的第三行输入数字引发的。如果第三行还调用了其它函数,Python还会再给出进一步的信息。总之,从第一个绿色框向下到第二个绿色框之间,反映的是出错代码的调用关系,你可以“顺藤摸瓜”找到出错的根源。

当然,从上面的截图可以看到,海龟编辑器提供了更友好的功能,直接把第三行代码标为红色,告诉你:错误就在这一行上。很多编辑器都有这种功能,但我们也要学会从异常信息中追根溯源。

第二个绿色框内,就是具体异常信息的提示了。“ValueError”表示参数无效错误,后面那句话说明具体是什么参数错误,刚才我们已经解释过了,你输入的字符“a”不能转换为十进制数字。

了解了异常信息的结构,我们再列出一些常见的异常:

异常名称 描述
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
IOError 输入/输出操作失败
OSError 操作系统错误
IndexError 序列中没有没有此索引(index)【越界】
KeyError 映射中没有这个键
NameError 未声明/初始化对象 (没有属性)
RuntimeError 一般的运行时错误
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
TypeError 对类型无效的操作
ValueError 传入无效的参数

上面列出的并不是全部的异常类型,这个类型也不需要记忆,只要了解一下,以后见得多了,也就熟悉了。如果遇到没见过的类型,可以在搜索引擎搜索异常类型的名字(如“ValueError”)即可。

三、基本的异常处理

编程中遇到异常,先不要着急,静下心来分析异常信息,定位到有问题的代码,一般可以解决,让程序正常运行。不过不管我们如何细致,总会有一些运行时才出现的异常,你根本无法预料让用户输入数字的时候,他会不会输入一个字符进来。这种情况下,我们就要分析程序运行时可能发生的已知或未知的错误,在程序在做出预防措施,这种预防措施就是异常捕获。

为了捕获并处理异常,Python提供了try…except语句:

try:
    <可能异常的语句>
except:
    <处理异常>

比如在上面的例子中,你预料用户有可能会输入一个不是数字的字符串导致程序异常,我们就可以使用try…except语句改写它(注意try和except后面的语句都需要缩进):

def check_number():
    try:
        a = int(input('请输入一个数字:'))
        if a > 0:
            print('你输入的是正数')
        else:
            print('你输入的不是正数')
    except:
        print('你输入的数字无效')
check_number()

这次,你输入错误的数字后,程序会友好地告诉你:你输入的数字无效,不会再抛出异常后中断程序了。需要注意的是,except后面的代码要小心,尽可能简单,别让except后的语句块再发生了异常,那程序还是会中止。

以上这种写法只是给我们提供了一种“优雅”地退出程序的方式,如果你要在用户输入无效数字的时候提示并让他重新输入,这就需要其它的逻辑来实现了,这里暂且不提。

四、异常处理的扩展写法

try…except语句还有两种扩展的写法,实现更完善的异常处理功能。

1、try…except…else:

try:
    <可能异常的语句>
except:
    <处理异常>
else:
    <语句块>

这个语句的意思是,如果try语句中的代码块没有发生任何异常,则会执行else语句中的代码块。

例如:

def check_number():
    try:
        a = int(input('请输入一个数字:'))
    except:
        print('你输入的数字无效')
    else:
        if a > 0:
            print('你输入的是正数')
        else:
            print('你输入的不是正数')
check_number()

2、try…except…finally

完整的异常处理语句还可以包括finally语句块,无论程序是否发生异常,finally中的代码块都会被执行。

try:
    <可能异常的语句>
except:
    <处理异常>
finally:
    <语句块>

例如:

def check_number():
    try:
        a = int(input('请输入一个数字:'))
        if a > 0:
            print('你输入的是正数')
        else:
            print('你输入的不是正数')
    except:
        print('你输入的数字无效')
    finally:
        print('函数执行结束')

check_number()

在这个例子中,我们是简单地在finally后加了一个信息提示。实际应用中,可能会用finally做一些清理工作。比如在代码中打开并处理文件时,为了防止发生异常时文件来不及关闭造成错误,我们就可以把关闭文件的代码写在finally中。

五、课后作业

编写程序,输入两个数字保存到x、y,将x、y转换为float类型并输出x/y的值。要求: 1、程序可能发生数据转换错误或被零除错误,如果发生异常,程序要能够给予提示; 2、无论是否发生异常,程序要在控制台输出“计算结束”。

给TA赞助
共{{data.count}}人
人已赞助
综合资讯

从Scratch到Python 10 Python中的“自制积木”

2023-6-4 16:00:06

综合资讯

从Scratch到Python 13 字典

2023-6-4 16:02:22

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索