一.错误和异常
1.错误(Error):程序中的错误分为俩种
第一种语法错误:不按照语言的规则,必须在程序执行前就改正
第二种逻辑错误:算法写错了,加法写成了减法,函数或类使用错误,其实这也属于逻辑错误
2.异常(Exception):就是程序运行时发生错误的信号,本身就是意外情况,这有个前提,没有出现上面说的错误,也就是说程序写的没有问题,但是在某些情况下,会出现一些意外,导致程序无法正常的执行下去。
(1)例如open函数操作一个文件,文件不存在,或者创建一个文件时已经存在了,或者访问一个网络文件,突然断网了,这就是异常,是个意外的情况,异常不可能避免。
(2)分为三部分
①Traceback:异常追踪的信息
②NameError:
③NameError异常类后面的是:异常值
3.错误和异常:在高级编程语言中,一般都有错误和异常的概念,异常是可以捕获,并被处理的,但是错误是不能被捕获的
(1)异常
with open('testabc') as f: pass ##异常 Traceback (most recent call last): File "test2.py", line 1, in <module> with open('testabc') as f: FileNotFoundError: [Errno 2] No such file or directory: 'testabc'
(2)错误
def 0A(): pass ##错误: def 0A(): ^ SyntaxError: invalid syntax
总结:一个健壮的程序,尽可能的避免错误,尽可能的捕获,处理各种异常
4.python中的常用的异常种类
在python中不同的异常可以用不同的类型(python中统一了类与类型,类型即类)去标识,不同的类对象标识不同的异常,一个异常标识一种错误
AttributeError:视图访问一个对象没有属性,比如foo.x,但是foo没有属性x
IOError:输入/输出操作失败(基本上是无法打开文件)
TypeError:传入对象类型与要求的不符合
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
5.异常类及继承层次
python异常的继承
BaseException[所有内建异常类的基类] +--SystemExit[sys.exit()函数引发的异常,异常不捕获处理,就直接交给python解释器,解释器退出] +--KeyboardInterrupt[对应的捕获用户中断行为Ctrl+c] +--GeneratorExit +--Exception[是所有内建的,非系统退出的异常的基类,自定义异常应该继承自它] +--自定义异常[从Exception继承的类] +--RuntimeError +RecursionError +--MemoryError +--NameError[异常类(错误的类型)] +--StopIteration +--StopAsyncIteration +--ArithmeticError[所有算术计算引发的异常,其子类的除零异常等] +--FloatingPointError +--OverflowError +--ZeroDivisionError +--LookupError[使用映射的键或序列的索引无效时引发的异常的基类:IndexError,KeyError] +--IndexError +--KeyError +--SyntaxError[语法错误:Python将这种错误也归到异常类下面的Exception下的子类,但是这种错误是不可捕获的] +--OSError +--BlockingIOError +--ChildProcessError +--ConnectionError +--BrokenPipeError +--ConnectionAbortedError +--ConnectionRefusedError +--ConnectionResetError +--FileExistsError +--FileNotFoundError +--InterruptedError +--InterruptedError +--IsADirectoryError +--NotADirectoryError +--PermissionError +--PermissionError +--ProcessLookupError +--TimeoutError
6.异常处理
(1)异常处理:把产生的异常捕捉到,进入另外一个处理分支,执行你为其制定的逻辑,使程序不会崩溃,这就是异常处理
(2)为何要进行异常处理:当触发异常后且没有被处理的情况下,程序就在当前异常终止,后面的代码不会运行,所以必须提供一种异常处理机制来增强你的程序健壮性与容错性
(3)异常是由程序的错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正
二.异常处理
方式一:if处理异常
#第一段代码 age=input('>>: ') if age.isdigit(): int(age) #主逻辑:如果用户输入是数字才会运行主逻辑 elif age.isspace(): #如果用户输入空格 print('用户输入的空格') elif len(age) == 0: #如果用户输入空 print('用户输入的为空') else: #如果用户输入除数字其它 print('其他的非法输入') #第二段代码 num2=input('>>: ') if num2.isdigit(): int(num2) #主逻辑 elif num2.isspace(): print('---->用户输入的空格') elif len(num2) == 0: print('----》用户输入的为空') else: print('其他的非法输入')
总结:
(1)if做异常处理只能针对一段代码,对于不同的代码段的相同类型的错误你需要重复的if来进行处理。
(2)在你的程序中频繁的写与程序本身无关,与异常处理有关的if
方式二:try...except:python为每一种异常定制了一个类型,然后提供一种特定的语法结构用来进行异常处理
1.基本语法:
try: 被检测的代码块 except [异常类型]: 异常的处理代码块 #try中一旦检测到异常,就执行这个位置的逻辑
举例:
try: #产生异常 1/0 #产生异常后下面不执行 print('after') #交给except处理 except: print('exception') #打印结果:exception
总结:
上例子执行到1/0时产生异常并抛出,由于使用了try...except语句块则捕捉到了这个异常,异常生成位置之后语句将不再执行,转而执行对应的except部分的语句,最后执行try...except语句块之外的语句。
使用try..except的方式的好处:
①把错误处理和真正的工作分开
②代码更易组织,更清晰,复杂的工作任务更容易实现
③更安全,不至于由一些小的疏忽而使程序意外崩溃了
2.as子句:
try: #主逻辑1输出整型 age=input('1>>: ') int(age) #主逻辑2输出整型 num2=input('2>>: ') int(num2) #except捕捉ValueError俩段代码同一种异常把取名字为e except ValueError as e: #在哪个位置引发异常异常会被except捕捉到,如果能捕捉到就会执行except以下的代码,直接打印捕捉的异常错误,如果捕捉不到程序蹦掉 print(e)
主逻辑1当输入123时候是整型没报错继续往下执行
1>>: 123
主逻辑2输入abc不是整型抛出异常被except捕捉到
2>>: abc
打印捕捉到的错误:invalid literal for int() with base 10: 'abc'
3.异常的捕获:except可以捕获多个异常
(1)如果你想要的效果是,无论出现什么异常,我们统一丢弃,或者使用同一段代码逻辑去处理他们,只有一个Exception万能异常就足够了
(2)如果你想要的效果是,对于不同的异常我们需要定制不同的处理逻辑,那就需要用到多分支
s1 = 'xixi' #s1=1 try: int(s1) #多分支异常1 except IndexError as e: print(e) #多分支异常2 except KeyError as e: print(e) #多分支异常3:捕获到异常 except ValueError as e: print(e) #捕获到异常打印:invalid literal for int() with base 10: 'xixi' #多分支万能异常其他没有考虑到的 except Exception as e: print(e)
捕获规则总结:
①捕获是从上到下依次比较,如果匹配,则执行匹配的except语句块
②如果被一个except语句捕获,其他except语句就不会再次捕获了
③如果没有任何一个except语句捕获到这个异常,则该异常向外抛出
捕获的原则:
①从小到大,从具体到宽泛
4.主动触发异常(raise)
(1)raise后什么都没有,表示抛出最近一个被激活的异常,入股没有被激活的异常,则抛类型异常。
(2)raise后要求应该是BaseException类的子类或实例,如果是类,将被无参实例化。
try: #python提供一堆类型就是类,类加上括号进行实例化,raise可以TypeError加一个括号传值进去 raise TypeError('类型错误') except Exception as xi: print(xi) #打印结果:类型错误
5.自定义异常类:
#自定义异常就是在写一个类,这个类就是XiXiException这个异常,自定义异常必须继承Exception这个类 class XiXiException(Exception): pass #主动触发异常用raise触发 try: #raise主动触发自定制的异常类XiXiException实例化产生的异常对象 raise XiXiException('自定制异常') #except捕捉到这个异常 except XiXiException as xixi: print(xixi) #打印结果:自定制异常
6.异常的捕获时机
(1)立即捕获:需要立即返回一个明确的结果
def parse_int(s): try: return int(s) #立即捕获异常 except: #返回异常结果 return 0 #正常传整数调用函数: print(parse_int(123)) #返回结果:123 #不正常传字符串调用函数捕捉异常 print(parse_int('a')) #返回结果:0
(2)边界捕获:封装产生了边界
例如,写一个模块,用户调用这个模块的时候捕获异常,模块内部不需要捕获,处理异常,一旦内部处理了,外部调用者就无法感知了,
例如,open函数,出现的异常交给调用者处理,文件存在了,就不用再创建了,看是否修改还是删除
例如,自己写一个类,使用open函数,但是出现了异常不知道如何处理,就继续向外层抛出,一般来说最外层也就是边界,必须处理这个异常了,否则线程退出
7.其他的异常结构(else和finally)
语法:
try: <语句> #运行别的代码 except <异常类>: <语句> #捕获某种类型的异常 except <异常类> as <变量名>: <语句> #捕获某种类型的异常并获得对象 else: <语句> #如果没有异常发生 finally: <语句> #退出try时总会执行
举例:
s1 = 'xixi' #s1=1 try: int(s1) except IndexError as e: #多分支异常1 print(e) except KeyError as e: #多分支异常2 print(e) except ValueError as e: #多分支异常3 print(e) except Exception as e: #多分支万能异常其他没有考虑到的 print(e) else: #try内代码里没有异常的情况下会执行else里的东西 print('try内代码块没有异常执行') finally: #无论异常与否都会执行finally里的东西,通常是清理工作 print('try内代码块有没有异常,都会执行') print(11111111111) print(22222222222) print(33333333333) ####打印结果: invalid literal for int() with base 10: 'xixi' try内代码块有没有异常,都会执行 11111111111 22222222222 33333333333
8.try的工作原理:
(1)如果try中语句执行时发生异常,搜索except子句,并执行第一个匹配该异常的except子句
(2)如果try中语句执行时发生异常,却没有匹配的except子句,异常将被递交到外层的try,如果外层不处理这个异常,异常将继续向外层传递。如果都不处理该异常,则会传递到最外层,如果还没有处理,就终止异常所在的线程
(3)如果在try执行时没有发生异常,将执行else子句中的语句
(4)无论try中是否发生异常,finally子句最终都会执行
9.断言assert:在程序的某个位置判断一下结果是否是你想要的值,如果不是想要的值抛出异常
def test(): #定义test函数 '一堆逻辑' res=1 #由一堆逻辑处理完得到一个结果是1 return 1 #处理完逻辑返回一个值1 res1=test() #一堆逻辑运行得到一个结果赋值给res1 assert res1 == 1 #断言判断res1是否等于1 #下面的代码,要跟res1的结果进行下一步处理
三.未实现和未实现异常
#未实现 print(NotImplemented) #打印结果:NotImplemented #未实现异常 print(NotImplementedError) #打印结果:<class 'NotImplementedError'>
总结:
NotImplemented是个值,单值,是NotImplementedType类的实例
NotImplementedError是类型,是异常,返回type