2011-06-21 40 views
53

請看下面的例子:with with語句在with-block之外是否可用定義變量?

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

我已閱讀與語句以及PEP-343,但據我可以告訴他們不要說在這個問題上的任何語言的文檔(2.7) 。

在CPython 2.6.5中f確實看起來是在with-block之外定義的,但我寧願不依賴於可能改變的實現細節。

+4

f在封閉範圍內是否可用的問題已經得到解答。對於我來說,當我意識到* context *的概念不同於* scope *的概念時,上下文管理器的整個概念就會被點擊。這是一個鏈接到我的網站,希望有一點幫助:http://www.markus-gattol.name/ws/python.html#context_manager – Tom

+0

確切地說 - 上下文是一個改變當前狀態的問題 - 文件打開,文件關閉或線程鎖定/解鎖。設備分配/解除分配。所有在範圍內命名的變量仍然存在 - 但現在它們將指向釋放/關閉/解鎖的句柄。 –

回答

96

是的,上下文管理器將在with語句之外提供,並且不依賴於實現或版本。用語句不要創建一個新的執行範圍。

+2

在我看來,這是最明確的解釋,因此授予接受的答案;將給Alex和TokenMacGuy指出其他有用的信息。 –

11

如果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的細節: '與' 聲明Python scope rules(可能是irritating)也適用於f

+0

我知道這個,我在問題中提到過。至少CPython 2.6.5。但是,你能保證Jython,IronPython和PyPy同樣適用嗎? –

+0

Python的範圍規則並不總是那麼清晰。在CPython 2.6.5中考慮這一點:'[x for x in [1]]'。外面有'x'。把它變成一個生成器:'(x for [1])''。現在'x'不可用。我似乎記得在Python 3中這已經發生了變化,因此即使使用列表理解'x'也不會泄漏,但我現在找不到參考。 –

+0

我搜索了,但現在還沒有發現任何重要的東西。有趣的問題,雖然。 – miku

17

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() 

上下文管理器可以是使用一種以上一旦。

+0

你確定這將在Jython,IronPython和PyPy中工作嗎? –

+0

好吧,鎖的重用可能會也可能不會(沒有想法,但如果它們不同,它會是一個錯誤) - 但是跨實現的Python範圍規則在這裏肯定是相同的。 – fuzzyman

+1

這再次不是範圍問題。範圍將是相同的。但是,如果foo .__ exit__的實現將線程置於停止狀態,那麼除非鎖具有重新鎖定它的__enter__,否則第二個語句看起來不像對線程鎖有用。 –

8

回答Heikki的問題:是的,這個範圍界定行爲是python語言規範的一部分,可以在任何和所有兼容的python(包括PyPy,Jython和IronPython)上工作。