Розглянемо наступне:
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блоку, який зазвичай не є тим, чого хочеться.
Process.terminate()це один з небагатьох (єдиних?) Сценаріїв, який не гарантує виклик finallyзаяви: "Зауважте, що обробники виходу та нарешті пункти тощо не будуть страчений ».
withблоку, чи зберігається гарантія, поки генератор зберігає врожайні значення? доки що-небудь посилається на це? Тобто мені потрібно використовувати delабо призначити інше значення змінній, яка містить об’єкт генератора?
ValueError: I/O operation on closed file..
Так.
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 )
finallykeywrod є: def test(): try: return True; finally: return False.
Так. Більш загально, __exit__метод менеджера контексту із заявою дійсно буде викликаний у випадку returnзсередини контексту. Це можна перевірити за допомогою наступного:
class MyResource:
def __enter__(self):
print('Entering context.')
return self
def __exit__(self, *exc):
print('EXITING context.')
def fun():
with MyResource():
print('Returning inside with-statement.')
return
print('Returning outside with-statement.')
fun()
Вихід:
Entering context.
Returning inside with-statement.
EXITING context.
Вихідний результат підтверджує те, що __exit__було викликано, незважаючи на ранній return. Таким чином, менеджер контексту не обходить стороною.
Так, але в інших випадках може бути якийсь побічний ефект, оскільки він може щось робити (наприклад, промивний буфер) в __exit__блоці
import gzip
import io
def test(data):
out = io.BytesIO()
with gzip.GzipFile(fileobj=out, mode="wb") as f:
f.write(data)
return out.getvalue()
def test1(data):
out = io.BytesIO()
with gzip.GzipFile(fileobj=out, mode="wb") as f:
f.write(data)
return out.getvalue()
print(test(b"test"), test1(b"test"))
# b'\x1f\x8b\x08\x00\x95\x1b\xb3[\x02\xff' b'\x1f\x8b\x08\x00\x95\x1b\xb3[\x02\xff+I-.\x01\x00\x0c~\x7f\xd8\x04\x00\x00\x00'
elseможна було б додати,withщоб вирішити цюtry with exceptпроблему. редагувати: додано до мови