当前异常上下文掩盖了先前的错误

2024-05-06

以下是我在 Doug Hellman 网站上名为“masking_exceptions_catch.py​​”的文件中找到的示例。我暂时无法找到链接。 throws() 中引发的异常将被丢弃,而 cleanup() 中引发的异常将被报告。

道格在他的文章中指出,这种处理方式并不直观。在编写它时(大约 2009 年),我预计它是 Python 版本中的一个错误或限制,因此我在 Mac 版 Python 的当前生产版本 (2.7.6) 中运行了它。它仍然报告来自 cleanup() 的异常。我觉得这有点令人惊奇,并且希望看到关于它实际上是正确或理想的行为的描述。

#!/usr/bin/env python

import sys
import traceback

def throws():
    raise RuntimeError('error from throws')

def nested():
    try:
        throws()
    except:
        try:
            cleanup()
        except:
            pass # ignore errors in cleanup
        raise # we want to re-raise the original error

def cleanup():
    raise RuntimeError('error from cleanup')

def main():
    try:
        nested()
        return 0
    except Exception, err:
        traceback.print_exc()
        return 1

if __name__ == '__main__':
    sys.exit(main())

程序输出:

$ python masking_exceptions_catch.py
Traceback (most recent call last):
  File "masking_exceptions_catch.py", line 24, in main
    nested()
  File "masking_exceptions_catch.py", line 14, in nested
    cleanup()
  File "masking_exceptions_catch.py", line 20, in cleanup
    raise RuntimeError('error from cleanup')
RuntimeError: error from cleanup

绕回来回答。我首先不回答你的问题。 :-)

这真的有效吗?

def f():
    try:
        raise Exception('bananas!')
    except:
        pass
    raise

那么,上面的作用是什么呢?提示危险音乐。


好吧,把铅笔放下来。

# python 3.3
      4     except:
      5         pass
----> 6     raise
      7 

RuntimeError: No active exception to reraise

# python 2.7
      1 def f():
      2     try:
----> 3         raise Exception('bananas!')
      4     except:
      5         pass

Exception: bananas!

嗯,那是富有成果的。为了好玩,让我们尝试命名异常。

def f():
    try:
        raise Exception('bananas!')
    except Exception as e:
        pass
    raise e

现在怎么办?

# python 3.3
      4     except Exception as e:
      5         pass
----> 6     raise e
      7 

UnboundLocalError: local variable 'e' referenced before assignment

# python 2.7
      4     except Exception as e:
      5         pass
----> 6     raise e
      7 

Exception: bananas!

异常语义在 python 2 和 3 之间发生了相当大的变化。但是,如果 python 2 的行为让您感到惊讶,请考虑一下:它基本上与 python 在其他地方的行为一致。

try:
    1/0
except Exception as e: 
    x=4
#can I access `x` here after the exception block?  How about `e`?

try and except不是范围。事实上,Python 中几乎没有什么东西;我们有“LEGB 规则”来记住四个命名空间——本地、封闭、全局、内置。其他块根本不是范围;而是范围。我可以很高兴地宣布x在一个for循环并期望在该循环之后仍然能够引用它。

所以,尴尬。是否应该对异常进行特殊处理以将其限制在其封闭的词汇块中? Python 2 说不,Python 3 说yes http://www.python.org/dev/peps/pep-3110/#semantic-changes。但我在这里把事情过于简单化了;裸raise是你最初问的问题,这些问题密切相关,但实际上并不相同。蟒蛇3could已强制规定命名异常的范围仅限于其块,而不涉及裸露的异常raise thing.

裸露是什么意思raise do‽

常见用法是使用裸raise作为保留堆栈跟踪的一种方法。接住,记录/清理,再加注。很酷,我的清理代码没有出现在回溯中,99.9% 的时间都有效。但是,当我们尝试在异常处理程序中处理嵌套异常时,事情可能会出问题。有时。(请参阅底部的示例,了解何时存在/不存在问题)

凭直觉,无需争论raise将正确处理嵌套异常处理程序,并找出要重新引发的正确“当前”异常。但这并不完全是现实。事实证明 - 在这里进入实现细节 - 异常信息被保存为当前的成员框架对象 https://docs.python.org/2/reference/datamodel.html#frame-objects。在 python 2 中,根本没有管道来处理单帧内堆栈上的推送/弹出异常处理程序;只是一个包含最后一个异常的字段,无论我们对它做了什么处理。就是这样裸露的raise grabs.

6.9. 加薪声明 https://docs.python.org/2/reference/simple_stmts.html#the-raise-statement

raise_stmt ::= "raise" [expression ["," expression ["," expression]]]

如果不存在表达式,则 raise 重新引发最后一个异常 活跃于当前scope.

所以,是的,这是 python 2 中的一个深层问题,与如何存储回溯信息有关 - 在 Highlander 传统中,只能有一个(回溯对象保存到给定的堆栈帧)。结果,光秃秃的raise重新引发当前框架认为是“最后”的异常,这不一定是我们人类大脑认为是我们当时所处的词法嵌套异常块所特有的异常。呸,scopes!

那么,在 python 3 中修复了吗?

是的。如何?新的字节码指令 https://docs.python.org/3.2/library/dis.html#opcode-POP_EXCEPT(实际上,除了处理程序之外,还有两个隐式的)但谁在乎呢——这一切都“直观地起作用”。而不是得到RuntimeError: error from cleanup,你的示例代码引发RuntimeError: error from throws正如预期的那样。

我无法给你一个官方原因,解释为什么它没有包含在 python 2 中。这个问题已经是已知的自 PEP 344 起 http://www.python.org/dev/peps/pep-0344/,其中提到 Raymond Hettinger 在2003。如果我必须guess,解决这个问题是一个重大变化(除其他外,它影响了sys.exc_info),这通常是不在次要版本中这样做的充分理由。

如果您使用的是 python 2,则选项:

1)命名您想要重新引发的异常,然后只需处理添加到堆栈跟踪底部的一两行即可。你的例子nested函数变为:

def nested():
    try:
        throws()
    except BaseException as e:
        try:
            cleanup()
        except:
            pass 
        raise e

以及相关的回溯:

Traceback (most recent call last):
  File "example", line 24, in main
    nested()
  File "example", line 17, in nested
    raise e
RuntimeError: error from throws

所以,回溯被改变了,但它有效。

1.5)使用 3 参数版本raise。很多人不知道这个,它是保存堆栈跟踪的合法(如果笨重)方法。

def nested():
    try:
        throws()
    except:
        e = sys.exc_info()
        try:
            cleanup()
        except:
            pass 
        raise e[0],e[1],e[2]

sys.exc_info给我们一个包含(类型、值、回溯)的三元组,这正是 3 参数版本的内容raise需要。请注意,此 3-arg 语法仅适用于 python 2。

2)重构您的清理代码,使其无法possibly抛出未处理的异常。请记住,这一切都是关于scopes- 移动那个try/except out of nested并转化为它自己的功能。

def nested():
    try:
        throws()
    except:
        cleanup()
        raise

def cleanup():
    try:
        cleanup_code_that_totally_could_raise_an_exception()
    except:
        pass

def cleanup_code_that_totally_could_raise_an_exception():
    raise RuntimeError('error from cleanup')

现在您不必担心;因为异常从未发生过nested的范围,它不会干扰您打算重新引发的异常。

3)裸露使用raise就像您在阅读所有这些内容并接受它之前所做的那样;清理代码通常不会引发异常,对吧? :-)

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

当前异常上下文掩盖了先前的错误 的相关文章

  • 从 RabbitMQ 迁移到 Amazon SQS [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我们的初创公司目前正在使用RabbitMQ with Python Django 对于消息队列 现在我们计划转移到Amazon SQS其高可用性
  • 将 3D 矩阵转换为级联 2D 矩阵

    我有一个3Dpython中的矩阵如下 import numpy as np a np ones 2 2 3 a 0 0 0 2 a 0 0 1 3 a 0 0 2 4 我想转换这个3D矩阵到一组2D矩阵 我努力了np reshape但这并没
  • numba.prange 性能不佳

    我试图整理一个简单的例子来说明使用的好处numba prange对于我自己和一些同事来说 但我无法获得像样的加速 我编写了一个简单的一维扩散求解器 它本质上是在一个长数组上循环 组合元素i 1 i and i 1 并将结果写入element
  • 在 Windows 7 上安装 Python Fabric 时出现问题

    我正在尝试使用以下指南在 Windows 7 上安装 Python Fabric在 Windows 上安装 Python 和 Fabric http www jonnyreeves co uk 2011 08 getting python
  • python 队列获取大小,使用 qsize() 还是 len()?

    我见过这样的例子qsize and len 已用于计算队列的大小 两者有什么区别 对于大多数容器 您需要len but Queue Queue实际上并不支持len 这可能是因为它很旧 或者因为在多线程环境中获取队列的长度并不是特别有用 无论
  • 使用 Pandas 解析时避免 Excel 的科学记数法舍入

    我有一个自动生成的 Excel 文件 其中偶尔包含非常大的数字 例如135061808695 在 Excel 文件中 当您单击单元格时 它会显示完整的数字135061808695然而 在视觉上 使用自动 常规 格式 数字显示为1 35063
  • Boost Python:多态容器?

    我有一个方法 或函数 它返回对多态对象列表的引用 class A class B public A std list
  • 从日志文件 python 创建 csv 标题

    我的日志文件每行都包含一些信息 如下所示 Info1 NewOrder key 123 Info3 10 Info5 abc Info3 10 Info1 OldOrder key 456 Info6 xyz Info1 NewOrder
  • f.read 为空

    我在解释器中完成这一切 loc1 council council1 file1 open loc1 r 此时我可以执行 file1 read 并将文件的内容作为字符串打印到标准输出 但如果我添加这个 string1 file1 read 字
  • 如何在 Pandas 中将多列乘以一列

    我想拥有 df income 1 income 2 df mtaz proportion 返回这些列乘以df mtaz proportion 这样我就可以设置 df mtaz income 1 mtaz income 2 df income
  • 如果“pip install”有效,为什么还要“sudo pip install”? (HelloAnalytics.py 的问题)

    Google 提供了一个示例 HelloAnalytics py 来演示如何使用谷歌 API python 客户端 https pypi org project google api python client 标题下方 2 安装客户端库
  • 如何从包含许多表的 Excel 工作表中解析数据帧(使用 Python,可能使用 Pandas)

    我正在处理布局糟糕的 Excel 工作表 我正在尝试解析这些工作表并将其写入数据库 每个工作表可以有多个表 尽管这些可能的表格的标题是已知的 但哪些表格将位于任何给定的工作表上 它们在工作表上的确切位置也不是已知的 表格不以一致的方式对齐
  • 如何使用 Anaconda Python 执行 .py 文件?

    我刚刚在我的 Windows 计算机上下载并安装了 Anaconda 但是 我在使用命令提示符执行 py 文件时遇到问题 如何让我的计算机了解 python exe 应用程序位于 Anaconda 文件夹中 以便它可以执行我的 py 文件
  • 在地图类型中创建 DataFrame 分组列

    My 数据框具有以下结构 df spark createDataFrame B a 10 B b 20 C c 30 Brand Type Amount df show Brand Type Amount B a 10 B b 20 C c
  • 使用不同的 CMD 名称同时运行多个 python 脚本

    我尝试通过 multiprocessing Process 在 test py 中同时调用 a py 和 b py 它起作用了 但过程CMDa py b py 和 test py 的名称相同 均为 usr bin python tmp te
  • 使用 scipy.io 将 python pandas dataframe 转换为 matlab 结构

    我正在尝试使用 scipy io 将 pandas 数据帧保存到 matlab mat 文件 我有以下内容 array1 np array 1 2 3 array2 np array a b c array3 np array 1 01 2
  • 为什么 `Pool.map()` 多处理中的内存消耗急剧增加?

    我正在对 pandas 数据帧进行多重处理 方法是将其拆分为多个数据帧 这些数据帧存储为列表 并且 使用Pool map 我将数据帧传递给定义的函数 我的输入文件约为 300 mb 因此小数据帧大约为 75 mb 但是 当多处理运行时 内存
  • 如何在seaborn displot上绘制正态曲线

    distplot 已被弃用 取而代之的是 displot 之前的函数可以选择绘制正态曲线 import seaborn as sns import matplotlib pyplot as plt from scipy import sta
  • 选择 matplotlib xticks 频率

    我正在用字符串作为 x 标签绘制数据 我想控制标签频率 以免文本使轴过载 在下面的示例中 我只想每 3 个刻度看到一个标签 a d g j 我可以做到这一点的一种方法是每 n 个元素用 2 个空字符串替换 my xticks 元素 但我确信
  • Python FFmpeg查询rtsp太慢

    目前 我正在尝试使用 python 和 FFmpeg 来查询原始格式为 h264 的 rtsp 数据 直播流视频的信息为 fps 29 分辨率 1280 720 我希望我可以以相同的格式 h264 查询数据并将其放入python队列中以便将

随机推荐

  • 保护浏览器帮助程序对象

    我目前正在构建浏览器帮助程序对象 其中一件事是BHO要做的就是发出绕过跨域策略的跨站请求 为此 我公开一个 MyBHONameSpace Request使用的方法WebClient内部 然而 我发现任何使用我的 BHO 的人现在到处都有 C
  • 如何从 NetService 获取 IP 地址

    当我得到一个 NetService 对象时 我尝试这样做 NSNetService ss netArray objectAtIndex indexPath row ss delegate self ss resolveWithTimeout
  • WPF 应用程序在每个系统规模上具有相同的大小(与规模无关)

    有没有办法让 WPF 应用程序在每个系统规模上获得相同的大小 当我改变时更改文本 应用程序和其他项目的大小在windows系统设置中125 推荐 to 100 在全高清屏幕中 我的 WPF 应用程序变得太小 为了实现独立的系统缩放应用程序
  • 如何重置rabbitmq管理用户

    使用rabbitmq 我们可以安装管理插件 然后我们通过浏览器访问http localhost 55672 使用访客 访客 问题是 我无法再登录 因为我更改了密码并为角色输入了空白 有没有办法重置rabbitmq管理的用户 您可以通过以下方
  • qemu kvm:如何获取性能监控中断?

    我在操作系统内核中编写了一些函数 以便在指令计数器溢出时发出性能监控中断 PMI 它在我的机器 Intel core i5 上运行良好 但是当我使用 qemu 在 qemu 上运行它时 qemu system x86 64 enable k
  • DISM.exe 返回代码?

    我有一个程序调用 dism exe 程序 它在后台运行一些命令 现在 我只检查返回代码 0 或其他任何内容 以显示进程失败或成功 我可以用什么来交叉检查返回代码以获得准确的返回错误 DISM 参考了哪些回报 评论中提供的链接DISMAPI
  • 如何让号码保持最新号码而不是回到默认号码?

    我的 TxnNo A0010001 来自 Unitcode A001 LastTxnNo 0001 这是我的按钮点击 Db Save setOnClickListener new View OnClickListener Override
  • SQL Server 中 SYSDATETIME 数据类型的准确性

    我已经在 SQL Server 2008 的存储过程中使用 SYSDATETIME 进行了一些测试 我设置了一个包含带有 IDENTITY 字段的 datetime2 7 的表 我了解这种数据类型的精度和准确度之间的差异 但是 在从此示例中
  • 如何在声明模块中导出构造函数

    我想使用内联样式前缀 例如 var InlineStylePrefixer require inline style prefixer var prefixer new InlineStylePrefixer userAgent var s
  • javascript 中的独立括号[重复]

    这个问题在这里已经有答案了 可能的重复 JavaScript 为什么使用匿名函数包装器 https stackoverflow com questions 1643321 javascript why the anonymous funct
  • 构造函数中的同步块

    我有一个带有静态变量的类 如下所示 private static Object sMyStaticVar 如果我想在构造函数中为这个 var 赋值 我有这样的代码 if sMyStaticVar null sMyStaticVar new
  • Dockerfile:在单行中设置多个环境变量

    我的印象是环境变量可以设置在一行上 如下所示 以尽量减少中间图像 FROM alpine 3 6 ENV RUBY MAJOR 2 4 RUBY VERSION 2 4 1 RUBY DOWNLOAD SHA256 4fc8a9992de3
  • Crashlytics 未报告任何前台 OOM

    我通过增加一个无限大的 NSStrings NSArray 造成了 OOM 崩溃 我什至尝试过调用exit 0 只是为了让它看起来像 OOM 虽然这些事情可以意外终止应用程序 但我没有看到 Crashlytics 上报告的任何 OOM 并且
  • 如何最小化两个子多边形的最大纵横比?

    我想使用直线将凸多边形切成给定面积比的两部分 以使两个子多边形的较大纵横比最小化 目前我的方法包括选择一个随机起点 计算将多边形分割成目标区域的适当终点 然后计算两个纵横比中较大的一个 然后重复这个很多次 直到我足够接近最小值 多边形 A
  • Web 服务错误“提供的 URI 方案‘http’无效;需要‘https’。”

    我的服务调用导致以下错误 提供的 URI 方案 http 无效 需要 https 应用程序配置值
  • 触发器和行版本控制信息

    在什么情况下表触发器会导致在行末尾添加 14 个字节以进行行版本控制 数据行中使用的空间 部分在本页 http msdn microsoft com en us library ms175492 aspx明确指出 每个数据库行可以在行末尾使
  • 如何修复错误“无法连接到远程进程。正在中止调试会话。”更新到 Android Studio 4.2.1 后

    我将 Android studio 更新到 4 2 1 但没有进行调试 但我无法执行此操作 因为此消息正在等待应用程序上线 com example myapplication com example myapplication test 一
  • JavaScript 使用多少位来表示数字?

    JavaScript 使用多少位来表示数字 一般JS实现使用64位双精度浮点数 对 32 位整数执行按位运算
  • ASP.Net Core 1.0支持WebForm项目吗

    Does ASP NET核心1 0支持 Net WebForm项目吗 或者它是一个仅 MVC 的环境 我还可以在那里创建经典的网络服务 asmx 吗 简短回答 不 ASP NET Core 不包含 Web 表单或 Web 服务 长答案 取决
  • 当前异常上下文掩盖了先前的错误

    以下是我在 Doug Hellman 网站上名为 masking exceptions catch py 的文件中找到的示例 我暂时无法找到链接 throws 中引发的异常将被丢弃 而 cleanup 中引发的异常将被报告 道格在他的文章中