4

我试图理解 python 中的 with 语句。我到处都在谈论打开和关闭文件,并且旨在替换 try-finally 块。有人也可以发布一些其他示例。我只是在尝试烧瓶,里面有很多陈述。绝对要求有人提供一些澄清。

4

3 回答 3

9

with声明的想法是让“做正确的事”成为阻力最小的道路。虽然文件示例是最简单的,但线程锁实际上提供了一个更经典的非明显错误代码示例:

try:
    lock.acquire()
    # do stuff
finally:
    lock.release()

此代码已损坏 - 如果锁获取失败,则会抛出错误的异常(因为代码将尝试释放它从未获取的锁),或者更糟糕的是,如果这是一个递归锁,它将被释放早期的。正确的代码如下所示:

lock.acquire()
try:
    # do stuff
finally:
    # If lock.acquire() fails, this *doesn't* run
    lock.release()

通过使用with语句,就不可能出错,因为它内置在上下文管理器中:

with lock: # The lock *knows* how to correctly handle acquisition and release
  # do stuff

该语句有很大帮助的另一个地方with类似于函数和类装饰器的主要好处:它采用“两段”代码,可以由任意数量的代码行分隔(装饰器的函数定义,try块当前的情况)并将其转换为“单片”代码,程序员只需预先声明他们正在尝试做什么。

对于简短的示例,这看起来并不是一个很大的收获,但在审查代码时它实际上会产生巨大的差异。当我看到lock.acquire()一段代码时,我需要向下滚动并检查相应的lock.release(). 但是,当我看到with lock:时,不需要这样的检查——我可以立即看到锁将被正确释放。

于 2011-02-08T07:44:33.217 回答
9

这里有一个很好的解释。基本上,with 语句调用关联对象的两个特殊方法。__enter__ 和 __exit__ 方法。enter 方法返回与“with”语句关联的变量。而 __exit__ 方法在语句执行后调用以处理任何清理(例如关闭文件指针)。

于 2010-09-28T14:42:44.153 回答
1

withPEP343中有 12 个使用示例,包括文件打开示例:

  1. 用于确保在块开始时获取的锁在离开块时释放的模板
  2. 用于打开文件的模板,可确保在离开块时关闭文件
  3. 用于提交或回滚数据库事务的模板
  4. 示例 1 在没有生成器的情况下重写
  5. 临时重定向标准输出
  6. opens() 的变体,它也返回错误条件
  7. 另一个有用的例子是阻塞信号的操作
  8. 此功能的另一个用途是十进制上下文
  9. 这是十进制模块的简单上下文管理器
  10. 一个通用的“对象关闭”上下文管理器
  11. 一个released() 上下文,通过交换acquire() 和release() 调用来临时释放先前获得的锁
  12. 一个“嵌套”上下文管理器,它自动从左到右嵌套提供的上下文以避免过度缩进
于 2011-08-01T01:18:58.593 回答