Змінна, визначена with-statement, доступна за межами with-block?


90

Розглянемо наступний приклад:

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

Я прочитав мовні документи (2.7) для with-statement, а також PEP-343, але, наскільки я можу сказати, вони нічого не говорять з цього приводу.

У CPython 2.6.5 f, здається, визначається поза блоком with, але я волію не покладатися на деталі реалізації, які можуть змінитися.


8
На питання про те, чи буде f доступним у межах, що вкладаються, вже дано відповіді. Для мене вся концепція менеджерів контексту клацнула , коли я зрозумів , що поняття контексту відрізняється , що від обсягу . Ось посилання на мій веб-сайт, яке, сподіваюся, трохи допоможе: markus-gattol.name/ws/python.html#context_manager
Том

1
Точно - контекст - це питання зміни поточного стану - файл відкритий, файл закритий або нитка заблокована / розблокована. Пристрій виділено / звільнено. Всі змінні, названі в області дії, все ще є, але тепер вони вказуватимуть на деблоковані / закриті / розблоковані дескриптори.
Danny Staple

Відповіді:


159

Так, менеджер контексту буде доступний поза оператором with, і це не залежить від реалізації чи версії. з операторами не створюють нову область виконання.


3
На мою думку, це найбільш чітке пояснення, тому присудження прийнятої відповіді; дасть бали Алексу та TokenMacGuy за додаткову корисну інформацію.
Heikki Toivonen

Щось, про що можна легко забути, якщо якийсь час не працював з Python, така функція, як відступ, ім'я та інше, передбачає, що ви не зможете отримати до нього доступ, але все ж можете.
Віталій Терзієв

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 не має введення, яке переблокує його, друге твердження не схоже на те, що це зробить щось корисне для блокування потоку.
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 у розділі Специфікація: Заява «з» . Правила обсягу Python (що може дратувати ) стосуються 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не протікало, але я зараз не можу знайти посилання.
Хейккі Тойвонен

Я шукав, але поки що не знайшов нічого суттєвого. Однак цікаве питання.
miku

Насправді це не питання сфери дії - змінна f все ще доступна, але тепер це дескриптор для подання у закритому стані - того самого файлу, який раніше був відкритий раніше. Виклик виходу, коли контекст залишиться, змінить цей стан.
Danny Staple

11

Щоб відповісти на запитання Хейккі в коментарях: так, така поведінка масштабування є частиною специфікації мови python і працюватиме на будь-якому сумісному Pythons (що включає PyPy, Jython та IronPython).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.