1、程序难免会出现错误,错误分两种:

1)语法错误;

2)逻辑错误;

# 错误常见类型
# 1/0          # ZeroDivisionError: division by zero
# name         # NameError: name 'name' is not defined
# 2 + '3'      # TypeError: unsupported operand type(s) for +: 'int' and 'str'
# [][3]        # IndexError: list index out of range
# {}['k']      # KeyError: 'k'
# int('a')     # ValueError: invalid literal for int() with base 10: 'a'

2、程序一旦出现错误,就从错误的位置上停下来了,不再继续执行后面的内容了。

python 设置错误级别 python中的错误类型_python

说明:解释器向我们报告了,有一个ZeroDevisionError的错误对象,异常对象产生了。

解释器没有办法执行后面的代码,所以程序就在这个位置上停下来,程序到此结束,不再执行后面的代码了。

ZeroDevisionError就是一个异常对象的类,继承自标准库里面的Exception类。

Python标准库中,还有很多其他的异常类都是继承自标准库里面的Exception类。代表各种不同类型的错误。

python 设置错误级别 python中的错误类型_异常处理_02

3、Python中的异常种类:

在Python中不同的异常可以有不同的类型(python中统一了类与类型,类型即类)去标识,不同的类对象标识不同的异常,一个异常标识一个错误。

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的

 

python 设置错误级别 python中的错误类型_异常处理_03

 KeyError:表示字典中没有2这个key值。字典中没有这个key值。

4、异常处理:

python解释器检测到错误,触发异常。我们代码可能会产生各种错误类型,各种异常类型。

如果我们在编写代码的时候,就预料到某些代码运行时可能会出现某些异常,就可以使用try...except...这种方式来捕获和处理异常。

程序员编写特定的代码,专门用来捕捉这个异常(这段代码与逻辑无关,与异常处理有关)

如果捕捉成功则进入到另外一个处理分支,执行你为其制定的逻辑,使程序不会奔溃,这就是异常处理。

while True:
    miles = input('请输入英里数:')
    km = int(miles) * 1.609344
    print(f'等于{km}公里')

编写这段代码的时候,我们就预料到,可能用户会输入非数字的字符,这样int转化就会出错,导致整个程序退出了。

while True:
    try:
        miles = input('请输入英里数:')
        km = int(miles) * 1.609344
        print(f'等于{km}公里')
    except ValueError:
        print('你输入了非数字字符')

 

python 设置错误级别 python中的错误类型_Python_04

程序不会出错,会继续执行。

另外,我们怎么知道是ValueError,这个也是在输入非数字字符的时候,解释器报出异常,根据提示错误信息来确认是ValueError。

try 下面缩进的3行代码可以看成是 保护区 中的代码。

如果执行保护区中代码时,出现异常,解释器会结束保护区中后续代码的执行,并检查这个异常的类型是否匹配后面的except 语句中声明的类型。

如果匹配上,解释器知道程序对此种异常是预料到的,并且有对应的处理方案,也就是匹配的except下面缩进的代码。解释器就执行匹配的except下面缩进的代码,不会因此中止程序。

如果我们开发程序的时候,估计某个代码段中可能出现好几种类型的异常,可以使用多个except代码段,分别捕获多种类型的异常。

try:
    choice = input('输入你的选择:')
    if choice == '1':
        100/0
    elif choice == '2':
        [][2]
except ZeroDivisionError:
    print ('出现 ZeroDivisionError')
except IndexError  :
    print ('出现 IndexError')

考虑更多异常,我们都可以使用except语句来处理。

获取异常对象:

try:
    100/0
except ZeroDivisionError as e:
    print (f'异常对象信息:{e}')

代码说明:

产生的异常对象赋值给了变量e。

匹配所有异常,也就是万能异常:

try:
    100/0
except Exception as e:
    print('未知异常:', e)

因为所有的异常都是Exception类,所以Exception能匹配所有类型的异常。

import traceback

try:
    100/0
except :
    print(traceback.format_exc())

如果想知道异常的详细信息,可以使用traceback模块。

5、为什么要进行异常处理?

Python解释器去执行程序,检测到一个错误时,触发异常,异常触发后没被处理的情况下,程序就在当前的异常处终止,后面的代码就不会执行,突然奔溃的软件是没有人使用的。

所以,我们必须提供一种异常处理机制来增强我们程序的健壮性与容错性。

6、如何进行异常处理?

异常是由程序错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正。

7、if语句处理异常的方法:

num1=input('>>: ') #输入一个字符串试试
if num1.isdigit():
    int(num1) #我们的正统程序放到了这里,其余的都属于异常处理范畴
elif num1.isspace():
    print('输入的是空格,就执行我这里的逻辑')
elif len(num1) == 0:
    print('输入的是空,就执行我这里的逻辑')
else:
    print('其他情情况,执行我这里的逻辑')

 
问题一:
使用if的方式我们只为第一段代码加上了异常处理,但这些if,跟你的代码逻辑并无关系,这样你的代码会因为可读性差而不容易被看懂。

问题二:
这只是我们代码中的一个小逻辑,如果类似的逻辑多,那么每一次都需要判断这些内容,就会倒置我们的代码特别冗长。

总结:

1.if判断式的异常处理只能针对某一段代码,对于不同的代码段的相同类型的错误你需要写重复的if来进行处理。

2.在你的程序中频繁的写与程序本身无关,与异常处理有关的if,会使得你的代码可读性极其的差

3.if是可以解决异常的,只是存在1,2的问题,所以,千万不要妄下定论if不能用来异常处理。

8、Python为每种异常定制了一种类型,然后提供了一种特定的语法结构用来进行异常处理。

1)基本语法:

try:
     被检测的代码块
except 异常类型:
     try中一旦检测到异常,就执行这个位置的逻辑

例1:

try:
    ret = int(input('number >>>'))
    print(ret * '*')
except ValueError:
    print("您输入的内容有误,请输入一个数字: ")

使用try和except就能处理异常:

# try是我们需要处理的代码

# except 后面跟一个错误类型,当代码发生错误且错误类型符合的时候,就会执行except中的代码。

例2:

try:
    f = open('a.txt')
    g = (line.strip() for line in f)
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
except StopIteration:
    f.close()
# content in file 'a.txt'
chang
jiang
yang
liang
huang
guang

 结果:

python 设置错误级别 python中的错误类型_python_05

并没有报错,而是第六行的时候,捕获了StopIteration,直接关闭文件。

next(g) 会触发迭代f,依次next(g)就可以读取文件中的一行一行的内容,无论文件a.txt有多大,同一时刻内存中只有一行内容。

提示:g是基于文件句柄f而存在的,因而只能在next(g)抛出异常StopIteration后才可以执行f.close()。

2)异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。未捕获的异常,程序直接报错。

例:

s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)

结果:

python 设置错误级别 python中的错误类型_python_06

int(s1),这个语句,是ValueError异常,不是代码中指定的异常处理,所以这个异常没有被处理,程序直接退出。

3)多分支:也就是except语句是支持多分支的。

例1:

try:
    [][3]
    ret = int(input('number >>>'))
    print(ret * '*')
except ValueError:
    print("您输入的内容有误,请输入一个数字: ")
except IndexError:
    print('List index out of range.')

例2:

s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)

 

4)万能异常:在Python中有一个万能异常Except,他可以捕获任意异常。

s1 = 'hello'
try:
    int(s1)
except Exception as e:
    print("有异常啦,请处理!", e)

说明:

a)pycharm提示异常子句过于宽泛。

b)异常有些比较具体,我们还是要用具体的异常来捕获,通过异常处理来具体单独处理解决。

c)异常处理也是有顺序的,从上到下,有了万能异常,但是要把能预测的异常单独处理。

d)单独处理的内容都应该写在万能异常之前。

python 设置错误级别 python中的错误类型_异常处理_07

 

5)异常的其他机构:

else语句:没有异常的时候,则执行else中的代码。

那什么时候使用呢?当代码执行顺利的时候,就执行else中的内容。

6)finally: 最后的。

无论执行异常与否,都会执行该模块,通常是进行清理工作(收尾工作)。常见的场景在try中有打开文件的处理,那最后在finally语句中要关闭下文件f.close()。另外还有操作数据库和操作网络的场景。

finally和return相遇的时候,依然会执行。

python 设置错误级别 python中的错误类型_ico_08

 从网上找到一个流程图的图片,其中except语句块,如果要拓展的话,还需要增加单独异常except语句,最后的Exception的万能语句块。

7)主动触发异常:

raise关键字,主动产生异常。

try:
    raise TypeError('类型错误')
except Exception as e:
    print(e)

8)自定义异常:

class EvaException(BaseException):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        return self.msg

try:
    raise EvaException('类型错误')
except EvaException as e:
    print(e)

异常类型都是继承自Exception的类,表示各种类型的错误。

# 异常对象,代表电话号码有非法字符
class InvalidCharError(Exception):
    pass

# 异常对象,代表电话号码非中国号码
class NotChinaTelError(Exception):
    pass

定义 了以上的异常,当用户输入电话号码的时候,出现相应的错误,我们就可以使用raise关键字来抛出对应的异常处理。

def  register():
    tel = input('请注册您的电话号码:')

    # 如果有非数字字符
    if not tel.isdigit(): 
        raise InvalidCharError()

    # 如果不是以86开头,则不是中国号码
    if not tel.startswith('86'): 
        raise NotChinaTelError()
    
    return tel

try:
    ret = register()
except InvalidCharError:
    print('电话号码中有错误的字符')
except NotChinaTelError:
    print('非中国手机号码')

 我们在代码中增加了traceback.format_exc(),会打印出调用栈中那段代码出现了问题。

python 设置错误级别 python中的错误类型_python 设置错误级别_09

python 设置错误级别 python中的错误类型_Python_10

这个就是traceback.format_exc()函数的功能,输出traceback的相关信息。

9)断言:

# assert 条件
 
assert 1 == 1
assert 1 == 2

try...except的方式比较if的方式:

try..except这种异常处理机制就是取代if那种方式,让你的程序在不牺牲可读性的前提下增强健壮性和容错性。

异常处理中为每一个异常定制了异常类型(python中统一了类与类型,类型即类),对于同一种异常,一个except就可以捕捉到,可以同时处理多段代码的异常(无需‘写多个if判断式’)减少了代码,增强了可读性。 

最后,什么时候使用异常处理:

try...except应该尽量少用,因为它本身就是你附加给你的程序的一种异常处理的逻辑,与你的主要的工作是没有关系的,这种东西加的多了,会导致你的代码可读性变差,只有在有些异常无法预知的情况下,才应该加上try...except,其他的逻辑错误应该尽量修正 。

异常无法预知的情况下,才应该加上try...except。

附:常见异常:

ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError