전체 파일을 읽으면 파일 핸들이 열린 상태로 유지됩니까?


372

전체 파일을 읽는 경우 content = open('Path/to/file', 'r').read()스크립트가 종료 될 때까지 파일 핸들이 열린 상태로 유지됩니까? 전체 파일을 읽는 더 간결한 방법이 있습니까?

답변:


585

이 질문에 대한 대답은 특정 Python 구현에 따라 다릅니다.

이것이 무엇인지 이해하려면 실제 file물체에 특히주의하십시오 . 코드에서 해당 객체는 표현식에서 한 번만 언급되며 바로 다음에 액세스 할 수 없게됩니다.read() 호출이 반환 된 .

이것은 파일 객체가 쓰레기라는 것을 의미합니다. 남은 유일한 질문은 "가비지 수집기가 언제 파일 개체를 수집합니까?"입니다.

참조 카운터를 사용하는 CPython에서는 이러한 종류의 가비지가 즉시 발견되므로 즉시 수집됩니다. 이것은 일반적으로 다른 파이썬 구현에는 해당되지 않습니다.

파일이 닫히도록하는 더 나은 해결책은 다음 패턴입니다.

with open('Path/to/file', 'r') as content_file:
    content = content_file.read()

블록이 끝나 자마자 항상 파일을 닫습니다. 예외가 발생하더라도.

편집 : 그것에 더 좋은 점을 두려면 :

다른보다 file.__exit__()"자동"는 호출되는, with상황에 맞는 관리자 설정, 유일한 다른 방법으로 file.close()자동으로 호출됩니다 (명시 적으로 자신을 호출하는 것보다 다른입니다,)를 통해입니다 file.__del__(). 이것은 언제 __del__()전화 를 받느냐에 대한 질문으로 이어집니다 .

올바르게 작성된 프로그램은 종료자가 프로그램 종료 전 어느 시점에서든 실행될 것이라고 가정 할 수 없습니다.

-https : //devblogs.microsoft.com/oldnewthing/20100809-00/ ? p=13203

특히:

객체는 절대 명시 적으로 파괴되지 않습니다. 그러나 도달 할 수 없게되면 가비지 수집 될 수 있습니다. 구현은 가비지 수집을 연기하거나 완전히 생략 할 수 있습니다. 수 있습니다. 여전히 도달 가능한 객체가 수집되지 않는 한 가비지 수집이 구현되는 방식의 구현 품질 문제입니다.

[...]

CPython은 현재 주기적으로 연결된 가비지에 대한 (선택적) 지연 감지와 함께 참조 계산 체계를 사용합니다.이 가비지는 대부분 객체를 도달 할 수 없게되는 즉시 수집하지만 순환 참조가 포함 된 가비지를 수집하는 것은 아닙니다.

-https : //docs.python.org/3.5/reference/datamodel.html#objects-values-and-types

(엠파 시스 마인)

그러나 제안한 것처럼 다른 구현에는 다른 동작이있을 수 있습니다. 예를 들어, PyPy 6 개의 서로 다른 가비지 콜렉션 구현을 가지고 있습니다 !


24
한동안, 실제로 다른 파이썬 구현은 없었습니다. 그러나 구현 세부 사항에 의존하는 것은 실제로 Pythonic이 아닙니다.
Karl Knechtel

여전히 구현에 특정한가요, 아니면 이미 표준화 되었습니까? __exit__()이런 경우에는 전화하지 않는 것이 디자인 결함처럼 들립니다.
rr-

2
@jgmjgm 그것은 GC가 예측할 수있는, 정확하게 때문에 그 3 문제의의, try/ finally서투른되는 및 정리 처리기의 매우 일반적인 usefulless 그 with해결한다. "명시 적으로 닫는"과 "관리하는 with" 의 차이점은 예외가 발생하더라도 종료 핸들러가 호출된다는 것입니다. close()finally절을 넣을 수는 있지만 with대신 조금 더 지저분하고 (1 대신 3 줄 추가) 올바르게 사용하는 것이 조금 더 어렵습니다.
SingleNegationElimination 4:23에서

1
내가 그것에 대해 얻지 못한 것은 'with'가 명시 적으로 아니기 때문에 더 이상 신뢰할 수있는 이유입니다. 스펙이 항상 그렇게 구현해야한다고 말했기 때문입니까?
jgmjgm

3
더 신뢰할 수 있기 때문에이있어 @jgmjgm with foo() as f: [...]기본적으로 동일하다 f = foo(), f.__enter__()[...]와 f.__exit__() 처리 예외를 제외하고 , 그래서 __exit__항상라고합니다. 따라서 파일은 항상 닫힙니다.
neingeist 2016 년

104

pathlib 를 사용할 수 있습니다 .

Python 3.5 이상의 경우 :

from pathlib import Path
contents = Path(file_path).read_text()

이전 버전의 Python의 경우 pathlib2를 사용 하십시오 .

$ pip install pathlib2

그때:

from pathlib2 import Path
contents = Path(file_path).read_text()

이것은 실제 read_text 구현입니다 .

def read_text(self, encoding=None, errors=None):
    """
    Open the file in text mode, read it, and close the file.
    """
    with self.open(mode='r', encoding=encoding, errors=errors) as f:
        return f.read()

2

글쎄, 당신은 각 줄을 사용하기 위해 한 줄씩 파일을 읽어야한다면,

with open('Path/to/file', 'r') as f:
    s = f.readline()
    while s:
        # do whatever you want to
        s = f.readline()

또는 더 나은 방법 :

with open('Path/to/file') as f:
    for line in f:
        # do whatever you want to

0

파일 내용을 단일 문자열로 검색하는 대신 파일을 구성하는 모든 줄의 목록으로 내용저장하는 것이 편리 할 수 ​​있습니다 .

with open('Path/to/file', 'r') as content_file:
    content_list = content_file.read().strip().split("\n")

보다시피, 이 스레드의 주요 답변에 연결된 메소드 .strip().split("\n")를 추가해야합니다 .

여기서는 .strip()전체 파일 문자열의 끝에서 공백과 개행 문자를 제거 .split("\n")하고 모든 줄 바꿈 문자 \ n 에서 전체 파일 문자열을 분할하여 실제 목록을 생성합니다 .

또한이 방법으로 전체 파일 내용을 변수에 저장할 수 있습니다 . 이 경우 이전 답변 에서 지적한 것처럼 파일을 한 줄씩 반복하는 대신 일부 경우에 필요할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.