零基础学Python--------第9章 异常处理及程序调试

第9章 异常处理及程序调试

9.1 异常概述

在程序运行过程当中,常常会遇到各类各样的错误,这些错误统称为“异常”。这些异常有的是因为开发者将关键字敲错致使的,这类错误多数产生的是SyntaxError:invalid syntax(无效的语法),这将直接致使程序不能运行。这类异常是显式的,在开发阶段很容易被发现。还有一类是隐式的,一般和使用者的操做有关。app

实例01:模拟幼儿园分苹果函数

def division():
    '''功能:分苹果'''
    print("\n=====================分苹果======================\n")
    apple = int(input("请输入苹果的个数:"))                         # 输入苹果的数量
    children = int(input("请输入来了几个小朋友:"))
    result = apple//children                                         # 计算每人分几个苹果
    remain = apple-result*children                                   # 计算余下几个苹果
    if remain>0:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个,剩下",remain,"个。")
    else:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个。")
if __name__ == '__main__':
    division()                                                       # 调用分苹果的函数

 

运行程序,当输入苹果和小朋友的数量都是10时:spa

请输入苹果的个数:10
请输入来了几个小朋友:10
10 个苹果,平均分给 10 个小朋友,每人分 1 个。

 

若是在输入数量时,不当心把小朋友的人数输成了0:3d

产生了ZeroDivisionError(除数为0错误)的根源在于算术表达式“10/0”中,0做为除数出现,因此正在执行的程序中被中断(第6行之后,包括第6行的代码都不会被执行)。调试

Python中还有不少异常。code

Python中常见的异常
异常 描述
NameError 尝试访问一个没有声明的变量引起的错误
IndexError 索引超出序列范围引起的错误
IndentationError 缩进错误
ValueError 传入错误
KeyError 请求一个不存在的字典关键字引起的错误
IOError 输入输出错误(如要读取的文件不存在)
ImportError 当import语句没法找到模块或from 没法在模块中找到相应的名称时引起的错误
AttributeError 尝试访问未知的对象属性引起的错误
TypeError 类型不合适引起的错误
MemoryError 内存不足
ZeroDivisionError 除数为0 引起的错误

9.2 异常处理语句

在程序开发时,有些错误并非每次运行都会出现。对象

下面将详细介绍Python中提供的异常处理语句。blog

9.2.1 try...eccept

在Python中,提供了try...except语句捕获并处理异常。在使用时,把可能产生异常的代码放在try 语句块中,把处理结果放在except 语句块中,这样,当try 语句块中的代码出现错误时,就会执行except语句块中的代码,若是try 语句块中的代码没有错误,那么except 语句块将不会执行。具体的语法格式以下:索引

try:
    block1    
except [ExceptionName [as alias]]:
    block2

 

参数说明:内存

  • block1:表示可能出现错误的代码块。
  • ExceptionName [as alias]:可选参数,用于指定要捕获的异常。其中,ExceptionName表示要捕获的异常名称,若是在其右侧加上as alias,则表示为当前的异常指定一个别名,经过该别名,能够记录异常的具体内容。

说明:在使用try...except语句捕获异常时,若是在except后面不指定异常名称,则表示捕获所有异常。

  • block2:表示进行异常处理的代码块。在这里能够输出固定的提示信息,也能够经过别名输出异常的具体内容。

说明:使用try...except语句捕获异常后,当程序出错时,输出错误信息后,程序会继续执行。

 实例02:模拟幼儿园分苹果(除数不能为0)

对“if __name__ =='__main__':”语句下面的代码进行修改,应用try...except语句捕获执行division()函数可能抛出的ZeroDivisionError(除数为零)异常,修改后的代码以下:

def division():
    '''功能:分苹果'''
    print("\n=====================分苹果======================\n")
    apple = int(input("请输入苹果的个数:"))                         # 输入苹果的数量
    children = int(input("请输入来了几个小朋友:"))
    result = apple//children                                         # 计算每人分几个苹果
    remain = apple-result*children                                   # 计算余下几个苹果
    if remain>0:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个,剩下",remain,"个。")
    else:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个。")
if __name__ == '__main__':
    try:                                                                 # 捕获异常
        division()                                                       # 调用分苹果的函数
    except ZeroDivisionError:                                            # 处理异常
        print("\n出错了 ~_~ ——苹果不能被0个小朋友分!")

 

执行以上的代码,输入苹果的数量为10,小朋友的人数为0时,将再也不抛出异常:

目前,咱们只处理了除数为0的状况,若是将苹果和小朋友的数量输入成小数或者不是数字会是什么结果呢?

能够看出,程序中要求输入整数,而实际输入的是小数,则抛出ValueError(传入的值错误)异常。要解决该问题,能够在实例02的代码中,为try...except语句再添加一个except语句,用于处理抛出ValueError异常的状况。修改后的代码以下:

def division():
    '''功能:分苹果'''
    print("\n=====================分苹果======================\n")
    apple = int(input("请输入苹果的个数:"))                         # 输入苹果的数量
    children = int(input("请输入来了几个小朋友:"))
    result = apple//children                                         # 计算每人分几个苹果
    remain = apple-result*children                                   # 计算余下几个苹果
    if remain>0:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个,剩下",remain,"个。")
    else:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个。")
if __name__ == '__main__':
    try:                                                                 # 捕获异常
        division()                                                       # 调用分苹果的函数
    except ZeroDivisionError:                                            # 处理异常
        print("\n出错了 ~_~ ——苹果不能被0个小朋友分!")
    except ValueError as e:                                              # 处理ValueError异常
        print("输入错误:",e)                                             # 输出错误缘由

 

再次运行程序:

多学两招:

在捕获异常时,若是须要同时处理多个异常也能够采用下面的代码实现:

try:                                                                 # 捕获异常
        division()                                                       # 调用分苹果的函数
    except (ZeroDivisionError,ValueError) as e:                          # 处理异常
        print("输入错误:",e)                                            # 输出错误缘由

 

即在except语句后面使用一对小括号将可能出现的异常名称括起来,多个异常名称之间使用逗号分隔。若是想要显示具体的出错缘由,那么再加上as指定一个别名。

9.2.2 try...except...else 语句

在Python中国,还有另外一种异常处理结构,它是try...except...else语句,也就是在原来try...except语句的基础上再添加一个else子句,用于指定当try语句块中没有发现异常时要执行的语句块。该语句块中的内容当try语句中发现异常,将不被执行。例如,实例02进行修改,实现当division()函数被执行后没有抛出异常时,输出文字“分苹果顺利完成...”。修改后的代码以下:

def division():
    '''功能:分苹果'''
    print("\n=====================分苹果======================\n")
    apple = int(input("请输入苹果的个数:"))                         # 输入苹果的数量
    children = int(input("请输入来了几个小朋友:"))
    result = apple//children                                         # 计算每人分几个苹果
    remain = apple-result*children                                   # 计算余下几个苹果
    if remain>0:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个,剩下",remain,"个。")
    else:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个。")
if __name__ == '__main__':
    try:                                                                 # 捕获异常
        division()                                                       # 调用分苹果的函数
    except ZeroDivisionError                  :                          # 处理异常
        print("\n出错了 ~_~ ——苹果不能被0个小朋友分!")
    except ValueError as e:                                              # 处理ValueError异常
        print("输入错误:",e)                                            # 输出错误缘由
    else:                                                                # 没有抛出异常时执行
        print("分苹果顺利完成...")

 

执行以上代码:

9.2.3 try...except...finally 语句

完整的异常处理语句应该包含finally 代码块,一般状况下,不管程序中有无异常产生,finally 代码块中的代码都会被执行,其语法格式以下:

try:
    block1
except [ExceptionName [as alias]]:
    block2
fianlly:
    block3

 

对于try...except...finally 语句的理解并不复杂,它只是比try...except 语句多了一个finally 语句,若是程序中有一些在任何情形中都必须执行的代码,那么就能够将它们放在finally 代码块中。

说明:使用except 子句是为了容许处理异常。不管是否引发了异常,使用finally 子句都是能够执行清理代码。若是分配了有限的资源(如打开文件),则应将释放这些资源的代码放置在finally 代码块中。

例如,在对实例02进行修改,实现当division() 函数在执行时不管是否抛出异常,都输出文字“进行了一次分苹果操做”。修改后的代码以下:

def division():
    '''功能:分苹果'''
    print("\n=====================分苹果======================\n")
    apple = int(input("请输入苹果的个数:"))                         # 输入苹果的数量
    children = int(input("请输入来了几个小朋友:"))
    result = apple//children                                         # 计算每人分几个苹果
    remain = apple-result*children                                   # 计算余下几个苹果
    if remain>0:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个,剩下",remain,"个。")
    else:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个。")
if __name__ == '__main__':
    try:                                                                 # 捕获异常
        division()                                                       # 调用分苹果的函数
    except ZeroDivisionError                  :                          # 处理异常
        print("\n出错了 ~_~ ——苹果不能被0个小朋友分!")
    except ValueError as e:                                              # 处理ValueError异常
        print("输入错误:",e)                                            # 输出错误缘由
    else:                                                                # 没有抛出异常时执行
        print("分苹果顺利完成...")
    finally:                                                             # 不管是否抛出异常都执行
        print("进行了一次分苹果操做。")

 

执行程序:

至此,已经介绍了异常处理语句的try....except、try...except...else 和 try...except...finally 等形式。

异常处理语句的不一样子句的执行关系

9.2.4 使用raise 语句抛出异常

若是某个函数或方法可能会产生异常,但不想在当前函数或方法中处理这个异常,则可使用raise 语句在函数或方法中抛出异常。raise 语句的语法格式以下:

raise [ExceptionName[(reason)]]

 

其中,ExceptionName[(reason)]为可选参数,用于指定抛出的异常名称以及异常信息的相关描述。若是省略,就会把当前的错误原样抛出。

说明:ExceptionName[(reason)]参数中的“(reason)”也能够省略,若是省略,则在抛出异常时,不附带任何描述信息。

例如,修改实例02,加入限制苹果数量必须大于或等于小朋友的数量,从而保证每一个小朋友都能至少分到一个苹果。

实例03:模拟幼儿园分苹果(每一个人至少分到一个苹果)

在第5行代码“children = int(input("请输入来了几个小朋友:"))”的下方添加一个if 语句,实现当苹果的数量小于小朋友的数量时,应用raise 语句抛出一个ValueError 异常,接下来再在最后一行语句的下方添加except 语句处理ValueError 异常。

def division():
    '''功能:分苹果'''
    print("\n=====================分苹果======================\n")
    apple = int(input("请输入苹果的个数:"))                         # 输入苹果的数量
    children = int(input("请输入来了几个小朋友:"))
    if apple < children:
        raise ValueError("苹果太少了,不够分...")
    result = apple//children                                         # 计算每人分几个苹果
    remain = apple - result*children                                   # 计算余下几个苹果
    if remain>0:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个,剩下",remain,"个。")
    else:
        print(apple,"个苹果,平均分给",children,"个小朋友,每人分",result,"个。")
if __name__ == '__main__':
    try:                                                                 # 捕获异常
        division()                                                       # 调用分苹果的函数
    except ZeroDivisionError                  :                          # 处理ZeroDivisionError异常
        print("\n出错了 ~_~ ——苹果不能被0个小朋友分!")
    except ValueError as e:                                              # ValueError
        print("\n出错了~_~ ——",e)

 

执行程序:

说明:在应用raise 抛出异常时,要尽可能选择合理的异常对象,而不该该抛出一个与实际内容不相关的异常。流入,在实例03中,想要处理的是一个和值有关的异常,这时就不该该抛出一个IndentationError异常。

9.3 程序调试

相关文章
相关标签/搜索