파이썬에서 "with"블록으로 돌아 오면 파일이 여전히 닫히나요?


답변:


238

예, 그것은 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없다는 것입니다.


8
else이 문제 with를 해결하기 위해 추가 될 수 있습니다 try with except. 편집 : 언어에 추가
rplnt

7
관련성이 있는지는 모르겠지만 내 지식 Process.terminate()에 따르면 finally명령문 의 호출을 보장하지 않는 몇 가지 (유일한가?) 시나리오 중 하나입니다 . "종료 처리기 및 finally 절 등은 처형. "
Rik Poggi

@RikPoggi os._exit는 때때로 사용됩니다. 정리 처리기를 호출하지 않고 Python 프로세스를 종료합니다.
Acumenus

2
아마도 뱀을 조금 도발하지만 with블록 내에서 생성기 표현식을 반환하면 생성기 가 값을 계속 유지하는 한 보증은 유지됩니까? 아무것도 참조하는 한? 즉 del, 생성기 객체를 보유하는 변수에 다른 값 을 사용 하거나 할당 해야 합니까?
ack

1
@davidA 파일을 닫은 후에도 여전히 참조에 액세스 할 수 있습니다. 그러나 참조 를 사용 하여 파일에서 데이터를 가져 오거나 파일로 푸시 하려는 시도 는 다음을 제공 ValueError: I/O operation on closed file.합니다.
RWDJ

36

예.

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에서 )


30
finallykeywrod 로부터 얻는 보장을 보여주는 흥미로운 실험 은 다음과 같습니다 def test(): try: return True; finally: return False.
Ehsan Kia

20

예. 더 일반적으로, 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. 따라서 컨텍스트 관리자는 무시되지 않습니다.


4

예, 그러나 다른 경우에는 부작용이있을 수 있습니다. __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'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.