【问题标题】:Meaning of "with" statement without "as" keyword没有“as”关键字的“with”语句的含义
【发布时间】:2014-12-08 04:22:10
【问题描述】:

我熟悉使用 python 的with 语句作为在抛出异常时确保对象最终确定的一种手段。这通常看起来像

with file.open('myfile.txt') as f:
    do stuff...

简写为

f = file.open('myfile.txt'):
try:
    do stuff...
finally:
    f.close()

或任何其他类可能存在的终结例程。

我最近遇到了一段处理 OpenGL 的代码,它展示了这个:

with self.shader:
    (Many OpenGL commands)

注意没有任何as 关键字。这是否表明该类的 __enter____exit__ 方法仍将被调用,但该对象从未在块中显式使用(即,它通过全局或隐式引用工作)?或者还有什么其他的含义让我无法理解?

【问题讨论】:

  • 如果您不需要在 with 块中为上下文管理器起别名,那很好 - 另请参见例如contextlib.suppress。严格来说,你可以做with open(...): ...,虽然你不能访问文件处理程序,所以没有什么意义!

标签: python with-statement contextmanager


【解决方案1】:

上下文管理器可以选择性地返回一个对象,该对象被分配给as命名的标识符。而as分配的是__enter__方法返回的对象,不一定是上下文管理器本身。

使用as <identifier> 有助于创建new 对象,就像open() 调用一样,但并非所有上下文管理器都是为上下文创建的。例如,它们可以重复使用并且已经创建。

建立一个数据库连接。您只需创建一次数据库连接,但许多数据库适配器允许您将连接用作上下文管理器;进入上下文并启动事务,退出并提交(成功时)或回滚(出现异常时):

with db_connection:
    # do something to the database

这里不需要创建新对象,使用db_connection.__enter__() 进入上下文并使用db_connection.__exit__() 再次退出,但我们已经拥有对连接对象的引用。

现在,可能是连接对象在您输入时产生一个光标对象。现在以本地名称分配该游标对象是有意义的:

with db_connection as cursor:
    # use cursor to make changes to the database

db_connection 仍然没有在这里调用,它之前已经存在,并且我们已经有了对它的引用。但是无论db_connection.__enter__() 生成的什么现在都分配给cursor,并且可以从那里开始使用。

这就是文件对象发生的情况; open() 返回一个文件对象,fileobject.__enter__() 返回文件对象本身,因此您可以在with 语句中使用open() 调用在一个步骤中引用新创建的对象,而不是两个。如果没有这个小技巧,您将不得不使用:

f = open('myfile.txt')
with f:
    # use `f` in the block

将所有这些应用到您的着色器示例中;您已经引用了self.shaderself.shader.__enter__() 很可能再次返回对 self.shader 的引用,但既然您已经有了一个完全可用的引用,为什么要为此创建一个新的本地?

【讨论】:

    【解决方案2】:

    上面的答案很好。

    我在阅读时不断问自己的唯一一件事是,以下场景的确认在哪里。如果在 with 语句的上下文主体中存在赋值,则赋值右侧的任何内容首先“绑定”到上下文。所以,在下面:

    with db_connection():
       result = select(...)
    

    ...select 是~ref_to_connection.select(...)

    我把这个放在这里是为了像我这样在语言之间来来往往的人,并且可能会从这里快速提醒如何阅读和跟踪参考中受益。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-12
      • 2021-10-26
      • 2011-06-09
      • 1970-01-01
      相关资源
      最近更新 更多