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函数返回多个值的示例方法
Dec 04 Python
Python IDLE入门简介
Dec 08 Python
python 在屏幕上逐字显示一行字的实例
Dec 24 Python
python实现多张图片拼接成大图
Jan 15 Python
介绍一款python类型检查工具pyright(推荐)
Jul 03 Python
详解python常用命令行选项与环境变量
Feb 20 Python
Python 线性回归分析以及评价指标详解
Apr 02 Python
4行Python代码生成图像验证码(2种)
Apr 07 Python
Xadmin+rules实现多选行权限方式(级联效果)
Apr 07 Python
Python unittest生成测试报告过程解析
Sep 08 Python
Python字符串查找基本操作代码案例
Oct 27 Python
python3 通过 pybind11 使用Eigen加速代码的步骤详解
Dec 07 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采集腾讯微博的实现代码
2012/01/19 PHP
Linux+Nginx+MySQL下配置论坛程序Discuz的基本教程
2015/12/23 PHP
PHP闭包函数传参及使用外部变量的方法
2016/03/15 PHP
php的单例模式及应用场景详解
2021/02/27 PHP
Jquery.TreeView结合ASP.Net和数据库生成菜单导航条
2010/08/27 Javascript
javascript生成随机数的方法
2014/05/16 Javascript
javascript实现checkbox全选的代码
2015/04/30 Javascript
JavaScript中用toString()方法返回时间为字符串
2015/06/12 Javascript
JS实现可直接显示网页代码运行效果的HTML代码预览功能实例
2015/08/06 Javascript
基于jQuery实现返回顶部实例代码
2016/01/01 Javascript
jQuery基本筛选选择器实例代码
2017/02/06 Javascript
使用grunt合并压缩js和css文件的方法
2017/03/02 Javascript
Vue.js bootstrap前端实现分页和排序
2017/03/10 Javascript
Vue.use源码分析
2017/04/22 Javascript
使用JS动态显示文本
2017/09/09 Javascript
Angularjs实现页面模板清除的方法
2018/07/20 Javascript
mpvue+vant app搭建微信小程序的方法步骤
2019/02/11 Javascript
浅谈vue加载优化策略
2019/03/19 Javascript
NodeJS读取分析Nginx错误日志的方法
2019/05/14 NodeJs
JavaScript的Proxy可以做哪些有意思的事儿
2019/06/15 Javascript
Moment.js实现多个同时倒计时
2019/08/26 Javascript
Python求解任意闭区间的所有素数
2018/06/10 Python
Python中@property的理解和使用示例
2019/06/11 Python
Python流程控制 while循环实现解析
2019/09/02 Python
Python标准库shutil模块使用方法解析
2020/03/10 Python
python中字典增加和删除使用方法
2020/09/30 Python
Python的轻量级ORM框架peewee使用教程
2021/02/05 Python
Fossil美国官网:Fossil手表、手袋、珠宝及配件
2017/02/01 全球购物
Haggar官网:美国男装品牌
2020/02/16 全球购物
医院义诊活动总结
2014/07/04 职场文书
党支部遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
2014光棍节单身联谊活动策划书
2014/10/10 职场文书
2015年秋季校长开学典礼致辞
2015/07/29 职场文书
浅谈golang 中time.After释放的问题
2021/05/05 Golang
SQL语句中JOIN的用法场景分析
2021/07/25 SQL Server
什么是clearfix (一文搞清楚css清除浮动clearfix)
2023/05/21 HTML / CSS