Considérer ce qui suit:
with open(path, mode) as f:
return [line for line in f if condition]
Le fichier sera-t-il fermé correctement ou l'utilisation de return
contourne-t-elle en quelque sorte le gestionnaire de contexte ?
Oui, il agit comme le bloc finally
après un bloc try
, c’est-à-dire qu’il est toujours exécuté (sauf si le processus python se termine de façon inhabituelle).
Il est également mentionné dans l'un des exemples de PEP-34 , qui est la spécification de l'instruction 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).
Il convient toutefois de mentionner qu’il est difficile d’attraper les exceptions émises par l’appel open()
sans placer le bloc entier with
dans un bloc try..except
, Ce qui n’est généralement pas ce que l’on veut. .
Oui.
def example(path, mode):
with open(path, mode) as f:
return [line for line in f if condition]
..est à peu près équivalent à:
def example(path, mode):
f = open(path, mode)
try:
return [line for line in f if condition]
finally:
f.close()
Plus précisément, la méthode __exit__
Dans un gestionnaire de contexte est toujours appelée lors de la sortie du bloc (quelles que soient les exceptions, les retours, etc.). La méthode __exit__
De l'objet fichier appelle simplement f.close()
(par exemple ici en CPython )
Oui. Plus généralement, le __exit__
La méthode d'un With Statement Context Manager sera en effet appelée dans le cas d'un return
de l'intérieur du contexte. Cela peut être testé avec les éléments suivants:
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()
La sortie est:
Entering context.
Returning inside with-statement.
EXITING context.
La sortie ci-dessus confirme que __exit__
a été appelé malgré le début return
. En tant que tel, le gestionnaire de contexte n'est pas ignoré.
Oui, mais il peut y avoir un effet secondaire dans d'autres cas, car il peut être utile de faire quelque chose (comme vider le tampon) dans __exit__
bloc
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'