您现在的位置是:首页 > 学无止境 > 其他网站首页其他 Python错误处理和异常处理(二)

Python错误处理和异常处理(二)

  • 莫愁
  • 其他
  • 2019-07-31
简介前面我们讲到Python编程过程中,在可能出现异常的地方使用try语句,来正确的处理一些异常,可以保证程序不中断继续运行。
字数 3398

前面我们讲到Python编程过程中,在可能出现异常的地方使用try语句,来正确的处理一些异常,可以保证程序不中断继续运行。

错误和异常

 

抛出异常

有时候,我们可能需要在程序的某些地方主动抛出异常,通知调用该代码的程序有错误发生。这时候,我们就要用到raise语句。raise语句就是帮助我们抛出知道异常的,比如:

In [6]: raise NameError("Bad Name")
-----------------------------------
NameError           Traceback (most recent call last)
<ipython-input-6-966a00c8f456> in <module>
----> 1 raise NameError("Bad Name")

NameError: Bad Name

raise的使用很简单,它的语法如下:

raise [expression [from expression]]

如果它后面不带表达式(参数),它会重新引发当前作用域内最后一个激活的异常。 如果当前作用域内没有激活的异常,将会引发 RuntimeError 来提示错误。

如果后面带有表达式,则将表达式求值为要抛出的异常对象,该表达式必须是一个异常实例或者是一个异常类(继承自BaseException类)。如果它是一个异常类,它将通过调用没有参数的构造函数来隐式实例化:

raise NameError  # 等同于 'raise NameError()'

raise表达式后面还可以跟一个from子句,用于异常的串联。from子句的表达式必须是另一个异常或实例,它将作为可写的(writable)的__cause__属性被关联到所引发的异常。如果引发的异常未被捕捉处理,两个异常都将被打印出来:

In [9]: try:
    ...:     print(10/0)
    ...: except Exception as e:
    ...:     raise RuntimeError("something is wrong") from e
    ...:
----------------------------------------------------------
ZeroDivisionError            Traceback (most recent call last)
<ipython-input-9-7de64aad634f> in <module>
      1 try:
----> 2     print(10/0)
      3 except Exception as e:

ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

RuntimeError                 Traceback (most recent call last)
<ipython-input-9-7de64aad634f> in <module>
      2     print(10/0)
      3 except Exception as e:
----> 4     raise RuntimeError("something is wrong") from e
      5

 RuntimeError: something is wrong

如果一个异常在except子句或finally子句中被抛出,类似的机制会隐式地发挥作用,之前的异常将被关联到新异常的__context__属性。例如:

In [10]: try:
     ...:     print(10/0)
     ...: except:
     ...:     raise RuntimeError("something is wrong")
     ...:
-----------------------------------------------
ZeroDivisionError           Traceback (most recent call last)
<ipython-input-10-e950a6292482> in <module>
      1 try:
----> 2     print(10/0)
      3 except:

ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

RuntimeError                Traceback (most recent call last)
<ipython-input-10-e950a6292482> in <module>
      2     print(10/0)
      3 except:
----> 4     raise RuntimeError("something is wrong")
      5
 RuntimeError: something is wrong

异常串连可通过在from子句中用None来显示地禁止:

In [11]: try:
     ...:     print(10/0)
     ...: except:
     ...:     raise RuntimeError("something is wrong") from None
     ...:
-------------------------------
RuntimeError                   Traceback (most recent call last)
<ipython-input-11-1818bd8b9d31> in <module>
      2     print(10/0)
      3 except:
----> 4     raise RuntimeError("something is wrong") from None
      5

 RuntimeError: something is wrong

 

用户自定义异常

Python允许用户自定义异常类,通常应该直接或间接地继承自Exception类。

自定义的异常类的名称通常以“Error”结尾,类似与内置标准异常的命名。自定义的异常类,可以像其它类那样可以执行任何操作,但通常保持简单,只提供用以处理程序为异常提取有关错误信息的属性。为模块自定义多个不同错误的异常时,通常是为该模块定义一个异常基类,再为不同错误创建特定的子类。例如:

class ModuleError(Exception):
    '''模块的异常基类'''
    pass

class ModuleNameError(ModuleError):
    '''模块的特定异常子类'''
    pass

class ModuleValueError(ModuleError):
    '''模块的另一个特定异常子类'''
    pass

 

最后的清理操作:finally 子句

finally子句是try语句的一个可选子句,用于定义在任何情况下都执行的操作,叫做“清理操作”。例如:

In [12]: try:
     ...:     raise NameError
     ...: finally:
     ...:     print('Bye :)')
     ...:
     ...:
Bye :)
-------------------------------
NameError        Traceback (most recent call last)
<ipython-input-12-9cda1523ce81> in <module>
      1 try:
----> 2     raise NameError
      3 finally:
      4     print('Bye :)')
      5 

NameError: 

finally子句总会在离开try语句前被执行,无论发生异常与否。当在try子句中发生了异常且尚未被except子句处理(或者它发生在 except 或 else 子句中)时,该异常将在 finally 子句执行后被重新抛出。 当 try 语句的任何其他子句通过 break, continue 或 return 语句离开时,finally 也会在“离开之前”被执行,参考下面这个更复杂的例子:

In [13]: def divide(a, b):
     ...:     try:
     ...:         result = a / b
     ...:     except ZeroDivisionError:
     ...:         print('divided by zero!')
     ...:     else:
     ...:         print('result is', result)
     ...:     finally:
     ...:         print('leaving try')
     ...:

In [14]: divide(8, 2)
result is 4.0
leaving try

In [15]: divide(8, 0)
divided by zero!
leaving try

In [16]: divide('a', 2)
leaving try
-----------------------
TypeError              Traceback (most recent call last)
<ipython-input-16-324d9fa22da2> in <module>
----> 1 divide('a', 2)

<ipython-input-13-5e4380c62566> in divide(a, b)
      1 def divide(a, b):
      2     try:
----> 3         result = a / b
      4     except ZeroDivisionError:
      5         print('divided by zero!')

TypeError: unsupported operand type(s) for /: 'str' and 'int'

从上面的例子我们看到,finally子句总是会被执行。但字符串被除时引发了TypeError的异常,这个异常没有被except子句处理,就会在finally子句执行后被重新抛出。

在编程实践中,finally子句对释放文件或网络连接等外部资源是非常有用的。

 

总结

编程中,我们不仅要在恰当的地方处理异常,也要在必要的时候抛出异常,我们抛出异常时可以自定义异常。熟练运用异常可以使我们的程序更加健壮,别忘了必要的时候使用finally来释放外部资源。


转载: 感谢您对莫愁个人博客网站平台的认可,非常欢迎各位朋友分享到个人站长或者朋友圈,但转载请说明文章出处“来源莫愁个人博客 https://www.mochoublog.com/study/304.html”。

文章评论

    • 评论
    人参与,条评论

技术在线

服务时间

周一至周日 12:00-22:00

关闭下雪
关闭背景特效