13.python错误和异常

一.错误和异常
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

posted on 2018-11-05 11:13  我不是西西  阅读(401)  评论(0编辑  收藏  举报