python除数为零的异常_"卧槽,怎么会这样"——Python异常

编写程序的时候,程序员通常需要辨别事件的异常(非正常)情况,这类异常事件可能是程序本身的设计错误,也可能是外界环境发生了变化。为了处理这些情况,Python提供了功能强大的异常处理机制。

1.异常简介

在Python中,程序在执行过程中产生的错误称为异常,如列表索引越界、打开不存在的文件等。例如,运行下面代码程序会发生错误。

print(a)

open("123.txt","r")

运行产生如下错误信息:

NameError: name 'a' is not defined

FileNotFoundError: [Errno 2] No such file or directory: '123.txt'

由上述信息可知,程序产生了两个异常。其中,第1个异常的类型为NameError(名称),描述信息为a没有定义;第2个异常为FileNotFoundError,描述信息为没有找到123.txt文件。在程序中遇到这些问题,如果没有进行任何处理,程序就会终止。

2.异常类

在Python中,所有异常都是Exception的子类。Exception类定义在exceptions模块中,该模块在Python的内建命名空间中,我们不必导入就可以直接使用。

在前面,每次执行程序遇到错误的时候,程序就会引发异常。如果这个异常对象没有进行处理和捕捉,程序就会用所谓的回溯(traceback,一种错误信息)终止执行,这些信息包括错误的名称(如NameError)、原因和错误发生的行号。

下面来列举几个比较常见的异常。

2.1 NameError

尝试当问一个未声明的变量,会引发NameError。例如:

print(foo)

错误信息如下:

Traceback (most recent call last):

File "C:\Users\dell\Desktop\zh.py", line 1, in

print(foo)

NameError: name 'foo' is not defined

上述信息表明,解释器在任何命名空间里面都没找到foo。

2.2 ZeroDivisionError

当除数为零的时候,会引发ZeroDivisionError异常。例如:

1/0

错误信息如下:

Traceback (most recent call last):

File "C:\Users\dell\Desktop\zh.py", line 1, in

1/0

ZeroDivisionError: division by zero

事实上,任何数值被零除都会导致上述异常。

2.3 SyntaxError

当解释器发现语法错误时,会引发SyntaxError异常。例如:

list = ["a","b","c"]

for i in list

print(1)

在上述示例中,由于for循环的后面缺少冒号,所以导致程序出现如下错误信息:

File "C:\Users\dell\Desktop\zh.py", line 2

for i in list

^

SyntaxError: invalid syntax

SyntaxError异常是为已不在运行时发生的异常,它代表着Python代码中有一个不正确的结构,使得程序无法执行。这些错误一般是在编译时发生,解释器无法把脚本转换为字节代码。

2.4 IndexError

当使用程序中不存在的索引时,会发生IndexError异常。例如:

list = []

list[0]

在上述示例中,list列表中没有任何元素,使用索引0访问列表首位元素时,出现如下错误信息:

Traceback (most recent call last):

File "C:\Users\dell\Desktop\zh.py", line 2, in

list[0]

IndexError: list index out of range

上述信息表明,列表的索引值超出了列表的范围。

2.5 KeyError

当使用映射中不存在的键时,会引发KeyError异常。例如。

myDict = {"host":"earth","port":80}

myDict["server"]

上述示例中,myDict字典中只有host和port两个键,获取server键对应的值时,出现如下错误信息:

Traceback (most recent call last):

File "C:\Users\dell\Desktop\zh.py", line 2, in

myDict["server"]

KeyError: 'server'

上述信息表明,出现了字典中没有的键server。

2.6 FileNotFoundError

试图打开不存在的文件时,会引发FileNotFoundError(Python3.2以前是IOError)异常。

例如:

f = open("test")

上述示例中,使用open方法打开名为test的文件或目录,出现如下错误信息:

Traceback (most recent call last):

File "C:\Users\dell\Desktop\zh.py", line 1, in

f = open("test")

FileNotFoundError: [Errno 2] No such file or directory: 'test'

2.7 AttributeError

当尝试访问未知的对象属性时,会引发AttributeError异常。例如:

class Car(object):

pass

car = Car()

car.color = "黑色"

print(car.color)

print(car.name)

上述示例中,Car类没有定义任何属性和方法,在创建Car类的实例以后,动态地给car引用的实例添加了color属性,然后访问它的color和name属性时,出现如下错误信息:

Traceback (most recent call last):

File "C:\Users\dell\Desktop\zh.py", line 6, in

print(car.name)

AttributeError: 'Car' object has no attribute 'name'

上述信息表明,在Car的实例中定义了color属性,所以可以使用car.color的方式访问;但是没有定义name属性,所以访问name属性时就会出现错误。

3.异常处理

Python处理异常的能力非常强大,它可以准确地反馈错误信息,帮助开发人员准确定位到问题发生的位置和原因。Python中使用try-except语句处理异常。其中,try语句用于检测异常,except语句用于捕获异常。

3.1 捕获简单异常

try-except语句定义了监控异常的一段代码,并且提供了处理异常的机制。最简单的try-except语句格式如下:

try:

#语句块

except:

#异常处理代码

当try里面的某条语句出现错误的时候,程序就不再继续执行try中的语句,而是直接执行except里面处理异常的语句。接下来,通过一张示意图来描述简单的异常。

为了更好的理解,接下来通过一个案例演示如何使用简单的try-except语句,试图捕获两个数相除可能产生的异常。

try:

print("-" * 20)

num1 = input("请输入第1个数:")

num2 = input("请输入第2个数:")

print(int(num1) / int(num2))

print("-" * 20)

except ZeroDivisionError:

print("第2个数不能为0")

在try子句的input函数中接受用户输入的两个数值,其中第一个数值作为被除数,另一个数值作为除数。如果发生除数为0的情况,程序会发出ZeroDivisionError异常,此时,except子句就会捕获到这个异常,并将异常信息打印出来。

运行程序,在控制台输入第1个数为20,第2个数为5,结果如图所示。

再次运行程序,在控制台输入第1个数为20,第二个数为0,结果如图。

从两次运行的结果可以看出,程序产生异常时不会再出现终止程序的情况了,而是按照自己设定的消息提醒用户。注意的是,只要监控到错误,程序就会执行except里面的语句,并且不再执行try里面未执行的语句。

3.2 捕获多个异常

在运行上面的代码时,如果输入的为非数字类型的值,就会产生另外一个数值错误的异常,具体错误信息如下:

Traceback (most recent call last):

File "C:\Users\dell\Desktop\zh.py", line 5, in

print(int(num1) / int(num2))

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

上述错误信息表明,由于输入了一个无效的参数,导致程序出现ValueError异常。之所以出现上述问题,原因在于except语句只能捕获ZeroDivisionError异常,程序没有处理新的异常而终止运行。为了让程序能检测到ValueError异常,可以再增加一个处理该异常的except语句。此时,需要用到处理多个异常的try-except语句,其语法格式如下。

try:

#语句块

except 异常名称1:

#异常处理代码1

except 异常名称2:

#异常处理代码2

...

当发现try里面的语句出现错误时,会根据出现异常的类型选择执行except语句。接下来,通过一张图描述多个except子句的情况。

为了更好的理解,在上面代码的基础上添加了ValueError异常部分。

try:

print("-" * 20)

num1 = input("请输入第1个数:")

num2 = input("请输入第2个数:")

print(int(num1) / int(num2))

print("-" * 20)

except ZeroDivisionError:

print("第2个数不能为0")

except ValueError:

print("只能输入数字")

运行程序,在控制台输入第1个数为20,第2个数为b,结果如图。

如果一个except子句想要捕捉多个异常,并且使用同一种处理方式,Python 2中可以在except的后面使用逗号连接多个异常名称;在Python 3中必须使用元组来表示。

Python 2 中:

except NameError,FileNotFoundError:

Python 3中:

except (NameError,FileNotFoundError):

3.3 捕获异常的描述信息

通过一个except子句可以捕捉多个异常。把上面代码的两个错误合并到一个except子句中,具体如下。

try:

print("-" * 20)

num1 = input("请输入第1个数:")

num2 = input("请输入第2个数:")

print(int(num1) / int(num2))

print("-" * 20)

except (ZeroDivisionError,ValueError):

print("捕捉到异常")

此时,无论出现上述两种异常的任意一种,都会打印except里面的语句。但是,只打印一个错误信息并没有什么帮助。为了区分不同的错误信息,可以使用as获取系统反馈的错误信息,如下所示。

try:

print("-" * 20)

num1 = input("请输入第1个数:")

num2 = input("请输入第2个数:")

print(int(num1) / int(num2))

print("-" * 20)

#获取描述信息

except (ZeroDivisionError,ValueError) as result:

print("捕捉到异常:%s"%result)

当监控到ZeroDivisionError或者ValueError这两种异常中的任意一个时,就会把描述信息保存到result变量中。

运行程序,在控制台输入第1个数为20,第2个数为b,如图所示:

再次运行程序,在控制台输入第1个数为20,第2个数为0,如图所示:

从两次结果可以看出,一个except子句同样能表达多种异常信息。

3.4 捕获所有异常

即使程序能够处理多个异常,但是防不胜防,很可能有些异常还是没有捕捉到。在上面代码中,如果在编写程序时把num1写成nmn1,又会得到类似于下面的错误信息。

Traceback (most recent call last):

File "C:\Users\dell\Desktop\zh.py", line 5, in

print(int(nmn1) / int(num2))

NameError: name 'nmn1' is not defined

上述这样的情况,可以在原有的基础上捕捉SyntaxError异常。如果程序出现几十个错误,就要增加捕捉这些异常,显得非常繁琐。为了解决这种情况,可以在except子句中不指明异常类型,这样它就可以更好地理解,接下来在上面代码的基础上增加捕捉所有异常的功能,如下面所示:

#捕捉所有的异常

try:

num1 = input("请输入第1个数:")

num2 = input("请输入第2个数:")

print(int(num1) / int(num2))

except:

print("出现错误了")

在上面代码中,except语句没有标注异常的类型,在该语句中统一处理了程序可能会出现的所有错误。

运行程序,在控制台中输入第1个数为20,第2个数为b,如图所示。

再次运行程序,在控制台输入第1个数为20,第2个数为0,如图所示。

从两次运行结果可以看出,所有异常的提示信息都一样。还有一种捕捉所有异常的方法,就是在except语句后使用Exception类。由于Exception类是所有异常类的父类,因此可以将所有的异常进行捕获。接下来我们把上面代码的异常替换为Exception,如下所示。

try:

num1 = input("请输入第1个数:")

num2 = input("请输入第2个数:")

print(int(num1) / int(num2))

except Exception as result:

print("捕捉到异常:%s"%result)

在上面代码中,except语句定义了一个Exception的对象result,用于接收异常处理对象。打印result可以输出异常信息,因为程序已经捕获到异常信息,所以不会再出现因为异常而退出的情况。

运行程序,在控制台 输入第1个数为20,第2个数为b,如图所示。

再次运行程序,在控制台输入第一个数为20,第二个数为0,如图所示。

从两次结果可以看出,使用Exception同样捕捉到了所有异常,以及获取了它们的描述信息。

既然上面两种方式都能捕捉到所有异常,那么如果同时使用这两个语句,程序会执行那个呢?接下来,在上面代码的基础上,再增加一个没有标注异常类型的except子句,如图所示。

try:

num1 = input("请输入第1个数:")

num2 = input("请输入第2个数:")

print(int(num1) / int(num2))

except:

print("出现错误了")

except Exception as result:

print("捕捉到异常:%s"%result)

程序运行后,出现如下错误信息。

上述错误信息表明,默认什么都不写的except语句必须位于语句的最后面。把第5~6行移到末尾,再次运行结果和之前运行结果是一样的。

通常情况下,如果获取所有的异常以后按照同一种方式处理,显然是不合理的,所以在程序中几乎不会使用到。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值