• 20210225-1 Python错误与异常


     

    一、什么是异常

     

    Python错误与异常

    什么是异常

    > 异常是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行。一般情况下,在Python无法正常处理程序时就会发生异常。异常是Python的对象,表示一个错误。当Python脚本发生异常时,我们需要捕获并处理异常,否则程序会终止执行。

    > 每一个异常都是一些类的实例,这些实例可以被引用,并且可以用很多种方法进行捕捉,使得错误可以被处理,而不是让整个程序失败。

    代码里会有很多异常,比如 NameError 名称错误,Syntax Error 语法异常,Type Error 类型错误,Value Error值异常;这四种都是异常,异常其实是一个事件

    代码里有异常是非常正常的事情,捕获到异常,扔掉就可以了

    >>> 10*(1/0)

    Traceback (most recent call last):

    File "<stdin>", line 1, in <module>

    ZeroDivisionError: division by zero

    >>> 4+a1*3

    Traceback (most recent call last):

    File "<stdin>", line 1, in <module>

    NameError: name 'a1' is not defined

    >>> '2'+2

    Traceback (most recent call last):

    File "<stdin>", line 1, in <module>

    TypeError: can only concatenate str (not "int") to str

    这些就叫做异常

     

    二、异常处理

     

    异常处理

    > try语句的基本形式为try/except。try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。如果你不想在发生异常时结束程序,只需在try语句块中捕获异常即可。

    > 捕获异常的语法如下:

    > 异常捕捉try/except

    1-1
    def exp_exception(x,y):
        try:
            a=x/y
            print('a=',a)
            return a
        except Exception:
            print("程序出现异常,异常信息:被除数为0")
     
    exp_exception(2,2)
    =>
    a= 1.0
    1-2
    def exp_exception(x,y):
        try:
            a=x/y
            print('a=',a)
            return a
        except Exception:
            print("程序出现异常,异常信息:被除数为0")
     
    exp_exception(2,0)
    =>
    程序出现异常,异常信息:被除数为0

    > 捕捉多个异常

    1-1
    def exp_exception(x,y):
        try:
            a=x/y
            b=name
            print('a=',a)
            return a
        except ZeroDivisionError:
            print("除数不能为0")
        except NameError:
            print("没有你要找的名字")
     
    exp_exception(2,0)
    =>
    除数不能为0
    1-2
    def exp_exception(x,y):
        try:
            a=x/y
            b=name
            print('a=',a)
            return a
        except ZeroDivisionError:
            print("除数不能为0")
        except NameError:
            print("没有你要找的名字")
     
    exp_exception(2,2)
    =>
    没有你要找的名字

    > 使用一个块捕捉多个异常

    > 如果需要使用一个块捕捉多个类型异常,可以将它们作为元组列出。使用该方式时,遇到的异常类型是元组中的任意一个,都会走异常流程。

    > 这么做有什么好处呢?假如我们希望多个except子句输出同样的信息,就没有必要在几个except子句中重复输入语句,放到一个异常块中即可。

    刚刚使用 except 捕获了两个异常,现在想把两个异常写到一个except中

    def exp_exception(x,y):
        try:
            a=x/y
            b=name
            print('a=',a)
            return a
        except (ZeroDivisionError,NameError,TypeError):
            print("你的输出数据有误!")
     
    exp_exception(2,'0')
    =>
    你的输出数据有误!

     

    异常处理

    > 捕捉对象

    > 如果希望在except子句中访问异常对象本身,也就是看到一个异常对象真正的异常信息,而不是输出自己定义的异常信息,可以使用as e的形式,我们称之为捕捉对象。

    def exp_exception(x,y):
        try:
            a=x/y
            b=name
            print('a=',a)
            return a
        except (ZeroDivisionError,NameError,TypeError) as e:
            print(e)    # 输出 e,这地方不要写自己自定义的内容
     
    exp_exception(2,'0')
    exp_exception(2,0)
    exp_exception(2,2)
    =>
    unsupported operand type(s) for /: 'int' and 'str'
    division by zero
    name 'name' is not defined

    这就是捕捉对象,前面的异常提示是自定义的,捕捉对象的意思是系统给的系统提示,用 as e 即可

    用系统给出的提示相比更便于定位

     

    > 全捕捉

    > 在实际编码过程中,即使程序能处理好几种类型的异常,但有一些异常还是会从我们手掌中溜走。对于这种情况我们根本无法预测会发生什么,也无法提前做任何准备。在这种情况下,与其使用不是捕捉异常的try/except语句隐藏异常,不如让程序立即崩溃。

    def exp_exception(x,y):
        try:
            a=x/y
            b=name
        except (ZeroDivisionError,NameError,TypeError) as e:
            print(e)   
     
    exp_exception(2,'')
    =>
    unsupported operand type(s) for /: 'int' and 'str'

    这样b=name的异常就逃走了,没有对 b 进行检查

    对于这种情况,无法预测未来会发生什么,也没办法提前做任何准备,所以缺陷一定会产生,所以这时不如让异常直接崩溃,直接在后面什么都不写就可以了

    def exp_exception(x,y):
        try:
            a=x/y
            b=name
        except:
            print("Error")   
     
    exp_exception(2,'')
    =>
    Error

    后面什么都不写就叫全捕捉,当然这只是一种解决方案,从实用性角度看不建议这样做,因为这样捕捉异常非常危险,会隐藏所有没有预先想到的错误

     

    > try/except...else

    > try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。

    > else 子句将在 try 子句没有发生任何异常的时候执行。

    > try/except...else

    def exp_exception(x,y):
        try:
            a=x/y
        except:
            print("Error")   
        else:
            print("程序没有错误,执行结束")
     
    exp_exception(2,'')
    exp_exception(2,2)
    =>
    Error

    程序没有错误,执行结束

    当程序没有异常时,会执行 else 子句流程

     

    > try-finally 语句

    > try-finally 语句无论是否发生异常都将执行最后的代码。

    > 在有finally的异常处理程序中,finally中的子句一定是最后执行的。finally子句在关闭文件或数据库连接时非常有用

    如果有异常,try => except => finally

    如果无异常,try => else => finally

    def use_finally(x,y):
        try:
            a=x/y
        finally:
            print("不管有没有异常,都会执行我的哦~")
     
    use_finally(2,2)
    use_finally(2,0)
    =>
    不管有没有异常,都会执行我的哦~
    不管有没有异常,都会执行我的哦~
    Traceback (most recent call last):
     File "d:/VSCode/Untitled-1.py", line 10, in <module>
     use_finally(2,0)
     File "d:/VSCode/Untitled-1.py", line 5, in use_finally
     a=x/y
    ZeroDivisionError: division by zero

    但这引起了一个新的问题,虽然执行了 finally 语句,但是还是抛出异常了

    能不能用 except 在 try 里面解惑它呢

    def use_finally(x,y):
        try:
            a=x/y
        except ZeroDivisionError:
            print("除数不能为0")
        finally:
            print("不管有没有异常,都会执行我的哦~")
     
    use_finally(2,2)
    use_finally(2,0)
    =>
    不管有没有异常,都会执行我的哦~
    除数不能为0
    不管有没有异常,都会执行我的哦~

    现在加上else也是一样可以的

    def use_finally(x,y):
        try:
            a=x/y
        except ZeroDivisionError:
            print("除数不能为0")
        else:
            print("程序执行成功")
        finally:
            print("不管有没有异常,都会执行我的哦~")
     
    use_finally(2,2)
    use_finally(2,0)
    =>
    程序执行成功
    不管有没有异常,都会执行我的哦~
    除数不能为0
    不管有没有异常,都会执行我的哦~

    除了 try,后面的 except else 和 finally 都被称为 try 的子句,必须和 try 配合使用才有意义

     

    三、抛出异常

     

    抛出异常

    > Python 使用 raise 语句抛出一个指定的异常。

    > raise语法格式如下:

    前面一直在说捕获异常,异常必须是能够抛出来才能捕获的,python中使用 raise 抛出指定的异常

    使用 raise 触发异常,把异常引出来即可,用实例调用 raise 语句,引发异常

    >>> raise Exception

    Traceback (most recent call last):

    File "<stdin>", line 1, in <module>

    Exception

    >>> raise NameError("This is NameError")

    Traceback (most recent call last):

    File "<stdin>", line 1, in <module>

    NameError: This is NameError

    通过 这两个实例,可以看出,第一个实例引发没有相关错误信息的普通异常

    第二个输出了一些错误提示;

    如果只想知道有没有抛出异常,并不想处理它,使用一个 raise 就可以把异常抛出

    try:
        raise NameError("这是一个NameError")
    except NameError:
        print("捕捉到NameError") # 不加 raise,输出对应字符就结束
    =>
    捕捉到NameError
    try:
        raise NameError("这是一个NameError")
    except NameError:
        print("捕捉到NameError")
        raise
    =>
    捕捉到NameError
    Traceback (most recent call last):
     File "d:/VSCode/Untitled-1.py", line 4, in <module>
     raise NameError("这是一个NameError")
    NameError: 这是一个NameError

    这样又把 NameError异常抛出来了,raise可以抛出更深更详尽的异常信息

     

    Python重要的内建异常类

    Exception:常规错误的基类

    AttributeError:对象没有这个属性

    IOError:输入/输出操作失败

    IndexError:序列中没有此索引

    KeyError:映射中没有这个键

    NameError:未声明/初始化对象(没有属性)

    SyntaxError:python语法错误

    SystemError:一般解释器系统错误

    ValueError:传入无效的参数

     

     

     

  • 相关阅读:
    js上传Excel文件
    在typescript中import第三方类库clipboard报错
    webpack学习(一)安装和命令行、一次js/css的打包体验及不同版本错误
    querySelector和getElementById之间的区别
    关于js延迟加载(异步操作)的方式
    addEventListener与attachEvent
    ES6 的Object.assign(target, source_1, ..., source_n)方法与对象的扩展运算符
    JS实现生成一个周对应日期数组
    微信小程序之媒体查询@media
    微信小程序之页面引用utils中的js文件
  • 原文地址:https://www.cnblogs.com/azxsdcv/p/14449643.html
Copyright © 2020-2023  润新知