withブロックの外で使用できるwithステートメントで定義された変数?


88

次の例について考えてみます。

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ブロックの外で定義されているようですが、変更される可能性のある実装の詳細には依存しません。


8
囲みスコープでfが使用可能かどうかの質問にはすでに回答済みです。私はのコンセプトことに気づいたときに私のためにコンテキストマネージャの全体のコンセプトは、クリックされたコンテキストがのそれと異なっている範囲。ここに私のウェブサイトへのリンクがあり、少しは役に立てれば幸いです:markus-gattol.name/ws/python.html#context_manager
Tom

1
まさに-コンテキストは、現在の状態(ファイルが開いている、ファイルが閉じている、またはスレッドがロック/ロック解除されている)を変更することの問題です。デバイスの割り当て/割り当て解除。スコープで指定されたすべての変数はまだ存在していますが、割り当て解除/クローズ/ロック解除されたハンドルを指すようになります。
ダニーステープル

回答:


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 '21 / 06/21

1
これもスコーピングの問題ではありません。スコープは同じです。ただし、foo .__ exit__の実装によりスレッドが停止状態になった場合、lockにEnter入力して再ロックしない限り、2番目のステートメントはスレッドロックに役立つことは何もないように見えます。
ダニーステープル2013

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はまだ使用可能ですが、現在は閉じた状態のファイルへのハンドルです-以前に開いていたのと同じファイルです。コンテキストが離れたときの出口呼び出しは、この状態を変更します。
ダニーステープル2013

11

コメントでのHeikkiの質問に答えるために:はい、このスコープ動作はPython言語仕様の一部であり、準拠しているすべてのPython(PyPy、Jython、IronPythonを含む)で動作します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.