Python新手学习raise用法


Posted in Python onJune 03, 2020

当程序出现错误时,系统会自动引发异常。除此之外,Python 也允许程序自行引发异常,自行引发异常使用 raise 语句来完成。

很多时候,系统是否要引发异常,可能需要根据应用的业务需求来决定,如果程序中的数据、执行与既定的业务需求不符,这就是一种异常。由于与业务需求不符而产生的异常,必须由程序员来决定引发,系统无法引发这种异常。

如果需要在程序中自行引发异常,则应使用 raise 语句。raise 语句有如下三种常用的用法:

  1. raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
  2. raise 异常类:raise 后带一个异常类。该语句引发指定异常类的默认实例。
  3. raise 异常对象:引发指定的异常对象。

上面三种用法最终都是要引发一个异常实例(即使指定的是异常类,实际上也是引发该类的默认实例),raise 语句每次只能引发一个异常实例。

可以利用 raise 语句再次改写前面五子棋游戏中处理用户输入的代码:

try :
  #将用户输入的字符串以逗号( ,)作为分隔符,分隔成两个字符串
  x_str, y_str = inputStr.split(sep =",")
  #如果要下棋的点不为空
  if board[int(y_str) - 1] [int(x_str) - 1] != "+":
  #引发默认的RuntimeError异常
  raise
  #把对应的列表元素赋为”●”
  board [int(y_str) - 1] [int(x_str) - 1] = ”●”
except Exception as e:
  print (type(e))
  inputStr = input("您输入的坐标不合法,请重新输入,下棋坐标应以x,y 的格式\n")
  continue

上面程序中第 7 行代码使用 raise 语句来自行引发异常,程序认为当用户试图向一个已有棋子的坐标点下棋时就是异常。当 Python 解释器接收到开发者自行引发的异常时,同样会中止当前的执行流,跳到该异常对应的 except 块,由该 except 块来处理该异常。也就是说,不管是系统自动引发的异常,还是程序员于动引发的异常,Python 解释器对异常的处理没有任何差别。

即使是用户自行引发的异常,也可以使用 try except 来捕获它。当然也可以不管它,让该异常向上(先调用者)传播,如果该异常传到 Python 解释器,那么程序就会中止。

下面示例示范了处理用户引发异常的两种方式:

def main():
  try:
    # 使用try...except来捕捉异常
    # 此时即使程序出现异常,也不会传播给main函数
    mtd(3)
  except Exception as e:
    print('程序出现异常:', e)
  # 不使用try...except捕捉异常,异常会传播出来导致程序中止
  mtd(3)
def mtd(a):
  if a > 0:
    raise ValueError("a的值大于0,不符合要求")
main()

从上面程序可以看到,程序既可在调用 mtd(3) 时使用 try except 来捕获异常,这样该异常将会被 except 块捕获,不会传播给调用它的函数;也可直接调用 mtd(3),这样该函数的异常就会直接传播给它的调用函数,如果该函数也不处理该异常,就会导致程序中止。

运行上面程序,可以看到如下输出结果:

程序出现异常: a的值大于0,不符合要求
Traceback (most recent call last):
File "C:\Users\mengma\Desktop\1.py", line 13, in <module>
main()
File "C:\Users\mengma\Desktop\1.py", line 9, in main
mtd(3)
File "C:\Users\mengma\Desktop\1.py", line 12, in mtd
raise ValueError("a的值大于0,不符合要求")
ValueError: a的值大于0,不符合要求

上面第一行输出是第一次调用 mtd (3) 的结果,该方法引发的异常被 except 块捕获并处理。后面的大段输出则是第二次调用 mtd(3) 的结果,由于该异常没有被 except 块捕获,因此该异常一直向上传播,直到传给 Python 解释器导致程序中止。

第二次调用 mtd(3) 引发的以“File”开头的三行输出,其实显示的就是异常的传播轨迹信息。也就是说,如果程序不对异常进行处理,Python 默认会在控制台输出异常的传播轨迹信息。

自定义异常类

很多时候,程序可选择引发自定义异常,因为异常的类名通常也包含了该异常的有用信息。所以在引发异常时,应该选择合适的异常类,从而可以明确地描述该异常情况。在这种情形下,应用程序常常需要引发自定义异常。

用户自定义异常都应该继承 Exception 基类或 Exception 的子类,在自定义异常类时基本不需要书写更多的代码,只要指定自定义异常类的父类即可。

下面程序创建了一个自定义异常类(程序一):

class AuctionException(Exception): pass

上面程序创建了 AuctionException 异常类,该异常类不需要类体定义,因此使用 pass 语句作为占位符即可。

在大部分情况下,创建自定义异常类都可采用与程序一相似的代码来完成,只需改变 AuctionException 异常的类名即可,让该异常的类名可以准确地描述该异常。

except 和 raise 同时使用

在实际应用中对异常可能需要更复杂的处理方式。当一个异常出现时,单靠某个方法无法完全处理该异常,必须由几个方法协作才可完全处理该异常。也就是说,在异常出现的当前方法中,程序只对异常进行部分处理,还有些处理需要在该方法的调用者中才能完成,所以应该再次引发异常,让该方法的调用者也能捕获到异常。

为了实现这种通过多个方法协作处理同一个异常的情形,可以在 except 块中结合 raise 语句来完成。如下程序示范了except 和 raise 同时使用的方法:

class AuctionException(Exception): pass
class AuctionTest:
  def __init__(self, init_price):
    self.init_price = init_price
  def bid(self, bid_price):
    d = 0.0
    try:
      d = float(bid_price)
    except Exception as e:
      # 此处只是简单地打印异常信息
      print("转换出异常:", e)
      # 再次引发自定义异常
      raise AuctionException("竞拍价必须是数值,不能包含其他字符!") # ①
      raise AuctionException(e)
    if self.init_price > d:
      raise AuctionException("竞拍价比起拍价低,不允许竞拍!")
    initPrice = d
def main():
  at = AuctionTest(20.4)
  try:
    at.bid("df")
  except AuctionException as ae:
    # 再次捕获到bid()方法中的异常,并对该异常进行处理
    print('main函数捕捉的异常:', ae)
main()

上面程序中 9~13 行代码对应的 except 块捕获到异常后,系统打印了该异常的字符串信息,接着引发一个 AuctionException 异常,通知该方法的调用者再次处理该 AuctionException 异常。所以程序中的 main() 函数,也就是 bid() 方法的调用者还可以再次捕获 AuctionException 异常,井将该异常的详细描述信息打印出来。

这种 except 和 raise 结合使用的情况在实际应用中非常常用。实际应用对异常的处理通常分成两个部分:

应用后台需要通过日志来记录异常发生的详细情况;

应用还需要根据异常向应用使用者传达某种提示;

在这种情形下,所有异常都需要两个方法共同完成,也就必须将 except 和 raise 结合使用。

如果程序需要将原始异常的详细信息直接传播出去,Python 也允许用自定义异常对原始异常进行包装,只要将上面 ① 号代码改为如下形式即可:

raise AuctionException(e)

raise 不需要参数

正如前面所看到的,在使用 raise 语句时可以不带参数,此时 raise 语句处于 except 块中,它将会自动引发当前上下文激活的异常;否则,通常默认引发 RuntimeError 异常。

例如,将上面程序改为如下形式:

class AuctionException(Exception): pass
class AuctionTest:
  def __init__(self, init_price):
    self.init_price = init_price
  def bid(self, bid_price):
    d = 0.0
    try:
      d = float(bid_price)
    except Exception as e:
      # 此处只是简单地打印异常信息
      print("转换出异常:", e)
      # 再次引发自定义异常
      raise
    if self.init_price > d:
      raise AuctionException("竞拍价比起拍价低,不允许竞拍!")
    initPrice = d
def main():
  at = AuctionTest(20.4)
  try:
    at.bid("df")
  except AuctionException as ae:
    # 再次捕获到bid()方法中的异常,并对该异常进行处理
    print('main函数捕捉的异常:', ae)
main()

正如从 13 行代码所看到的,此时程序在 except 块中只是简单地使用 raise 语句来引发异常,那么该 raise 语句将会再次引发该 except 块所捕获的异常。运行该程序,可以看到如下输出结果:

转换出异常: could not convert string to float: 'df'

main 函数捕获的异常:<class 'ValueError'>

知识点补充:

演示raise用法

 

try:
   s = None
   if s is None:
     print "s 是空对象"
     raise NameError   #如果引发NameError异常,后面的代码将不能执行
   print len(s) #这句不会执行,但是后面的except还是会走到
except TypeError:
   print "空对象没有长度"
 
s = None
if s is None:
  raise NameError 
print 'is here?' #如果不使用try......except这种形式,那么直接抛出异常,不会执行到这里

触发异常

我们可以使用raise语句自己触发异常

raise语法格式如下:

raise [Exception [, args [, traceback]]]

语句中 Exception 是异常的类型(例如,NameError)参数标准异常中任一种,args 是自已提供的异常参数。

最后一个参数是可选的(在实践中很少使用),如果存在,是跟踪异常对象。到此这篇关于Python新手学习raise用法的文章就介绍到这了,更多相关Python中raise用法内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
使用Python判断IP地址合法性的方法实例
Mar 13 Python
python删除不需要的python文件方法
Apr 24 Python
Python3 利用requests 库进行post携带账号密码请求数据的方法
Oct 26 Python
python读写csv文件的方法
Aug 13 Python
Django 批量插入数据的实现方法
Jan 12 Python
keras 自定义loss model.add_loss的使用详解
Jun 22 Python
Django crontab定时任务模块操作方法解析
Sep 10 Python
浅析python字符串前加r、f、u、l 的区别
Jan 24 Python
一文搞懂如何实现Go 超时控制
Mar 30 Python
python scipy 稀疏矩阵的使用说明
May 26 Python
pycharm安装深度学习pytorch的d2l包失败问题解决
Mar 25 Python
图神经网络GNN算法
May 11 Python
Django实现任意文件上传(最简单的方法)
Jun 03 #Python
Python flask框架如何显示图像到web页面
Jun 03 #Python
python实现时间序列自相关图(acf)、偏自相关图(pacf)教程
Jun 03 #Python
tensorflow dataset.shuffle、dataset.batch、dataset.repeat顺序区别详解
Jun 03 #Python
利用python实现平稳时间序列的建模方式
Jun 03 #Python
Python ADF 单位根检验 如何查看结果的实现
Jun 03 #Python
基于Python快速处理PDF表格数据
Jun 03 #Python
You might like
十天学会php之第一天
2006/10/09 PHP
用PHP和ACCESS写聊天室(八)
2006/10/09 PHP
php下通过伪造http头破解防盗链的代码
2010/07/03 PHP
jQuery中的RadioButton,input,CheckBox取值赋值实现代码
2014/02/18 PHP
关于PHP开发的9条建议
2015/07/27 PHP
php文件系统处理方法小结
2016/05/23 PHP
ThinkPHP中session函数详解
2016/09/14 PHP
PHP上传文件及图片到七牛的方法
2018/07/25 PHP
jQuery获取地址栏参数插件(模仿C#)
2010/10/26 Javascript
JavaScript之appendChild、insertBefore和insertAfter使用说明
2010/12/30 Javascript
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
2014/07/15 NodeJs
JavaScript实现广告的关闭与显示效果实例
2015/07/02 Javascript
JavaScript jQuery 中定义数组与操作及jquery数组操作
2015/12/18 Javascript
javascript学习笔记_浅谈基础语法,类型,变量
2016/09/19 Javascript
JS实现的相册图片左右滚动完整实例
2016/11/23 Javascript
微信小程序封装http访问网络库实例代码
2017/05/24 Javascript
详解Angular-ui-BootStrap组件的解释以及使用
2018/07/13 Javascript
详解Ubuntu安装angular-cli遇到的坑
2018/09/08 Javascript
JS计算斐波拉切代码实例
2019/09/12 Javascript
javascript实现简单打字游戏
2019/10/29 Javascript
解决vue addRoutes不生效问题
2020/08/04 Javascript
[14:24]Optic Gaming vs PSG LGD BO3
2018/06/07 DOTA
Python检测一个对象是否为字符串类的方法
2015/05/21 Python
python实现壁纸批量下载代码实例
2018/01/25 Python
python3之模块psutil系统性能信息使用
2018/05/30 Python
python中bs4.BeautifulSoup的基本用法
2019/07/27 Python
Python实现报警信息实时发送至邮箱功能(实例代码)
2019/11/11 Python
解决python3插入mysql时内容带有引号的问题
2020/03/02 Python
Python3 获取文件属性的方式(时间、大小等)
2020/03/12 Python
如何在mac版pycharm选择python版本
2020/07/21 Python
python opencv实现简易画图板
2020/08/27 Python
详解Python中import机制
2020/09/11 Python
澳大利亚现代波西米亚风格女装网站:Bohemian Traders
2018/04/16 全球购物
师范毕业生自荐信
2013/10/17 职场文书
Pytorch数据读取之Dataset和DataLoader知识总结
2021/05/23 Python
使用Python拟合函数曲线
2022/04/14 Python