小编典典

我将不提及范围,因为它实际上并不十分相关。

with EXPR as VAR:

BLOCK

转换为

mgr = (EXPR)

exit = type(mgr).__exit__ # Not calling it yet

value = type(mgr).__enter__(mgr)

exc = True

try:

try:

VAR = value # Only if "as VAR" is present

BLOCK

except:

# The exceptional case is handled here

exc = False

if not exit(mgr, *sys.exc_info()):

raise

# The exception is swallowed if exit() returns true

finally:

# The normal and non-local-goto cases are handled here

if exc:

exit(mgr, None, None, None)

如您所见,type(mgr).__enter__就像您所期望的那样被调用,但是 不在内try。

type(mgr).__exit__在退出时被调用。唯一的区别是, 如果有异常,则采用if not exit(mgr,

*sys.exc_info())path。with与finally子句可以执行的操作不同,这提供了自省和静默错误的能力。

contextmanager没有这个复杂 得多 。只是:

def contextmanager(func):

@wraps(func)

def helper(*args, **kwds):

return _GeneratorContextManager(func, *args, **kwds)

return helper

然后看一下有问题的课程:

class _GeneratorContextManager(ContextDecorator):

def __init__(self, func, *args, **kwds):

self.gen = func(*args, **kwds)

def __enter__(self):

try:

return next(self.gen)

except StopIteration:

raise RuntimeError("generator didn't yield") from None

def __exit__(self, type, value, traceback):

if type is None:

try:

next(self.gen)

except StopIteration:

return

else:

raise RuntimeError("generator didn't stop")

else:

if value is None:

value = type()

try:

self.gen.throw(type, value, traceback)

raise RuntimeError("generator didn't stop after throw()")

except StopIteration as exc:

return exc is not value

except:

if sys.exc_info()[1] is not value:

raise

不重要的代码已被删除。

首先要注意的是,如果存在多个yield,则此代码将出错。

这不会明显影响控制流程。

考虑一下__enter__。

try:

return next(self.gen)

except StopIteration:

raise RuntimeError("generator didn't yield") from None

如果上下文管理器写得很好,那将永远不会超出预期。

一个区别是,如果生成器抛出StopIteration,RuntimeError将产生不同的错误()。这意味着,with如果您运行的是完全任意的代码,则行为与正常情况并不完全相同。

考虑一个没有错误的__exit__:

if type is None:

try:

next(self.gen)

except StopIteration:

return

else:

raise RuntimeError("generator didn't stop")

唯一的区别是和以前一样。如果您的代码抛出StopIteration,它将影响生成器,因此contextmanager装饰器将误解它。

这意味着:

from contextlib import contextmanager

@contextmanager

def with_cleanup(func):

try:

yield

finally:

func()

def good_cleanup():

print("cleaning")

with with_cleanup(good_cleanup):

print("doing")

1/0

#>>> doing

#>>> cleaning

#>>> Traceback (most recent call last):

#>>> File "", line 15, in

#>>> ZeroDivisionError: division by zero

def bad_cleanup():

print("cleaning")

raise StopIteration

with with_cleanup(bad_cleanup):

print("doing")

1/0

#>>> doing

#>>> cleaning

这不太重要,但是可以。

最后:

else:

if value is None:

value = type()

try:

self.gen.throw(type, value, traceback)

raise RuntimeError("generator didn't stop after throw()")

except StopIteration as exc:

return exc is not value

except:

if sys.exc_info()[1] is not value:

raise

这就引起了关于的相同问题StopIteration,但是有趣的是注意到了最后一部分。

if sys.exc_info()[1] is not value:

raise

这意味着,如果未处理异常,则回溯将保持不变。如果已处理但存在 新的 回溯,则将引发该回溯。

这完全符合规格。

TL; DR

with实际上try...finally,它比a的功能要强大得多,因为它with可以进行内省并保持沉默。

请当心StopIteration,但是您可以使用它@contextmanager来创建上下文管理器。

2020-12-20

python一个try块后接一个或多个finally块_Python * with *语句是否完全等同于try-(例外)-finally块?...相关推荐

  1. 高频模拟混频器模块,功能为一个AD835乘法器+后级一个10KHz的低通滤波器,输入可以撑到100MHz,输出带宽10KHz

    高频模拟混频器模块,功能为一个AD835乘法器+后级一个10KHz的低通滤波器,输入可以撑到100MHz,输出带宽10KHz ID:62119638128398781UncleJack

  2. 高频模拟混频器模块,功能为一个AD835乘法器+后级一个10KHz的低通滤波器

    高频模拟混频器模块,功能为一个AD835乘法器+后级一个10KHz的低通滤波器,输入可以撑到100MHz,输出带宽10KHz ID:62119638128398781

  3. python一个try块后接一个或多个finally块_Effective Python(13): 合理利用try/except/else/finally结构中的每个代码块...

    一.Python的异常处理机制 Python的异常处理要考虑四种不同的时机,可用try.except.else和finally块来表述. 1. finally块 如果: 既要将异常向上传播 又要在异常 ...

  4. python一个try块后接一个或多个finally块_五、Python try except finally:资源回收

    Python 中,finally 语句是与 try 和 except 语句配合使用的,其通常是用来做清理工作的.无论 try 中的语句是否跳入 except 中,最终都要进入 finally 语句,并 ...

  5. python一个try块后接一个或多个finally块_Python *与*语句完全等同于一个try – (除了) – finally块?...

    我会放弃提及的范围,因为它真的不是很相关. with EXPR as VAR: BLOCK 翻译成 mgr = (EXPR) exit = type(mgr).__exit__ # Not calli ...

  6. textedit 内容刷新_QT中如何让一个按钮单击后更新一个TextEdit

    我的程序如下,想让BUTTON CLICKED后让pTextEdit2显示pTextEdit1的内容,不知道哪里做错了 才用QT,不是很了解,希望大家帮忙看看 #include #include #i ...

  7. 萌新的Python练习实例100例(三)一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数

    题目: 一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少? 分析: 根据题目得出: 整数x²=i+100,y²=i+100+168 采用for in 遍历为i ...

  8. python一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?

    runoob100-003 1.题目 2.分析 代码 运行 1.题目 一个整数i,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?(假设该数位于-10000到10000 ...

  9. python做的游戏放到微信_【1、 创建一个python的文件,运行后,文字版方式模拟微信游戏“跳一跳?】...

    python脚本学习过程推荐 学习流程: 一:打础 1.找到合适的书籍(推荐Python核心编程2Dive into Python),大致读一次,循环啊判,常用类啊,搞懂(太难的跳过) 2.勤练习py ...

最新文章

  1. Windows10下SSH远程拷贝文件
  2. 【最爽的日期工具包LocalDate·超爽,超实用】(Java8版本)
  3. 现有工程项目上加响应式
  4. PHPCMS V9 按浏览次数排行调用文章
  5. linux命令:watch 、lsmod、mdadm 创建软RAID
  6. js中while死循环语句_如何检测JavaScript中的死循环?
  7. 分区怎么4k对齐_电脑升级SSD后,依然卡顿怎么解决?
  8. BCB使用线程删除目录中的图片
  9. 割裂的前端工程师--- 2017年前端生态窥探
  10. 【手掌识别】基于matlab形态学手掌长宽检测【含Matlab源码 1382期】
  11. android文件存储的有点,快速理解Android文件存储路径
  12. 终于解决了x64 win7上运行金山词霸的问题
  13. 【DB2报错】执行存储过程报SQLSTATE:-811 SQLCODE:21000,怎么办?
  14. 在linux下如何显示隐藏文件
  15. MySQL 名次查询
  16. keepalived结合nginx主备高可用实现
  17. 【微信小程序】全局数据共享
  18. AGC012B Splatter Painting
  19. sql优化之:批量处理和分批处理
  20. 人形机器人视觉处理——定位抓取

热门文章

  1. [高数][高昆轮][高等数学上][第二章-导数与微分]01.导数的定义
  2. ffmpeg 基本数据结构和对象: AVPacket、AVPicture、AVFrame
  3. 6.3 Spring Boot集成mongodb开发
  4. C++14尝鲜:Generic Lambdas(泛型lambda)
  5. 安卓5.0API的特性,多了些什么
  6. Grub及内核的简单介绍安装
  7. 初涉SQL Server性能问题(1/4):服务器概况
  8. 这种事都有?建行网银把Demo版的放上线了?!
  9. oracle索引优劣,ORACLE的五种表的优缺点概述
  10. php 只能输入中英文,JavaScript基于正则实现控制输入框中只能输入中文、数字和英文的方法...