异常
异常处理机制
python使用异常对象来表示异常状态,并在遇到错误时引发异常。异常对象没有被处理(或捕获)时程序将终止并显示一条错误现象(traceback)
raise语句
要引发异常,可使用raise语句,并且将一个类(必须是Exception的子类)或实例作为参数。
>>>raise Exception
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
raise Exception
Exception
>>>raise Exception('hyperdrive overload')
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
raise Exception('hyperdrive overload')
Exception: hyperdrive overload
注:添加了错误消息“hyperdrive overload”
内置的异常类:
Exception:几乎所有的异常类都是从它派生而来的
AttributeError:引用属性或给它赋值失败时引发
OSError:操作系统不能执行指定的任务(如打开文件)时引发,有多个子类
IndexError:使用序列中不存在的索引时引发,为LookupError的子类
KeyError:使用映射中不存在的键时引发,为LookupError的子类
NameError:找不到名称(变量)时引发
SyntaxError:代码不正确时引发
TypeError:将内置操作或者函数用于类型不正确的对象时引发
ValueError:将内置操作或者函数用于这样的对象时引发:其类型正确但包含的值不合适
ZeroDivisionError:在除法或求模运算的第二个参数为零时引发
自定义异常类:
class somecustomException(Exception) :pass
捕获异常:对异常进行处理;可使用try、except语句
x=int(input("enter the first number: "))
y=int(input("enter the second number: "))
print(x/y)
当第二个数输入为0时,会出现异常:
Traceback (most recent call last):
File "C:UsersAdministratorDesktopp.py", line 3, in <module>
print(x/y)
ZeroDivisionError: division by zero
要捕获这种异常并对错误进行处理,可这样写:
try:
x=int(input("enter the first number: "))
y=int(input("enter the second number: "))
print(x/y)
except ZeroDivisionError:
print("the seconf number can't be zero!")
不提供任何参数
捕获异常后,如果要重新引发它即继续向上传播,可调用raise且不提供任何参数(也可显式的提供捕获到的异常)
“抑制”异常:如果启用这种功能,将打印一条错误消息,而不让异常继续传播,在与用户交互的会话中,抑制异常很有用,但在程序内部使用时,引发异常时更佳的选择。
class MuffledCalcultor:
muffled = False
def calc(self,expr):
try:
return eval(expr)
except ZeroDivisionError:
if self.muffled:
print("Division by zero is illegal")
else:
raise
>>>calculator = MuffledCalcultor()
>>>calculator.calc("10 / 2") --->5.0
>>>calculator.calc("10 / 0") #关闭了抑制功能
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
calculator.calc("10 / 0")
File "C:UsersAdministratorDesktopp.py", line 5, in calc
return eval(expr)
File "<string>", line 1, in <module>
ZeroDivisionError: division by zero
注:关闭了抑制功能时,捕获了异常ZeroDivisionError,但继续向上传播
如果无法处理异常,可以在except子句中使用不带参数的raise。有时可能想引发别的异常,在这种情况下,导致进入except子句的异常将被作为异常上下文储存起来,并出现在最终的错误消息中。
try:
1/0
except ZeroDivisionError:
raise ValueError
运行结果:
Traceback (most recent call last):
File "C:UsersAdministratorDesktopp.py", line 2, in <module>
1/0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:UsersAdministratorDesktopp.py", line 4, in <module>
raise ValueError
ValueError
在处理上述异常时,引发了另一个异常:ValueError
可以使用raise......from......语句来提供自己的异常上下文,也可使用None来禁用上下文:
try:
1/0
except ZeroDivisionError:
raise ValueError from None
运行结果:
Traceback (most recent call last):
File "C:UsersAdministratorDesktopp.py", line 4, in <module>
raise ValueError from None
ValueError
多个except子句
try:
x=int(input("enter the first number: "))
y=int(input("enter the second number: "))
print(x/y)
except ZeroDivisionError:
print("the second number can't be zero!")
except TypeError:
print("that wasn't a number,was is?")
except ValueError:
print("that wasn't a empty")
若要使用一个except子句捕获多个异常,可在一个元组中指定这些异常:
try:
x=int(input("enter the first number: "))
y=int(input("enter the second number: "))
print(x/y)
except (ZeroDivisionError,TypeError,ValueError):
print("wasn't a number or wasn't a empty or the second number can't be zero")
捕获对象:
要在except子句中访问异常对象本身,可使用两个而不是一个参数(注意:即便是在捕获多个异常时,也只向except提供了一个参数--一个元组)。需要让程序继续运行并记录错误时很有用。
try:
x=int(input("enter the first number: "))
y=int(input("enter the second number: "))
print(x/y)
except (ZeroDivisionError,TypeError,ValueError) as err:
print(err)
注:打印了发生的异常并继续运行
该例中,except捕获了3中异常,但同时显式的捕获了异常对象本身,因此可将其打印出来,让用户知道发生了什么情况。
若还有其它异常没有被try、except捕获,只需要在except语句中不指定任何异常类即可:
try:
x=int(input("enter the first number: "))
y=int(input("enter the second number: "))
print(x/y)
except ZeroDivisionError:
print("the second number can't be zero!")
except TypeError:
print("that wasn't a number,was is?")
except:
print("something wrong happend ...")
在try、except语句中添加else子句:
while True:
try:
x=int(input("enter the first number: "))
y=int(input("enter the second number: "))
value = x / y
print("x/y is: ",value)
except:
print("invalid input,please try again")
else:
break
注:仅当没有引发异常时,才会跳出循环(是有else子句中的break语句实现的)。只要出现错误,程序就会要求用户重新输入。
打印出异常的错误信息:
while True:
try:
x=int(input("enter the first number: "))
y=int(input("enter the second number: "))
value = x / y
print("x/y is: ",value)
except Exception as err:
print("invalid input: ",err)
print("please try again")
else:
break
finally:finally子句,用于在发生异常时执行清理工作,这个子句是与try子句配套的
x=None
try:
x=3/0
finally:
print("cleaning up ...")
del x
运行结果:(在执行清理工作后崩溃了)
Traceback (most recent call last):
File "C:UsersAdministratorDesktopppppppp.py", line 3, in <module>
x=3/0
ZeroDivisionError: division by zero
注:不管try子句中发生什么异常,都将执行finally子句。在try子句前给x赋值,若不这样做,ZeroDivisionError将导致根本没有机会给它赋值,进而导致在finally子句中对其执行的del语句时引发没有捕获的异常。
同时包含try、except、finally和else(或其中3个)
try:
1/0
except NameError:
print("unknown variable")
else:
print("that went well")
finally:
print("cleaning up ...")
运行结果:
cleaning up ...
Traceback (most recent call last):
File "C:UsersAdministratorDesktopppppppp.py", line 2, in <module>
20/0
ZeroDivisionError: division by zero
注:没有出现异常才会执行else后面的语句
异常之禅:
如果知道代码可能引发某种异常,且不希望出现这种异常时程序终止并显示栈跟踪信息,可添加必要的try/except或try/finally来处理。
def describe_person(person):
print("description of",person['name'])
print("age: ",person['age'])
if "occupation" in person:
print('occupation: ',person['occupation'])
创建一个包含姓名和age的字典,该函数再调用它:
>>>per={}
>>>per["name"]="webadmin"
>>>per["age"]=42
>>>describe_person(per)
description of webadmin
age: 42
def describe_person(person):
print("description of",person['name'])
print("age: ",person['age'])
try:
print('occupation: ',person['occupation'])
except KeyError:pass
检查对象是否包含特定的属性,可使用try/except语句:
检查一个对象是否包含属性write:
try:
obj.write
except AttribetError:
print("the object is not writeable")
else:
print("the object is writeable")
不那么异常的情况:警告
只想发出警告,指出情况偏离了正轨,可使用模块warnings中的函数warn
>>>from warnings import warn
>>>warn("there is a alert")
运行结果:
Warning (from warnings module):
File "C:UsersAdministratorDesktopp.py", line 2
warn("there is a alert")
UserWarning: there is a alert
注:警告值显示一次,若再运行warn(......),什么都不会发生。
如果其它代码在使用你的模块,可使用模块warnings中的函数filterwarnings来抑制你发出的告警(或特定类型的警告),并指定要采取的措施,如“error”或“ignore”
>>>from warnings import filterwarnings
>>>filterwarnings("ignore")
>>>warn("there is alert")
>>>filterwarnings("error")
>>>warn("something is wrong")
Traceback (most recent call last):
File "<pyshell#222>", line 1, in <module>
warn("something is wrong")
UserWarning: something is wrong
注:引发的异常为UserWarning
发出警告时,可指定将引发的异常(即告警类别),但必须是warning的子类。如果将告警转为错误,将使用你指定的异常。另还可根据异常来过滤掉特定类型的警告。
>>>filterwarnings("error")
>>>warn("this function is too old...",DeprecationWarning)
Traceback (most recent call last):
File "<pyshell#233>", line 1, in <module>
warn("this function is too old...",DeprecationWarning)
DeprecationWarning: this function is too old...
>>>filterwarnings("ignore",category=DeprecationWarning)
>>>warn("another dprecation warning",DeprecationWarning)
>>>warn("something else")
Traceback (most recent call last):
File "<pyshell#246>", line 1, in <module>
warn("something else")
UserWarning: something else