2017-04-25 3 views
1

오늘 중첩 된 생성기 함수로 놀았으며 재미있는 속성/동작을 발견했습니다.중첩 된 생성기 개체 컨텍스트

어쩌면 이것은 yield from의 이해 부족과 관련이 있습니다. 그러나 이제 문제가 발생했습니다 :

def foo(): 
    for iter in range(10): 
     yield iter 

generator = foo() 

def bar(): 
    yield from generator 

print(next(bar()), end=' ') 
print(next(bar()), end=' ') 
... 

따라서 예외는 0 1 ...이됩니다.

그러나 next에 대한 첫 번째 성공적인 호출 후에, 내가 얻을 : 역 추적 (마지막으로 가장 최근 통화) : 파일 "", 줄 1 StopIteration을에

그래서 제 질문은 다음과 같습니다 발전기를 가지고 왜 이미 끝났어?

답변

6

generator 개체는 글로벌입니다. 당신은 새로운 것을 만들지 않습니다. 을 반복하거나을 종료하면 소모됩니다.

yield from을 함수로 사용했기 때문에 닫혔습니다. bar 생성기 함수가 끝나면 GeneratorExit 예외가 기본 생성기 (예 : foo() 인스턴스)로 전파되고 닫힙니다. bar()은 개체에 대한 참조가 없으므로 정리가 끝납니다. Yield expressions section 가입일

는 :

yield from <expr> 사용

, 그것은 subiterator로 제공된 식을 취급한다. 해당 하위 작성자가 생성 한 모든 값은 현재 생성기의 메서드 호출자에게 직접 전달됩니다. send()으로 전달 된 값과 throw()으로 전달 된 예외는 적절한 메소드가있는 경우 기본 iterator로 전달됩니다.

PEP-380 *Syntax for Delegating to a Subgenerator에서

:

GeneratorExit 예외가 호출 위양 발생기 또는 위임 발전기 close() 방법에 투입되는 경우가있는 경우, 다음 반복기의 close() 방법이라고

하나. 상세

은, 무슨 일이 있습니다 :

  • generator = foo() 새로운 발전기 개체를 만듭니다.
  • bar()은 다른 것을 만듭니다. 그러나이 객체에 대한 참조는 스택이 아닙니다.
  • next()은 스택에서 bar() 생성기를 가져 와서 한 단계 전달합니다.
  • next()이 반환되며 bar() 생성기에 남아있는 참조가 없으므로 삭제됩니다.
  • 생성자 개체를 삭제하면 generator.close() method이 생성되고 generator.throw()을 통해 생성자에서 GeneratorExit가 발생합니다.
  • yield from은 해당 예외를 생성자 객체 인 foo()에 전파합니다.