在编写计算机程序时,通常能够区分正常和异常(不正常)情况。异常事件可能是错误(如试图除以零),也可能是通常不会发生的事情。Python使用异常对象来表示异常状态,并在遇到错误时引发异常。异常对象未被处理(或捕获)时,程序将终止并显示一条错误消息(traceback)。
#试图除以零的报错
print(1/0)
# Traceback (most recent call last):
# print(1/0)
# ZeroDivisionError: division by zero
正如你所见,出现问题是,自动引发异常。要引发异常,可使用raise语句,并将一个类(必须是Exception的子类)或者实例作为参数,将类作为参数时,将自动创建一个实例。
raise Exception
# Traceback (most recent call last):
# raise Exception
# Exception
raise Exception("error occurred ")
# Traceback (most recent call last):
# raise Exception("error occurred ")
# Exception: error occurred
在第一个示例(raise Exception)中,引发的时通常异常,并没有指出来出现了什么错误。在第二个示例中,添加了错误消息error occurred。 几乎所有的异常类都是由Exception派生出来的。
常见类名 | 描述 |
KeyboardInterrupt | 用户中断执行(通常是输入Ctrl+C) |
ArithmeticError | 引用属性或给它赋值失败时引发 |
ZeroDivisionError | 在除法或求模运算的第二个参数为零时引发 |
ImportError | 导入模块/对象失败 |
IndexError | 序列中没有此索引(index) |
TypeError | 将内置操作或函数用于类型不正确的对象时引发 |
-
捕获异常
在编写代码的时候,出现异常可以对其进行一定的处理,而在处理之前,我们通常要对其进行捕获,称之为 捕获异常 。可以使用try/except语句。(此时还是以ZeroDivisionError为例,演示如何捕获异常)
x = float(input("Enter the first number:")) #用户输入的内容为str型,需对其进行强转,int或者float均可
y = float(input("Enter the second number:"))
print(x/y)
# Traceback (most recent call last):
# print(x/y)
# ZeroDivisionError: float division by zero
print(x%y)
# Traceback (most recent call last):
# print(x%y)
# ZeroDivisionError: float modulo
这个程序运行正常,直到用户在第二个参数输入0,对于第二个参数输入值为0这种异常状态时,使用try/except进行捕获异常(这里打印一条对用户更友好的错误消息)。
try:
x = float(input("Enter the first number:"))
y = float(input("Enter the second number:"))
print(x/y)
except:
print("The sceond number can't be zero!")
"""
Enter the first number:1
Enter the second number:0
The sceond number can't be zero!
"""
或许使用if来判断y值好像简单许多,就本例而言,这可能也是更佳的解决方案,因为这个程序执行的除法运算越多,则每条除法运算都需要一条if进行判断,无疑增加其空间复杂度(O(n)),而使用try/except只需要一个错误处理程序。
发生除零行为时,如果启用了“抑制”功能,将返回None,换言之,如果启用“抑制”功能,将不应依赖返回值。关闭“抑制”功能时,捕获异常ZeroDivisionError
class MuffledCalculator:
muffled = False # 抑制
def calc(self,expr):
try:
return eval(expr)
except ZeroDivisionError:
if self.muffled:
print('Division by zero is illegal')
else:
raise
# eval() 函数用来执行一个字符串表达式,并返回表达式的值。
c = MuffledCalculator()
print(c.calc('10/2'))
# 5.0
print(c.calc('10/0')) #关闭抑制,报错
# ZeroDivisionError: division by zero
c.muffled = True
print(c.calc('10/0'))
# Division by zero is illegal
# None
如果无法处理异常,在except子句中使用不带参数的raise通常是不错的选择,有时你可能想引发别的异常,在这种情况下,导致进入except子句的异常将作为异常上下文储存起来,并出现在最终的错误消息中。
-
证明except在处理异常优于if
x = float(input("Enter the first number:"))
y = float(input("Enter the second number:"))
print(x/y)
"""
Enter the first number:10
Enter the second number:python
ValueError: could not convert string to float: 'python'
"""
对于这种情况,用户在第二个参数输入的为字符串或者其他类型的数据,此时使用if来判断还是最优的解吗?对于任何可能出现的异常进行判断和捕获。
try:
x = float(input("Enter the first number:"))
y = float(input("Enter the second number:"))
print(x/y)
except ZeroDivisionError:
print("The sceond number can't be zero!")
except TypeError:
print("Please change a data type")
except ValueError:
print("That wasn't a number,was it?")
仅当有异常时才会中断输入
while True:
try:
x = float(input("Enter the first number:"))
y = float(input("Enter the second number:"))
print(x / y)
except:
print("Invalid input,Please try again")
break
仅当没有引发异常时,才会跳出循环,只要出现错误,程序就会要求用户提供新的输入
while True:
try:
x = float(input("Enter the first number:"))
y = float(input("Enter the second number:"))
print(x / y)
except:
print("Invalid input,Please try again")
else:
break
"""
Enter the first number:a
Invalid input,Please try again
Enter the first number:1
Enter the second number:0
Invalid input,Please try again
Enter the first number:10
Enter the second number:2
5.0
"""
-
finally的用法
'''
try:
执行代码
except:
如果有异常发生,执行此处的代码
else:
如果没有异常发生,执行此处代码
finally:
不管有没有异常都会执行此处代码
'''
-
自定义异常类
自定义的异常类必须是Exception或者Error的子类!!!
class My_Exception(Exception):
'''
Custom exception types
'''
def __init__(self, parameter, para_value):
my_error = 'The parameter "{0}" is not legal:{1}'.format(parameter, para_value)
Exception.__init__(self, my_error)
self.parameter = parameter
self.para_value = para_value
对于warnings警告模块,最后结尾说两句:
import warnings
warnings.warn("I've got a bad feeling about this.")
# warnings.filters() 用于过滤警告
# warnings.warn 用于发出警告
-
小结:
- 异常对象:异常情况时用异常对象表示的。对于异常情况,有多种处理方式;如果忽略,将导致程序终止。
- 引发异常:可使用raise语句来引发异常,它将一个异常类或者异常实例作为参数,也可以使用excerpt同时判断多个异常情况(上面有示例)。如果在except子句中调用raise时没有提供任何参数,它将重新引发该子句捕获异常。
- 自定义的异常类:通过Exception派生出来的自定义异常类
-
捕获异常:要捕获异常,可在try语句中使用except子句,在except子句中,如果没有指定异常类,将捕获所有的异常。也可以指定多个异常类,将其放在 元组 中。
-
else子句:除except子句外,还可以使用else子句,在主try块没有引发异常时执行。
-
finally子句:确保代码块无论怎么样都可以执行异常,可以用try/finally,将代码块放在finally子句中。
-
警告:警告类似于异常,但是通常只打印一条错误消息,可以指定警告类别,因为它们是 Warning 的子类。
按照我的python版本找到了关于warning的文档。需要请参考!
Warning文档