python使用异常对象来表示异常状态,并在错误时引发异常,异常未被捕获或处理,程序将终止并显示错误信息。
引发异常
使用raise语句,并将一个类(必须时Exception的子类)或实例作为一个参数,将类作为一个参数时,将自动创建一个实例。
python中有一些常见内置异常类:
异常名称 |
描述 |
Exception |
常规错误的基类 |
ZeroDivisionError |
除(或取模)第二参数为零 (所有数据类型) |
AttributeError |
引用属性或给它赋值失败 |
OSError |
操作系统错误 |
IndexError |
序列中没有此索引(index) |
KeyError |
映射中没有这个键 |
NameError |
未声明/初始化对象 (没有属性) |
SyntaxError |
Python 语法错误,代码不正确 |
TypeError |
对类型无效的操作 |
ValueError |
传入无效的参数 |
还可以自定义异常类,但必须直接或间接的继承Exception:
class someException(Exception): pass
#自定义异常类 class SortInputException(Exception): def __init__(self, length, latest): self.length = length self.latest = latest def main(): try: s = input("enter:") if len(s) >= 3: raise SortInputException(len(s), 3) except SortInputException as res: print("输入的字符长度为:{0},默认长度应该小于:{1}".format(res.length, res.latest)) else: print("nothing to do") main()
捕获异常
捕获异常也就是对异常进行处理,可用try/except来实现:
>>> try: x = input('Enter the first number: ') y = input('Enter the second number: ') print(int(x)/int(y)) #需要转换为整型 except ZeroDivisionError: print("The second number can't be zero!") Enter the first number: 10 Enter the second number: 0 The second number can't be zero!
捕捉异常并重新引发---用raise实现
>>> 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 #raise重新引发异常 >>> mc = MuffledCalculator() >>> mc.calc('10/0') #屏蔽机制未打开,因为muffled = False Traceback (most recent call last): File "<pyshell#31>", line 1, in <module> calculator.calc('10/0') File "<pyshell#27>", line 5, in calc return eval(expr) File "<string>", line 1, in <module> ZeroDivisionError: int division or modulo by zero >>> mc.muffled = True #打开屏蔽机制 >>> mc.calc('10/0') Division by zero is illegal
如上如果启用了屏蔽机制,方法calc将会隐式的返回None,也就是不依赖返回值了。关闭屏蔽机制时,捕获了异常ZeroDivisionError,但是它继续向上传播。如果无法处理异常,可以在except子句中使用不带参数的raise即可。
当引发其他异常的时候,except的子句的异常会被作为异常上下文存储起来。可以使用raise...from...语句来提供自己的上下文,使用None禁用上下文:
多个except子句,捕捉多个不同类型的异常(此处不必类型转换)
>>> try: x = input('Enter the first number: ') y = 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 it? ") Enter the first number: 2 Enter the second number: wsf That wasn't a number. was it?
用一个块捕捉两个异常,在一个元组中指定这些异常
>>> try: x = input('Enter the first number: ') y = input('Enter the second number: ') print(int(x)/int(y)) except(ZeroDivisionError,TypeError,NameErrror): #NameError找不到名字(变量)时引发 print('Your numbers were bogus....')
捕捉对象---让程序继续运行并记录错误
except子句中访问异常对象本身,得使用两个参数,而不是一个
注意:在捕获多个异常时,也只是向except提供了一个参数,元组。
>>> try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y) except (ZeroDivisionError, TypeError) as e: print(e) Enter the first number: 1 Enter the second number: 0 division by zero
捕捉所有的异常,except后不指定任何异常类即可。但是这样使用会隐藏没考虑过的错误不推荐。更好的选择是使用except Except as e并对异常对象进行检查。这样也会使得不是从Except类派生而来的异常漏掉。像SystemExit和KeyboradInterrupt都是从BaseExcept(Except的超类)派生而来的。
>>> try: x = input('Enter the first number: ') y = input('Enter the second number: ') print(x/y) except: print('Something wrong happened...') Enter the first number: "This" is "completely" illegal 123 Enter the second number: 2 Something wrong happened...
给try/except语句添加一个else子句:
>>> try: print('A simple task') except: print('What? Something went wrong?') else: print('Ah...It went as planned.') A simple task Ah...It went as planned.
当没有发生异常使用break跳出循环
>>> while True: try: x = input('Enter the first number: ') y = input('Enter the second number: ') value = int(x)/int(y) print('x/y is', value) except: print('Invalid input, Please try again.') else: break Enter the first number: test Enter the second number: 1 Invalid input, Please try again. Enter the first number: 10 Enter the second number: 2 x/y is 5.0
使用try/except Exception,e /else
>>> while True: try: x = input('Enter the first number: ') y = input('Enter the second number: ') value = int(x)/int(y) print('x/y is', value) except Exception as e: #python 3.0的写法 print('Invalid input: ',e) print('Please try again') else: break Enter the first number: 1 Enter the second number: 0 Invalid input: int division or modulo by zero Please try again Enter the first number: 'x' Enter the second number: 'y' Invalid input: invalid literal for int() with base 10: "'x'" Please try again Enter the first number: quux Enter the second number: 2 Invalid input: invalid literal for int() with base 10: 'quux' Please try again Enter the first number: 10 Enter the second number: 2 x/y is 5.0
使用try/finally,不管try中发生什么,最后finally都会被执行
>>> try: x = 1/0 finally: #finally子句肯定会被执行 print('Cleaning up...') del x Cleaning up... Traceback (most recent call last): File "<pyshell#25>", line 2, in <module> x = 1/0 ZeroDivisionError: int division or modulo by zero
一条语句可以同时包含try/except/else/finally (或者其中3个)
>>> try: 1/0 except NameError: print("Unknown variable") else: print("That went well!") finally: print("Cleaning up.")
异常和函数
>>> def describePerson(Person): print('Description of', person['name']) print('Age:', Person['age']) try: print('Occupation:' , person['occupation']) #直接假设存在occupation键,如果不存在则引发异常 except KeyError: pass >>> person = {'name': 'Jack', 'age': 34} >>> describePerson(person) Description of Jack Age: 34
查看对象是否存在特定特性时,try/except很有用
>>> try: obj.write except AttributeError: print('The Object is not writeable') else: print('The Object is writeable')
警告,类似与异常,但通常只打印一条错误消息,可以指定警告级别,它们是Warning的子类。
还可以使用warnings模块中的函数filterwarnings来抑制警告,并指定采取的措施,比如ignore和error。另外可以根据异常来过滤掉特定类型的警告。