资源简介 (共40张PPT)Python少儿编程第九章 一起捉bug目录1.1什么是bug1.2如何捉bug1.3主动抛出bug1.4自己也可以定义bugPART 01什么是bug语法错误1.1语法错误也称为解析错误,在使用PyCharm编写代码时,如果出现语法错误,会通过红色波浪线提示。常见的语法错误包括拼写错误、缩进错误等不符合Python语法规范的错误。例如,变量名使用数字开头,if语句后没有冒号,错误提示如图9-1所示。从图9-1中可以看出,“1name = '小蓝'”语句由于变量名使用数字开头,所以出现错误提示。“if age < 18”语句由于最后缺少冒号,也出现错误提示,此时,将鼠标放到错误提示位置,会给出错误原因或解决方法。异常1.2即使Python程序的语法是正确的,在运行时也有可能发生错误,这种在运行期间检测到的错误称为异常。Python的异常分为两种:一种是内置异常,在某些错误出现时会自动触发;另一种是用户自定义异常(详见9.4节),就是用户根据自己的需求设置的异常。常见的内置异常如表9-1所示。表9-1 Python中常见的内置异常异常1.2表9-1 Python中常见的内置异常(续)异常1.2大多数异常不会被程序自动处理,会以异常信息的形式进行显示。例如,执行“a = '2' + 3”语句,出现的异常信息如图9-2所示。图9-2 异常信息从图9-2可以看出,该语句抛出了TypeError异常,如果没有对该异常进行处理,程序就会使用所谓的回溯(Traceback,一种异常信息)终止执行,这些信息包括异常发生的行号、异常的名称(如TypeError)和原因等。PART 02如何捉bugtry-except语句2.1try-except语句用于捕获和处理异常,其语法格式如下。try:#可能会引发异常的代码块except exception [as e]:#出现异常后执行的代码块其中,exception为异常类名,[]为可选项,“as e”表示将异常类的实例对象命名为e。如果try子句中的代码块引发异常并被except子句捕获,就执行except子句中的代码块;如果try子句中的代码块没有引发异常,就继续执行try-except语句后面的代码;如果引发的异常没有被except子句捕获,程序将终止运行并输出异常信息。try-except语句2.1【例9-1】 捕获除数为0的异常。【问题分析】 在try子句中输入被除数和除数,然后进行除法运算,并输出商;except子句捕获ZeroDivisionError异常,并输出异常信息。【参考代码】try:a = float(input('请输入被除数:'))b = float(input('请输入除数:'))c = a / bprint('商为:', c)except ZeroDivisionError:print('除数不能为0!')try-except语句2.1【运行结果】 运行程序,输入被除数为2,除数为1,结果如图9-3所示;再次运行程序,输入被除数为2,除数为0,结果如图9-4所示。图9-3 例9-1程序运行结果1 图9-4 例9-1程序运行结果2【程序说明】 从运行结果可以看出,当除数为0时,程序引发ZeroDivisionError异常,此时,except子句捕获了这个异常并输出“除数不能为0!”。由于程序对异常进行了处理,所以没有出现终止运行并抛出异常的情况。try-except语句2.1也可通过异常类的实例对象直接输出异常信息。例如,将例9-1的except子句做如下修改。except ZeroDivisionError as e:print(e)再次运行例9-1,结果如图9-5所示。图9-5 例9-1程序修改后的运行结果多重except语句2.2在某些情况下,一个代码块可能引发多种异常,此时,可定义多个except子句,每个except子句捕获一种类型的异常,其语法格式如下。try:#可能会引发异常的代码块except exception1 [as e]:#处理异常类型1的代码块except exception2 [as e]:#处理异常类型2的代码块except exception3 [as e]:#处理异常类型3的代码块…当异常发生时,依次检查每一个except子句,并执行第一个异常类型匹配的代码块,其他的except子句将不再捕获,程序继续执行try-except语句后面的代码。多重except语句2.2【例9-2】 在例9-1的基础上,捕获参数类型不正确异常。【参考代码】try:a = float(input('请输入被除数:'))b = float(input('请输入除数:'))c = a / bprint('商为:', c)except ZeroDivisionError:print('除数不能为0!')except ValueError:print('被除数和除数应为数字类型!')多重except语句2.2【运行结果】 运行程序,输入被除数为2,除数为x,结果如图9-6所示。图9-6 例9-2程序运行结果【程序说明】 上述代码中,输入的除数为非数字类型,导致程序出现ValueError异常,并被第二个except子句捕获,所以输出“被除数和除数应为数字类型!”。如果没有第二个except子句,程序将由于没有处理新异常的语句而导致终止运行并抛出异常。try-except-else语句2.3try-except语句还有一个可选的else子句,如要使用该子句,须将其放在所有except子句后。else子句将在try子句没有发生任何异常时执行,其语法格式如下。try:#可能会引发异常的代码块except exception [as e]:#出现异常后执行的代码块else:#如果try子句中的代码没有引发异常,则执行该代码块try-except-else语句2.3【例9-3】 以只读方式打开文件,并统计文件中文本的行数,如果文件不存在则给出提示信息。【参考代码】fileName = 'birthday.txt'try:file = open(fileName, 'r')except FileNotFoundError:print(fileName, '文件不存在')else:print(fileName, '文件有', len(file.readlines()), '行')file.close()try-except-else语句2.3【运行结果】 运行程序,如果文件“birthday.txt”不存在,结果如图9-7所示;如果文件“birthday.txt”存在,且有6行文本,结果如图9-8所示。图9-7 例9-3程序运行结果1 图9-8 例9-3程序运行结果2try-except-finally语句2.4finally子句用于为异常处理提供一个统一的出口,无论try子句中的代码是否引发异常,都会执行该子句。通常,finally子句用于资源清理工作,如释放内存、关闭打开的文件、断开网络连接等,其语法格式如下。try:#可能会引发异常的代码块except exception [as e]:#出现异常后执行的代码块finally:#无论try子句中的代码是否引发异常,都会执行的代码块try-except-finally语句2.4【例9-4】 将输入的整数写入文件,要求无论是否捕获到异常,都会执行关闭文件的操作。【参考代码】fileName = 'integer.txt'try:file = open(fileName, 'a')data = int(input('请输入一个整数:'))file.write(str(data))except Exception as e:print(e)finally:print('关闭文件')file.close()try-except-finally语句2.4【运行结果】 运行程序,输入5,结果如图9-9所示;再次运行程序,输入9.6,结果如图9-10所示。图9-9 例9-4程序运行结果1 图9-10 例9-4程序运行结果2【程序说明】 从运行结果可以看出,输入整数5时,try子句中代码没有引发异常,会跳过except子句执行finally子句中的代码。输入浮点数9.6时,try子句中代码引发异常,则会先执行except子句中的代码,再执行finally子句中的代码。总之,无论如何finally子句中的代码都要执行。PART 03主动抛出bugraise语句3.1raise语句可抛出一个指定的异常,其语法格式如下。raise [exception[(message)]]其中,exception表示异常类名,message表示异常对象的描述信息,[]表示参数可选。使用raise语句抛出指定异常时,须使用try-except语句捕获抛出的异常,否则程序会终止,并显示异常信息。raise语句根据参数的不同有下面3种用法。raise语句3.1(1)exception和message都存在,在指定异常类型的同时,设置异常对象的描述信息。【例9-5】 创建通讯录。【问题分析】 try-except语句包含在循环中,try子句中使用len()函数检测号码是否为11位,使用isdigit()函数检测号码是否只包含数字,并分别使用raise语句抛出Exception异常,设置相应的异常信息,如果号码格式正确,则写入文件;except子句捕获异常并输出异常信息。raise语句3.1【参考代码】while True:try:name = input('请输入姓名:')phone = input('请输入手机号码:')if len(phone) != 11:raise Exception('手机号必须为11位。')if not phone.isdigit():raise Exception('手机号必须为数字。')with open('PhoneBook.txt', 'a') as file:file.write(name + '\t' + phone + '\n')except Exception as e:print('异常信息:', e)raise语句3.1【运行结果】 程序运行结果如图9-11所示。图9-11 例9-5程序运行结果【程序说明】 从运行结果可以看出,程序捕获了异常并输出了设置的异常信息,且程序没有终止运行,继续循环。raise语句3.1(2)message缺省,只指定异常类型。此时,捕获异常后无法输出异常信息。例如,基于例9-5,删除异常的描述信息,修改代码如下。if len(phone) != 11:raise Exception()if not phone.isdigit():raise Exception()再次运行例9-5,程序运行结果如图9-12所示。从图9-12可以看出,输入的手机号码格式不对时,程序虽然捕获到异常,但是无法输出异常信息。图9-12 message缺省时例9-5程序运行结果raise语句3.1(3)exception和message都缺省,只有一个单独的raise。此时,捕获到异常后,将重新引发它(传递异常)。例如,基于例9-5,在except子句的末尾添加raise语句,修改代码如下。except Exception as e:print('异常信息:', e)raiseraise语句3.1再次运行例9-5,程序运行结果如图9-13所示。图9-13 重新引发异常的运行结果从图9-13可以看出,输入的手机号码格式不对时,程序捕获到异常并输出了异常信息。由于在except子句中使用单独的raise语句重新引发了该异常,且没有捕获,所以程序终止运行并输出了异常信息。assert语句3.2assert语句又称为断言,它是对一个逻辑表达式进行检查,如果为False,就会触发AssertionError异常,其语法格式如下。assert expression [,message]assert后面紧跟逻辑表达式,message为一个字符串,当表达式的值为False时,作为异常类的描述信息使用。逻辑上等同于:if not expression:raise AssertionError(message)assert语句用于收集用户定义的约束条件,而不是捕获内在的程序设计错误。assert语句3.2【例9-6】 将百分制成绩转换成五级制成绩输出,使用assert语句判断输入的百分制成绩是否处于0~100。【参考代码】while True:try:score = int(input('请输入百分制成绩:'))#断言score处在0~100,如果不是抛出异常assert score >= 0 and score <= 100, '分数必须处于1~100'if score >= 90:print('优')assert语句3.2【参考代码】(续)elif score >= 80:print('良')elif score >= 70:print('中')elif score >= 60:print('及格')else:print('不及格')except Exception as e:print('异常信息:', e)break #跳出循环assert语句3.2【运行结果】 程序运行结果如图9-14所示。图9-14 例9-6程序运行结果【程序说明】 整个程序位于while循环内部,循环中通过try-except语句进行异常处理。在try子句中,通过键盘获取了int类型的数据score,然后断言score的值必须处于0~100。如果输入的数据不处于0~100,则会抛出AssertionError异常,从而执行except子句,输出提示信息并跳出循环,结束程序。PART 04自己也可以定义bug自己也可以定义bug4Python提供的内置异常可以描述大部分异常情况,但有时程序会有特殊的要求,系统可能无法识别该异常,此时,需要用户创建自定义异常类,使系统能够识别异常并进行处理。自定义异常类必须继承Exception类,通过__init__()方法初始化异常类对象,然后通过__str__()方法返回异常类对象说明信息。自定义异常类通过raise语句抛出,捕获异常后可直接通过异常对象输出说明信息。自己也可以定义bug4【例9-7】 体质指数(BMI)的计算公式为:BMI=体重/身高2,其中体重的单位为kg,身高的单位为m。编写程序,输入一个人的身高和体重,如果BMI小于18.5则输出“消瘦”,处于18.5~24(不含)则输出“正常”,处于24~28(不含)则输出“超重”,28及以上则输出“肥胖”。要求自定义异常类处理身高小于0.3 m、大于2.5 m的异常情况。【参考代码】import math #导入math模块class HeightException(Exception):def __init__(self, value):self.value = valuedef __str__(self):return '异常信息:身高应处于0.3~2.5,输入的身高是:{}'\.format(self.value)自己也可以定义bug4【参考代码】(续)def computeBMI():height = float(input('请输入身高:'))if height < 0.3 or height > 2.5:raise HeightException(height) #抛出异常weight = float(input('请输入体重:'))BMI = weight / math.pow(height, 2) #计算BMI指数if BMI < 18.5: #如果BMI小于18.5,输出“消瘦”print('消瘦');elif BMI < 24: #如果BMI小于24且大于等于18.5,输出“正常”print('正常');elif BMI < 28: #如果BMI小于28且大于等于24,输出“超重”print('正常');else: #如果BMI大于等于28,输出“肥胖”print('肥胖');自己也可以定义bug4【参考代码】(续)#异常处理try:computeBMI()except HeightException as e:print(e)except ValueError:print('输入的数据异常,请输入浮点数或整数!')自己也可以定义bug4【运行结果】 运行程序,当输入身高为1.8时,程序正常运行,结果如图9-15所示;当输入身高为3时,抛出异常,结果如图9-16所示。图9-15 例9-7程序运行结果1 图9-16 例9-7程序运行结果2【程序说明】 第2~6行定义了HeightException异常类继承Exception类,value表示实际输入的值。若用户输入的身高不符合规范时,就会抛出HeightException异常。感谢观看 展开更多...... 收起↑ 资源预览