Python中raise…from用法

2023-05-16

本来这几天是计划阅读string模块的源码,恰好其中一段异常处理的代码我觉得很新奇,也就是raise…from的用法,raise的用法大家都知道。因为我之前没遇到过,所以就去网上查了相关的资料,自己试验一下。

我阅读的这段代码取自于string模块的Formatter类的format方法,源码如下:

class Formatter:
    def format(*args, **kwargs):
        if not args:
            raise TypeError("descriptor 'format' of 'Formatter' object "
                            "needs an argument")
        self, *args = args  
        try:
            format_string, *args = args 
        except ValueError:
            if 'format_string' in kwargs:
                format_string = kwargs.pop('format_string')
                import warnings
                warnings.warn("Passing 'format_string' as keyword argument is "
                              "deprecated", DeprecationWarning, stacklevel=2)
            else:
                raise TypeError("format() missing 1 required positional "
                                "argument: 'format_string'") from None
        return self.vformat(format_string, args, kwargs)

在异常捕获的else分支中,用到了raise…from的语法。而且这里比较特别的是raise…from None。我之前一直不知道这样的用法,所以就自己试验了一下。

例如我们直接用两段代码来对比一下。

try:
    raise IndexError
except Exception as e:
    raise ValueError

这里就是我们常见的异常捕获的写法,不过在下面的捕获中又引发了一个新的异常,报错信息如下。

Traceback (most recent call last):
File “E:/pythonlab/test127.py”, line 2, in <module>
raise IndexError
IndexError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “E:/pythonlab/test127.py”, line 4, in <module>
raise ValueError
ValueError

try:
    raise IndexError
except Exception as e:
    raise ValueError from e

再用raise…from的语法试试。

Traceback (most recent call last):
File “E:/pythonlab/test127.py”, line 2, in <module>
raise IndexError
IndexError

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

Traceback (most recent call last):
File “E:/pythonlab/test127.py”, line 4, in <module>
raise ValueError from e
ValueError

对比发现其实差别在于提示信息的不同

  • During handling of the above exception, another exception occurred:
  • The above exception was the direct cause of the following exception:

前一个是 在处理上述异常期间,发生了另一个异常。

后者为 上述异常是以下异常的直接原因。

try:
    raise IndexError
except Exception as e:
    raise ValueError from None

而如果将其改为from None,那么报错如下。

Traceback (most recent call last):
File “E:/pythonlab/test127.py”, line 4, in <module>
raise ValueError from None
ValueError

此时报错提示信息也简洁了很多。

现在再分析一下其原理。

当在 except 块或者 finally 块中出现异常时(包括使用单独的 raise 重新抛出异常的情况),之前的异常会被附加到新异常的 __context__ 属性上。

而在其他任何地方抛出异常,都不会设置 __context__ 属性。
这样打印出来的异常信息就会包含这么一句话:During handling of the above exception, another exception occurred:。

raise A from B

raise A from B 语句用于连锁 chain 异常。
from 后面的 B 可以是:

  • 异常类
  • 异常实例
  • None(Python 3.3 的新特性)

如果 B 是异常类或者异常实例,那么 B 会被设置为 A 的 __cause__ 属性,表明 A异常 是由 B异常 导致的。
这样打印出来的异常信息就会包含这样一句话:The above exception was the direct cause of the following exception:。
与此同时,在 Python 3.3 中 A异常 的 __suppress_context__ 属性会被设置为 True,这样就抑制了 A异常 的 __context__ 属性,即忽略 __context__ 属性。
于是 Python 就不会自动打印异常上下文 exception context,而是使用 __cause__ 属性来打印异常的引发者。

在 Python 3.3 中,B 还可以是 None:raise A异常 from None。
这样相当于把 __suppress_context__ 属性设置为 True,从而禁用了 __context__ 属性,Python 不会自动展示异常上下文。

下面是Python中所有异常的基类BaseException类的代码。

class BaseException(object):
    """ Common base class for all exceptions """
    def with_traceback(self, tb): # real signature unknown; restored from __doc__
        """
        Exception.with_traceback(tb) --
            set self.__traceback__ to tb and return self.
        """
        pass
 
    def __delattr__(self, *args, **kwargs): # real signature unknown
        """ Implement delattr(self, name). """
        pass
 
    def __getattribute__(self, *args, **kwargs): # real signature unknown
        """ Return getattr(self, name). """
        pass
 
    def __init__(self, *args, **kwargs): # real signature unknown
        pass
 
    @staticmethod # known case of __new__
    def __new__(*args, **kwargs): # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass
 
    def __reduce__(self, *args, **kwargs): # real signature unknown
        pass
 
    def __repr__(self, *args, **kwargs): # real signature unknown
        """ Return repr(self). """
        pass
 
    def __setattr__(self, *args, **kwargs): # real signature unknown
        """ Implement setattr(self, name, value). """
        pass
 
    def __setstate__(self, *args, **kwargs): # real signature unknown
        pass
 
    def __str__(self, *args, **kwargs): # real signature unknown
        """ Return str(self). """
        pass
 
    args = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
 
    __cause__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception cause"""
 
    __context__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """exception context"""
 
    __suppress_context__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
 
    __traceback__ = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
 
    __dict__ = None # (!) real value is ''

这样就可以理解得更加深刻些了。引用网上的总结。

在异常处理程序或 finally 块中引发异常,Python 会为异常设置上下文,可以手动通过 with_traceback() 设置其上下文,或者通过 from 来指定异常因谁引起的。这些手段都是为了得到更友好的异常回溯信息,打印清晰的异常上下文。若要忽略上下文,则可以通过 raise ... from None 来禁止自动显示异常上下文。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python中raise…from用法 的相关文章

随机推荐

  • 每天进步一点点之Android基础(3)—— Activity的onNewIntent

    onNewIntent 的触发时间 xff1a 如图所示 xff0c onCreate 和 onNewIntent 不会被同时调用 如果在 AndroidManifest xml 中 xff0c 将 Activity 的 launchMod
  • 重载全局new和delete

    程序代码 如下所示 xff1a span class token macro property span class token directive keyword include span span class token string
  • Android LottieAnimationView 源码分析(仅包含加载和缓存机制)

    使用 mLottieAnimationView 61 rootView findViewById R id lottie anim layout 此处的animRes 为R raw 文件 mLottieAnimationView setAn
  • xstart使用方法

    出处 xff1a 点击打开链接 有时工作中 xff0c 我们需要用到Linux图形用户界面环境进行一些操作 xff08 比如装Oracle数据库等等 xff09 xff0c 这时就需要用xstart远程连接linux图形用户界面 xff0c
  • 资源网站-转自知乎

    作者 xff1a 吴剃中 链接 xff1a https zhuanlan zhihu com p 21479053 来源 xff1a 知乎 著作权归作者所有 商业转载请联系作者获得授权 xff0c 非商业转载请注明出处 一 找资源利器 PS
  • java网络故障报修系统J2EE

    目 录 第一章 绪论 1 1 1 课题开发背景 1 1 2 课题研究意义 1 1 3 本课题主要工作 1 第二章 相关技术介绍 3 2 1 JSP技术 3 2 2 MySQL数据库 3 2 3 J2EE 技术 4 2 4 B S架构 5 第
  • linux脚本中的命令command not found的原因及解决方法

    场景描述 xff1a 一个生产的数据库备份脚本 xff0c 使用定时任务crontab配置自动执行bakup sh xff0c 报错信息是 expdp xff1a command not found 可是 xff0c 我在linux中 xf
  • ubuntu防火墙安装和设置-ufw

    ubuntu防火墙使用的是iptables 为了简化iptables设置 xff0c ubuntu提供了一个名为ufw的工具 本文主要介绍ufw使用方法 如果ufw没有安装 xff0c 那么可以使用如下命令安装 xff1a sudo apt
  • Win10/11+Ubuntu 双系统 修改grub默认启动选项 | 默认等待时间

    文章目录 进入Ubuntu xff0c 修改配置更新配置 本文环境为Win11 43 Ubuntu22 04 进入Ubuntu xff0c 修改配置 span class token function sudo span span clas
  • 2022-08-14 SSH 相关命令详解

    SSH 相关命令详解 sshssh keygenssh copy idssh agent 和 ssh addssh keyscansshd ssh ssh OpenSSH 远端登陆客户端 xff0c 默认22端口 描述 xff1a span
  • 浅谈Centos用户权限管理

    一 用户与组的概念 1 xff0e 理解linux多用户 xff0c 多任务的特性 Linux是一个真实的 完整的多用户多任务操作系统 xff0c 多用户多任务就是可以在系统上建立多个用户 xff0c 而多个用户可以在同一时间内登录同一个系
  • Linux centos升级nodejs,解决升级NodeJS遇到的问题,升级GLIBC、GLIBCXX、gcc(含资源包下载)

    公司网站用的Nuxt开发的 xff0c 本地开发环境NodeJS已经升级到16 14 2版本 xff0c 服务器也要从12版本升级到16 14 2 如需本次安装的资源 xff0c 请下滑到文章下面下载整套资源 NodeJS版本下载地址 xf
  • 关于UEFI引导的理解

    UEFI 和 Legacy区别 UEFT和Legacy是引导模式 xff0c 是用来引导系统的 按下开机键到看到windows标识 Legacy 传统BIOS模式 xff0c 启动顺序 xff1a 开机 gt BIOS初始化 gt BIOS
  • IDEA license server 地址

    旧地址 xff1a http jetbrains license server 新地址 xff1a http fls jetbrains agent com
  • 线性探测再散列

    哈希表又称散列表 哈希表存储的基本思想是 xff1a 以数据表中的每个记录的关键字 k为自变量 xff0c 通过一种函数H k 计算出函数值 把这个值解释为一块连续存储空间 xff08 即数组空间 xff09 的单元地址 xff08 即下标
  • 特征选择的几种方法

    目录 1 过滤法 xff08 Filter xff09 1 1 方差选择法 1 2 相关系数法 1 3 卡方检验 1 4 互信息法 1 5 relief算法 2 包裹法 xff08 Wrapper xff09 2 1 递归特征消除法 2 2
  • Excel调用有道词典实现批量翻译

    如图所示 xff0c 我们在B2单元格中写入公式 xff1a 61 FILTERXML WEBSERVICE 34 http fanyi youdao com translate amp i 61 34 amp A2 amp 34 amp
  • Python的使用技巧:any all的短路

    注意迭代类型和list的结果是不一样的 xff1a if name 61 61 39 main 39 a 61 1 2 3 if any print i is None for i in a print 6666666666 1 2 3 6
  • curl升级到7.87(centos7和TencentOS2.4 tk)

    centos7升级curl到7 8 7 按照之前写过的一篇文章 大致按描述操作即可 只不过需要做一点点修正 CentOS 7升级curl 乐大师的博客 CSDN博客 centos7 curl升级 更新操作中会报错安装失败 提示如下 nbsp
  • Python中raise…from用法

    本来这几天是计划阅读string模块的源码 xff0c 恰好其中一段异常处理的代码我觉得很新奇 xff0c 也就是raise from的用法 xff0c raise的用法大家都知道 因为我之前没遇到过 xff0c 所以就去网上查了相关的资料