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 returnpomija 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 returnpomija menedżera kontekstu ?
Odpowiedzi:
Tak, działa jak finallyblok po trybloku, 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ą withinstrukcji:
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 withbloku w try..exceptbloku, który zwykle nie jest tym, czego chce.
Process.terminate()jest to jeden z niewielu (jedynych?) Scenariuszy, który nie gwarantuje wywołania finallyinstrukcji: „Pamiętaj, że procedury obsługi wyjścia i klauzule wreszcie itd. Nie będą wykonany."
withbloku, 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ć dellub 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 )
finallykeywrod 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 returnz 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'
elsemożna dodać,withaby rozwiązać tentry with exceptproblem. edycja: dodano do języka