파이썬에서 “with”블록으로 돌아 오면 파일이 여전히 닫히나요? return [line for line

다음을 고려하세요:

with open(path, mode) as f:
    return [line for line in f if condition]

파일이 제대로 닫혀 할 것인가, 또는 사용 않는 return바이 패스 어떻게 든 컨텍스트 매니저 ?



답변

예, 그것은 finally블록 이후의 try블록 처럼 작동합니다 . 즉, 파이썬 프로세스가 비정상적으로 종료되지 않는 한 항상 실행됩니다.

또한의 사례 중 하나에 언급 된 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에서 )


답변

예. 더 일반적으로, With Statement Context Manager__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'


답변