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实现从web抓取文档的方法
Sep 26 Python
纯Python开发的nosql数据库CodernityDB介绍和使用实例
Oct 23 Python
基于python中staticmethod和classmethod的区别(详解)
Oct 24 Python
基于python中pygame模块的Linux下安装过程(详解)
Nov 09 Python
python 递归深度优先搜索与广度优先搜索算法模拟实现
Oct 22 Python
用python脚本24小时刷浏览器的访问量方法
Dec 07 Python
Python爬虫如何应对Cloudflare邮箱加密
Jun 24 Python
Python自动巡检H3C交换机实现过程解析
Aug 14 Python
python 密码学示例——凯撒密码的实现
Sep 21 Python
Matplotlib中rcParams使用方法
Jan 05 Python
Jupyter notebook 更改文件打开的默认路径操作
May 21 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
centos 5.6 升级php到5.3的方法
2011/05/14 PHP
PHP快速按行读取CSV大文件的封装类分享(也适用于其它超大文本文件)
2014/04/10 PHP
In Javascript Class, how to call the prototype method.(three method)
2007/01/09 Javascript
JS查看对象功能代码
2008/04/25 Javascript
javascript来定义类的规范小结
2010/11/19 Javascript
超棒的响应式布局jQuery插件Freetile.js
2014/11/17 Javascript
Javascript字符串浏览器兼容问题分析
2014/12/01 Javascript
js实现点击向下展开的下拉菜单效果代码
2015/09/01 Javascript
AngularJS自动表单验证
2016/02/01 Javascript
基于JavaScript实现右键菜单和拖拽功能
2016/11/28 Javascript
JavaScript使用简单正则表达式的数据验证功能示例
2017/01/13 Javascript
详解vue-cli与webpack结合如何处理静态资源
2017/09/19 Javascript
Vue.js实现表格渲染的方法
2018/09/07 Javascript
原生JS forEach()和map()遍历的区别、兼容写法及jQuery $.each、$.map遍历操作
2019/02/27 jQuery
vue实现公共方法抽离
2020/07/31 Javascript
javascript解析json格式的数据方法详解
2020/08/07 Javascript
Javascript如何实现扩充基本类型
2020/08/26 Javascript
[00:55]深扒TI7聊天轮盘语音出处3
2017/05/11 DOTA
Python学习笔记(一)(基础入门之环境搭建)
2014/06/05 Python
Python自动化构建工具scons使用入门笔记
2015/03/10 Python
Python爬虫获取整个站点中的所有外部链接代码示例
2017/12/26 Python
Pipenv一键搭建python虚拟环境的方法
2018/05/22 Python
djang常用查询SQL语句的使用代码
2019/02/15 Python
Python开启线程,在函数中开线程的实例
2019/02/22 Python
使用Python快乐学数学Github万星神器Manim简介
2019/08/07 Python
微信小程序实现可实时改变转速的css3旋转动画实例代码
2018/09/11 HTML / CSS
有机婴儿毛毯和衣服:Monica + Andy
2020/03/01 全球购物
房地产融资计划书
2014/01/10 职场文书
校园演讲稿汇总
2014/05/21 职场文书
超市创意活动方案
2014/08/15 职场文书
党的群众路线教育实践活动个人剖析材料
2014/10/07 职场文书
2015年幼儿园班主任个人工作总结
2015/10/22 职场文书
毕业生就业推荐表自我鉴定
2019/06/20 职场文书
浙江省杭州市平均工资标准是多少?
2019/07/09 职场文书
2019年房屋委托租赁合同范本(通用版)!
2019/07/17 职场文书
python文件目录操作之os模块
2021/05/08 Python