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用法 的相关文章

  • 为什么我不能使用“exclude”从 python 轮子中排除“tests”目录?

    考虑以下包结构 与以下setup py内容 from setuptools import setup find packages setup name dfl client packages find packages exclude te
  • Python Nose 导入错误

    我似乎无法理解鼻子测试框架 https nose readthedocs org en latest 识别文件结构中测试脚本下方的模块 我已经设置了演示该问题的最简单的示例 下面我会解释一下 这是包文件结构 init py foo py t
  • Python 在 chroot 中运行时出现错误

    我尝试在 chroot 中运行一些 Python 程序 但出现以下错误 Could not find platform independent libraries
  • Python,将迭代函数变成递归函数

    我创建了一个输出 4 3 2 1 0 1 2 3 4 的迭代函数 def bounce2 n s n for i in range n print n n n 1 if n lt 0 for i in range s 1 print n n
  • Python的reduce()短路了吗?

    If I do result reduce operator and False 1000 得到第一个结果后它会停止吗 自从False anything False 相似地 result reduce operator or True 10
  • conda 无法从 yml 创建环境

    我尝试运行下面的代码来从 YAML 文件创建虚拟 Python 环境 我在 Ubuntu 服务器上的命令行中运行代码 虚拟环境名为 py36 当我运行下面的代码时 我收到下面的消息 环境也没有被创建 这个问题是因为我有几个必须使用 pip
  • 如何从谷歌云存储桶读取音频文件并在datalab笔记本中使用ipd播放

    我想在数据实验室笔记本中播放我从谷歌云存储桶中读取的声音文件 这个怎么做 import numpy as np import IPython display as ipd import librosa import soundfile as
  • 为什么我的scoped_session 引发 AttributeError: 'Session' object has no attribute 'remove'

    我正在尝试建立一个系统 将数据库操作优雅地推迟到单独的线程 以避免在 Twisted 回调期间发生阻塞 到目前为止 这是我的方法 from contextlib import contextmanager from sqlalchemy i
  • 如何使用循环将十进制转换为二进制?

    我想编写一个程序 将十进制数 0 到 9 转换为二进制数 我可以编写如何使用重复除法将十进制数转换为二进制数的代码 但是 我在创建一个以二进制格式打印十进制数字 0 到 9 的循环时遇到了麻烦 这是我的代码 number 0 remaind
  • 网页抓取 - 前往第 2 页

    如何访问数据集的第二页 无论我做什么 它都只返回第 1 页 import bs4 from urllib request import urlopen as uReq from bs4 import BeautifulSoup as sou
  • 如何对这个 Flask 应用程序进行单元测试?

    我有一个 Flask 应用程序 它使用 Flask Restless 来提供 API 我刚刚写了一些身份验证来检查 如果消费者主机被识别 该请求包含一个哈希值 通过加密 POST 的请求内容和 GET 的 URL 以及秘密 API 密钥来计
  • 一起使用 Flask 和 Tornado?

    我是以下的忠实粉丝Flask 部分是因为它很简单 部分是因为它有很多扩展 http flask pocoo org extensions 然而 Flask 是为了在 WSGI 环境中使用而设计的 而 WSGI 不是非阻塞的 所以 我相信 它
  • 为什么“return self”返回 None ? [复制]

    这个问题在这里已经有答案了 我正在尝试获取链的顶部节点getTopParent 当我打印出来时self name 它确实打印出了父实例的名称 然而 当我回来时self 它返回 None 为什么是这样 class A def init sel
  • Spark中的count和collect函数抛出IllegalArgumentException

    当我使用时抛出此异常时 我尝试在本地 Spark 上加载一个小数据集count 在 PySpark 中 take 似乎有效 我试图搜索这个问题 但没有找到原因 看来RDD的分区有问题 有任何想法吗 先感谢您 sc stop sc Spark
  • smooth_idf 是多余的吗?

    The scikit learn 文档 http scikit learn org stable modules generated sklearn feature extraction text TfidfTransformer html
  • 如何强制 Y 轴仅使用整数

    我正在使用 matplotlib pyplot 模块绘制直方图 我想知道如何强制 y 轴标签仅显示整数 例如 0 1 2 3 等 而不显示小数 例如 0 0 5 1 1 5 2 等 我正在查看指导说明并怀疑答案就在附近matplotlib
  • 大型数据集上的 Sklearn-GMM

    我有一个很大的数据集 我无法将整个数据放入内存中 我想在这个数据集上拟合 GMM 我可以用吗GMM fit sklearn mixture GMM 重复小批量数据 没有理由重复贴合 只需随机采样您认为机器可以在合理时间内计算的尽可能多的数据
  • scipysolve_ivp() 中的访问时间步长

    我有一个常微分方程系统 正在使用 scipy 的solve ivp 函数求解 它运行良好 但我在访问每个步骤中使用的时间步时遇到问题 我知道solve ivp 将当前时间传递给用户定义的函数 但我需要使用的时间步长 而不是当前时间 为了解决
  • 在Python中从日期时间中减去秒

    我有一个 int 变量 它实际上是秒 让我们调用这个秒数X 我需要得到当前日期和时间 以日期时间格式 减去的结果X秒 Example If X是 65 当前日期是2014 06 03 15 45 00 那么我需要得到结果2014 06 03
  • 为什么用字符串和时间增量转置 DataFrame 会转换数据类型?

    这种行为对我来说似乎很奇怪 id列 字符串 在转置后转换为时间戳df如果另一列是时间增量 import pandas as pd df pd DataFrame id 00115 01222 32333 val 12 14 170 df v

随机推荐

  • 每天进步一点点之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 所以就去网上查了相关的资料