为什么这个上下文管理器与字典理解的行为不同?

2024-04-23

我有一个上下文装饰器,完成后会产生副作用。我注意到,如果我使用字典理解,就不会出现副作用。

from contextlib import contextmanager
import traceback
import sys

accumulated = []

@contextmanager
def accumulate(s):
    try:
        yield
    finally:
        print("Appending %r to accumulated" % s)
        accumulated.append(s)

def iterate_and_accumulate(iterable):
    for item in iterable:
        with accumulate(item):
            yield item

def boom_unless_zero(i):
    if i > 0:
        raise RuntimeError("Boom!")

try:
    {i: boom_unless_zero(i) for i in iterate_and_accumulate([0, 1])}
except:
    traceback.print_exc()

print(accumulated)

print('\n=====\n')

try:
    {i: boom_unless_zero(i) for i in iterate_and_accumulate([0, 1])}
except:
    traceback.print_exc()

print(accumulated)
print('Finished!')

Output:

$ python2 boom3.py 
Appending 0 to accumulated
Traceback (most recent call last):
  File "boom3.py", line 25, in <module>
    {i: boom_unless_zero(i) for i in iterate_and_accumulate([0, 1])}
  File "boom3.py", line 25, in <dictcomp>
    {i: boom_unless_zero(i) for i in iterate_and_accumulate([0, 1])}
  File "boom3.py", line 22, in boom_unless_zero
    raise RuntimeError("Boom!")
RuntimeError: Boom!
[0]

=====

Appending 0 to accumulated
Appending 1 to accumulated
Traceback (most recent call last):
  File "boom3.py", line 34, in <module>
    {i: boom_unless_zero(i) for i in iterate_and_accumulate([0, 1])}
  File "boom3.py", line 34, in <dictcomp>
    {i: boom_unless_zero(i) for i in iterate_and_accumulate([0, 1])}
  File "boom3.py", line 22, in boom_unless_zero
    raise RuntimeError("Boom!")
RuntimeError: Boom!
[0, 0, 1]
Finished!
Appending 1 to accumulated

奇怪的是,副作用是在我的脚本“完成”后发生的。这意味着如果用户使用字典理解,则无法使用我的 contextdecorator。

我注意到这种行为在 Python 3 上消失了,如果我写的话这种行为也不会发生[boom_unless_zero(i) for i in iterate_and_accumulate([0, 1])]而不是字典理解。

为什么会出现这种情况?


From https://docs.python.org/2/reference/simple_stmts.html#the-yield-statement https://docs.python.org/2/reference/simple_stmts.html#the-yield-statement:

从 Python 版本 2.5 开始,yield 语句现在允许出现在 try ...finally 构造的 try 子句中。如果生成器在最终确定之前没有恢复(通过达到零引用计数或被垃圾收集),则将调用生成器迭代器的 close() 方法,从而允许执行任何挂起的 finally 子句。

换句话说,待生成器迭代器关闭之前,挂起的finally子句不会执行,无论是显式关闭还是由于垃圾收集(引用计数或循环)而关闭。看来 Python 2 列表推导式和 Python 3 在垃圾回收可迭代方面更有效。

如果您想明确关闭生成器迭代器:

from contextlib import closing

try:
    with closing(iter(iterate_and_accumulate(a))) as it:
        {i: boom_unless_zero(i) for i in it}
except:
    traceback.print_exc()
print(accumulated)

我研究了根本问题;看来问题在于生成器迭代器由异常回溯状态保持,因此另一个解决方法是调用sys.exc_clear():

import sys

try:
    {i: boom_unless_zero(i) for i in iterate_and_accumulate(a)}
except:
    traceback.print_exc()
    try:
        sys.exc_clear()
    except AttributeError:
        pass
print(accumulated)

在 Python 3 中,词法异常处理系统(http://bugs.python.org/issue3021 http://bugs.python.org/issue3021) 意味着异常状态在退出处理程序块时被清除,因此sys.exc_clear()没有必要(而且确实不存在)。

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

为什么这个上下文管理器与字典理解的行为不同? 的相关文章

  • 如何在groupby之后将pandas数据框拆分为许多列

    我希望能够在 pandas 中使用 groupby 按列对数据进行分组 然后将其拆分 以便每个组都是数据框中自己的列 e g time data 0 1 2 0 1 2 3 0 2 3 4 0 3 1 2 1 4 2 3 1 5 3 4 1
  • 对打开文件的脚本进行单元测试

    我编写了一个脚本 它打开一个文件 读取内容并进行一些操作和计算 并将它们存储在集合和字典中 我该如何为这样的事情编写单元测试 我的问题具体是 我会测试文件是否打开 文件很大 这是unix字典文件 我如何对计算进行单元测试 我真的必须手动计算
  • 如何在 C# 中捕获等待的异步方法的异常?

    我基本上想知道在 C 中我应该如何捕获通过等待的异步方法的异常await关键词 例如 考虑以下小控制台程序 其中最重要的是包含一个名为AwaitSync AwaitSync calls TestAsync 它返回一个任务 执行时会抛出异常
  • multiprocessing.freeze_support()

    为什么多处理模块需要调用特定的function http docs python org dev library multiprocessing html multiprocessing freeze support在被 冻结 以生成 Wi
  • 使用 Python 中的 IAM 角色访问 AWS API Gateway

    我有一个 AWS API 网关 我想使用它来保护其安全IAM 角色 http docs aws amazon com apigateway latest developerguide permissions html 我正在寻找一个包来帮助
  • 我有一个 Employee 类,我想返回“姓名”列表

    我有一个 Employee 类 我想返回 姓名 列表 雇员 py class Employee object def init self id name members None self id id self name name self
  • 以编程方式将列名称添加到 numpy ndarray

    我正在尝试将列名称添加到 numpy ndarray 然后按名称选择列 但这不起作用 我无法判断问题是在添加名称时出现 还是在稍后尝试调用它们时出现 这是我的代码 data np genfromtxt csv file delimiter
  • 如何检查包含 NaN 的列表 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 在我的 for 循环中 我的代码生成一个如下所示的列表 list 0 0 0 0 sum 0 0 0 0 该循环生成所有其他数字向量 但它也
  • 如何将同步函数包装在异步协程中?

    我在用着aiohttp https github com aio libs aiohttp构建一个 API 服务器 将 TCP 请求发送到单独的服务器 发送 TCP 请求的模块是同步的 对于我来说是一个黑匣子 所以我的问题是这些请求阻塞了整
  • 如何在 Keras 中使用部分输入进行训练,其余部分用于损失函数

    我是 Keras 新手 正在尝试实现神经网络机器学习模型 输入张量看起来像 X1 X2 和输出 Y 注意 X1 和 X2 是相关的 在模型中 只有 X1 将用于训练 但 X1 和 X2 都将传递给损失函数 该损失函数是 X1 X2 y pr
  • 将具有不同大小的行的数据加载到 Numpy 数组中

    假设我有一个包含如下数据的文本文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 如何将它加载到 numpy 数组中 使其看起来像这样 1 2 3 4 5 0 6 7 8 0 0 0 9 1
  • 从 python 中的缩进文本文件创建树/深度嵌套字典

    基本上 我想迭代一个文件并将每行的内容放入一个深层嵌套的字典中 其结构由每行开头的空格数量定义 本质上 目标是采取这样的事情 a b c d e 并将其变成这样的东西 a b c d e Or this apple colours red
  • 在 Python 中,如何获取特定文件中定义的类列表?

    如果一个文件myfile py包含 class A object Some implementation class B object Some implementation 我如何定义一个方法 以便在给定的情况下myfile py 它返回
  • 与函数复合 UniqueConstraint

    一个快速的 SQLAlchemy 问题 我有一个 文档 类 其属性为 数字 和 日期 我需要确保没有重复的号码同年 是 有没有办法对 数字 年份 日期 进行UniqueConstraint 我应该使用唯一索引吗 我如何声明功能部分 SQLA
  • python 中的基本矩阵转置

    我尝试了 python 中矩阵转置的最基本方法 但是 我没有得到所需的结果 接下来是代码 A 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 print A def TS A B A for i in range len A
  • 向伪 shell (pty) 发出命令

    我尝试使用 subprocess popen os spawn 来运行进程 但似乎需要伪终端 import pty master slave pty openpty os write master ls l 应该发送 ls l 到从属终端
  • Windows 与 Linux 文本文件读取

    问题是 我最近从 Windows 切换到 Ubuntu 我的一些用于分析数据文件的 python 脚本给了我错误 我不确定如何正确解决 我当前仪器的数据文件输出如下 Header 有关仪器等的各种信息 Data 状态 代码 温度 字段等 0
  • SpaCy 中的自定义句子边界检测

    我正在尝试在 spaCy 中编写一个自定义句子分段器 它将整个文档作为单个句子返回 我编写了一个自定义管道组件 它使用以下代码来执行此操作here https github com explosion spaCy issues 1850 但
  • 将数组从 .npy 文件读入 Fortran 90

    我使用 Python 以二维数组 例如 X 的形式生成一些初始数据 然后使用 Fortran 对它们进行一些计算 最初 当数组大小约为 10 000 x 10 000 时 np savetxt 在速度方面表现良好 但是一旦我开始增加数组的维
  • 如何抑制 Pandas Future 警告?

    当我运行该程序时 Pandas 每次都会给出如下所示的 未来警告 D Python lib site packages pandas core frame py 3581 FutureWarning rename with inplace

随机推荐