Rozważ następujące:
with open(path, mode) as f:
return [line for line in f if condition]
Czy plik zostanie poprawnie zamknięty, czy też użycie go return
pomija menedżera kontekstu ?
Rozważ następujące:
with open(path, mode) as f:
return [line for line in f if condition]
Czy plik zostanie poprawnie zamknięty, czy też użycie go return
pomija menedżera kontekstu ?
Odpowiedzi:
Tak, działa jak finally
blok po try
bloku, tzn. Zawsze wykonuje się (chyba że proces python zakończy się w nietypowy sposób).
Jest również wspomniany w jednym z przykładów PEP-343, który jest specyfikacją with
instrukcji:
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).
Warto jednak wspomnieć, że nie można łatwo wychwycić wyjątków zgłaszanych przez open()
połączenie bez umieszczenia całego with
bloku w try..except
bloku, który zwykle nie jest tym, czego chce.
Process.terminate()
jest to jeden z niewielu (jedynych?) Scenariuszy, który nie gwarantuje wywołania finally
instrukcji: „Pamiętaj, że procedury obsługi wyjścia i klauzule wreszcie itd. Nie będą wykonany."
with
bloku, czy gwarancja obowiązuje tak długo, jak długo generator generuje wartości? tak długo, jak cokolwiek to odwołuje? Czy muszę użyć del
lub przypisać inną wartość zmiennej, która przechowuje obiekt generatora?
ValueError: I/O operation on closed file.
.
Tak.
def example(path, mode):
with open(path, mode) as f:
return [line for line in f if condition]
.. jest prawie równoważne z:
def example(path, mode):
f = open(path, mode)
try:
return [line for line in f if condition]
finally:
f.close()
Dokładniej, __exit__
metoda w menedżerze kontekstu jest zawsze wywoływana przy wychodzeniu z bloku (niezależnie od wyjątków, zwrotów itp.). Metoda obiektu pliku __exit__
wywołuje tylko f.close()
(np. Tutaj w CPython )
finally
keywrod jest: def test(): try: return True; finally: return False
.
Tak. Mówiąc bardziej ogólnie, __exit__
metoda With Context Context Manager rzeczywiście zostanie wywołana w przypadku return
z wewnątrz kontekstu. Można to przetestować za pomocą:
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()
Dane wyjściowe to:
Entering context.
Returning inside with-statement.
EXITING context.
Powyższe dane wyjściowe potwierdzają, że __exit__
wywołano je mimo wczesnego okresu return
. W związku z tym menedżer kontekstu nie jest pomijany.
Tak, ale w innych przypadkach może wystąpić pewien efekt uboczny, ponieważ może on zrobić coś (np. Bufor opróżniania) w __exit__
bloku
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
można dodać,with
aby rozwiązać tentry with except
problem. edycja: dodano do języka