【问题标题】:Variable defined with with-statement available outside of with-block?用with语句定义的变量在with块之外可用吗?
【发布时间】:2011-09-19 21:56:58
【问题描述】:

考虑以下示例:

with open('a.txt') as f:
    pass
# Is f supposed to be defined here?

我已阅读有关 with-statement 和 PEP-343 的语言文档 (2.7),但据我所知,他们没有就此事发表任何意见。

在 CPython 2.6.5 中,f 似乎确实是在 with 块之外定义的,但我宁愿不依赖可能改变的实现细节。

【问题讨论】:

  • f 在封闭范围内是否可用的问题已经得到解答。对我来说,当我意识到 context 的概念与 scope 的概念不同时,上下文管理器的整个概念就被点击了。这是我网站的链接,希望对您有所帮助:markus-gattol.name/ws/python.html#context_manager
  • 完全正确 - 上下文是改变当前状态的问题 - 文件打开、文件关闭或线程锁定/解锁。设备分配/解除分配。范围内命名的所有变量仍然存在 - 但它们现在将指向已释放/关闭/解锁的句柄。

标签: python


【解决方案1】:

如果f 是一个文件,它将在with 语句之外显示为关闭。

比如这个

f = 42
print f
with open('6432134.py') as f:
    print f
print f

将打印:

42
<open file '6432134.py', mode 'r' at 0x10050fb70>
<closed file '6432134.py', mode 'r' at 0x10050fb70>

您可以在 Specification: The 'with' Statement 部分下的PEP-0343 中找到详细信息。 Python scope rules(可能是irritating)也适用于f

【讨论】:

  • 我知道这一点,我在问题中提到过。至少对于 CPython 2.6.5。但是你能保证这同样适用于 Jython、IronPython 和 PyPy 吗?
  • Python 的作用域规则也不总是那么清晰。在 CPython 2.6.5 中考虑这一点:[x for x in [1]]x 在此之外可用。把它变成一个生成器:(x for x in [1])。现在x 不可用。我似乎记得这在 Python 3 中发生了变化,因此即使使用列表理解 x 也不会泄漏,但我现在找不到参考。
  • 我搜索过,但目前还没有发现任何重要的东西。不过,这个问题很有趣。
  • 实际上这不是作用域问题——变量 f 仍然可用,但它现在是关闭状态下文件的句柄——与之前打开的文件相同。离开上下文时的退出调用会改变这个状态。
【解决方案2】:

with 语法:

with foo as bar:
    baz()

大约是糖:

try:
    bar = foo.__enter__()
    baz()
finally:
    if foo.__exit__(*sys.exc_info()) and sys.exc_info():
        raise

这通常很有用。例如

import threading
with threading.Lock() as myLock:
    frob()

with myLock:
    frob_some_more()

上下文管理器可能不止一次使用。

【讨论】:

  • 好吧,锁重用可能会也可能不会(不知道,但如果它们不同,那将是一个错误) - 但是 Python 范围规则在不同的实现中肯定是相同的。
  • 这又不是范围界定问题。范围将是相同的。但是,如果 foo.__exit__ 的实现使线程进入停止状态,那么除非 lock 有一个重新锁定它的 enter,否则第二个语句看起来不会对线程做任何有用的事情锁。
【解决方案3】:

在 cmets 中回答 Heikki 的问题:是的,这种作用域行为是 Python 语言规范的一部分,适用于所有兼容的 Python(包括 PyPy、Jython 和 IronPython)。

【讨论】:

    【解决方案4】:

    是的,上下文管理器将在 with 语句之外可用,并且不依赖于实现或版本。 with 语句创建新的执行范围。

    【讨论】:

    • 这是我认为最清楚的解释,因此授予接受的答案;将给 Alex 和 TokenMacGuy 积分以获得更多有用的信息。
    • 如果有一段时间没有使用 Python 很容易忘记一些东西,像缩进、名称和其他东西这样的功能表明你应该无法访问它,但你可以。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 2012-08-29
    • 2017-06-07
    • 1970-01-01
    • 2010-10-27
    • 2020-11-09
    相关资源
    最近更新 更多