다음이 선호되는 이유는 정확히 한 가지입니다.
with open('filename.txt') as fp:
for line in fp:
print line
우리는 모두 가비지 콜렉션에 대한 CPython의 비교적 결정적인 참조 계산 체계에 의해 망쳐졌습니다. 다른 가설적인 파이썬의 구현은 with
다른 스키마를 사용하여 메모리를 되 찾을 경우 반드시 블록 없이 파일을 "빠르게"닫을 필요는 없습니다 .
이러한 구현에서 가비지 수집기가 분리 된 파일 핸들에서 종료자를 호출하는 것보다 코드가 파일을 빠르게 여는 경우 OS에서 "너무 많은 파일이 열렸습니다"오류가 발생할 수 있습니다. 일반적인 해결 방법은 GC를 즉시 트리거하는 것이지만 이는 해킹에 지나지 않으며 라이브러리의 오류를 포함하여 오류가 발생할 수있는 모든 함수에 의해 수행되어야합니다 . 악몽이야
아니면 그냥 with
블록을 사용할 수도 있습니다 .
보너스 질문
(문제의 객관적인 측면에만 관심이있는 경우 지금 읽기를 중지하십시오.)
파일 객체의 반복자 프로토콜에 왜 포함되어 있지 않습니까?
이것은 API 디자인에 대한 주관적인 질문이므로 두 부분으로 주관적인 답변이 있습니다.
창자 수준에 그 반복자 프로토콜을 만들기 때문에, 이것은 잘못된 느낌 할 별도의 두 가지-으로 반복 라인 이상 및 파일 가까운 핸들과 간단한 보이는 함수는 두 개의 작업을 할 수 있도록하는 것이 좋은 생각입니다. 이 경우 반복자는 파일의 내용과 유사하게 기능적인 값 기반 방식으로 관련되어 있기 때문에 특히 나쁘지만 파일 핸들 관리는 완전히 별개의 작업입니다. 하나의 행동으로 보이지 않게 두 가지를 모두 분류하는 것은 코드를 읽는 사람에게는 놀라운 일이며 프로그램 행동에 대한 추론을 어렵게 만듭니다.
다른 언어들도 본질적으로 같은 결론을 내 렸습니다. Haskell은 이른바 "게으른 IO"로 잠깐 동안 파일을 반복하여 스트림이 끝날 때 자동으로 닫히도록하지만 최근에는 Haskell에서 게으른 IO를 사용하지 않는 것이 일반적으로 바람직하지 않습니다. 사용자는 주로 Conduit과 같은보다 명시적인 리소스 관리로 이동하여 with
Python 의 블록 과 유사하게 작동 합니다.
기술적 인 수준에서 파이썬에서 파일 핸들로 할 수있는 일이있을 수 있습니다. 반복은 파일 핸들을 닫으면 잘 작동하지 않습니다. 예를 들어 파일을 두 번 반복해야한다고 가정합니다.
with open('filename.txt') as fp:
for line in fp:
...
fp.seek(0)
for line in fp:
...
이것은 일반적인 사용 사례는 아니지만, 맨 처음 세 줄을 가진 기존 코드베이스에 맨 아래에 세 줄의 코드를 추가했을 수도 있습니다. 반복이 파일을 닫으면 그렇게 할 수 없습니다. 따라서 반복과 리소스 관리를 별도로 유지하면 코드 덩어리를 더 크고 작동하는 Python 프로그램으로 쉽게 작성할 수 있습니다.
조합 성은 언어 또는 API의 가장 중요한 유용성 기능 중 하나입니다.