Рассмотрим следующее:
with open(path, mode) as f:
return [line for line in f if condition]
Будет ли файл закрыт должным образом или с помощью return
каким-то образом обходит контекстный менеджер ?
Рассмотрим следующее:
with open(path, mode) as f:
return [line for line in f if condition]
Будет ли файл закрыт должным образом или с помощью return
каким-то образом обходит контекстный менеджер ?
Да, он действует как блок finally
после блока try
, т.е. он всегда выполняется (если процесс python не заканчивается необычным образом).
Это также упоминается в одном из примеров PEP-343, который является спецификацией для оператора with
:
with locked(myLock):
# Code here executes with myLock held. The lock is
# guaranteed to be released when the block is left (even
# if via return or by an uncaught exception).
Однако стоит упомянуть то, что вы не можете легко перехватывать исключения, вызванные вызовом open()
, не помещая весь блок with
внутри блока try..except
, который обычно не тот, который вам нужен.
Да.
def example(path, mode):
with open(path, mode) as f:
return [line for line in f if condition]
.. в значительной степени эквивалентен:
def example(path, mode):
f = open(path, mode)
try:
return [line for line in f if condition]
finally:
f.close()
Точнее, метод __exit__
в менеджере контекста всегда вызывается при выходе из блока (независимо от исключений, возвратов и т.д.). Метод файла __exit__
просто вызывает f.close()
(например, здесь, в CPython)
В более общем плане, метод __exit__
с оператором контекста Statement действительно будет вызываться в случае return
от внутри контекста. Это можно протестировать следующим образом:
class Resource(object):
def __enter__(self):
print('Entering context.')
return self
def __exit__(self, *exc):
print('Exiting context.')
def fun():
with Resource():
print('Returning inside with-statement.')
return
print('Returning outside with-statement.')
fun()
Вывод:
Entering context.
Returning inside with-statement.
Exiting context.
Вышеприведенный вывод подтверждает, что __exit__
был вызван, несмотря на ранний return
. Таким образом, менеджер контекста не обходит.