with语句定义的变量在with-block之外可用吗?


88

考虑以下示例:

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

我已经阅读过带声明的语言文档(2.7)以及PEP-343,但据我所知,他们对此事一言不发。

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


8
f在封闭范围内是否可用的问题已经得到解答。对我来说,当我意识到的概念上下文管理的整个概念点击背景是到不同的范围。这里是我的网站的链接,希望可以帮助一点:markus-gattol.name/ws/python.html#context_manager
汤姆

1
确实-上下文是更改当前状态的问题-文件打开,文件关闭或线程锁定/解锁。设备已分配/取消分配。范围内命名的所有变量仍然存在-但它们现在将指向已释放/关闭/未锁定的句柄。
Danny Staple

Answers:


158

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


3
我认为这是最清晰的解释,因此请给予接受的答案。将给Alex和TokenMacGuy积分以获取其他有用的信息。
Heikki Toivonen

如果一段时间未使用Python,可能会轻易忘记,缩进,名称和内容之类的功能表明您应该无法访问它,但是仍然可以。
Vitaliy Terziev,

28

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范围规则在这里在实现上肯定是相同的。
Fuzzyman

1
这又不是范围问题。范围将是相同的。但是,如果foo .__ exit__的实现将线程置于停止状态,则除非lock具有将其重新锁定的enter,否则第二条语句看起来不会对线程锁产生任何有用的作用。
Danny Staple

16

如果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>

您可以在PEP-0343的“ 规范:'with'语句”部分下找到详细信息。Python范围规则(可能会令人讨厌)也适用f


我知道这一点,我在问题中提到了它。至少对于CPython 2.6.5。但是,您可以保证Jython,IronPython和PyPy同样适用吗?
Heikki Toivonen

Python的范围规则也不总是那么清楚。在CPython的2.6.5考虑这个问题:[x for x in [1]]x在那之外可用。使其成为生成器:(x for x in [1])。现在x不可用。我似乎记得在Python 3中对此进行了更改,因此即使有了列表理解x也不会泄漏,但是我现在找不到引用。
Heikki Toivonen

我进行了搜索,但暂时没有发现任何重要信息。有趣的问题。
miku

实际上,这不是范围问题-变量f仍然可用,但现在它是处于关闭状态的文件的句柄-以前打开过的文件相同。离开上下文时的退出调用将更改此状态。
Danny Staple 2013年

11

要在评论中回答Heikki的问题:是的,这种范围界定行为是python语言规范的一部分,并且可以在所有兼容的Python(包括PyPy,Jython和IronPython)上使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.