2017-05-16 6 views
9

다음 Python 2.x 코드 스 니펫을 고려하십시오. 내가 특별히 __exit__ 통화에 대한 관심with 문 및 context manager의 __exit__ 메소드에서 내림차순

Line 1 from file 
Before del 
__exit__ called 
After del 

:이 스크립트의

from __future__ import print_function 


class myfile(file): 
    def __exit__(self, *excinfo): 
     print("__exit__ called") 
     super(myfile, self).__exit__(*excinfo) 


def my_generator(file_name): 
    with myfile(file_name) as fh: 
     for line in fh: 
      yield line.strip() 


gen = my_generator('file.txt') 
print(next(gen)) 
print("Before del") 
del gen 
print("After del") 

출력은 (주어진 file.txt를 하나 개 이상의 라인을 가지고).

그의 메소드 실행을 트리거하는 요인은 무엇입니까? 우리가 아는 한, 코드는 결코 with 문장을 남기지 않았습니다. (이것은 yield 문장 이후에 "멈추었"고 결코 계속되지 않았습니다). 제너레이터의 레퍼런스 카운트가 0으로 떨어지면 __exit__이 호출 될 것입니다.

+2

두 번째 다음 호출은 아직 미미한 예제의 나머지 부분이었습니다. 코드 스 니펫을 수정했는데 정확합니다. –

+1

이 질문은 CPython에 관한 것입니까? – MSeifert

+0

의미 적으로는 'finally'를 갖는 것과 유사합니다. https://www.python.org/dev/peps/pep-0343/ –

답변

4

, 파이썬 통화 close 메서드를 사용하여 예외를 발생시키고 아직 실행을 완료하지 않은 경우 마지막 yield 시점에 예외를 발생시킵니다. 이 GeneratorExit이 전파되면 사용 된 컨텍스트 관리자의 __exit__ 메서드가 트리거됩니다.

파이썬 2.5, in the same PEP as send and yield expressions에서 소개되었습니다. 그 전에는 을 에 넣고 finally으로 만들 수 없었고 with 문이 2.5보다 먼저 존재했다면 내부에 yield을 작성할 수 없었을 것입니다.

1

@user2357112's answer에 추가하려면 with 블록이 내부에서 예외가 발생하면 차단됩니다. 이 예외는 컨텍스트에 대해 작성된 객체의 __exit__ 메소드에 전달됩니다.

클래스는 신호가 없기 때문에 GeneratorExit 예외를 자동으로 전달하는 것처럼 보입니다.

class myfile(file): 
    def __exit__(self, *excinfo): 
     print("__exit__ called") 
     print(excinfo[0]) # Print the reason why the context exited 
     super(myfile, self).__exit__(*excinfo) 

출력 스크립트의 : 당신이 당신의 myfile.__exit__ 방법에 argc를 인쇄 할 경우, 당신은 문맥이 자연스럽게 폐쇄되지 않았 음을 볼 수

발전기 개체의 간척에
Line 1 from file 
Before del 
__exit__ called 
<type 'exceptions.GeneratorExit'> 
After del