PEP 288 – 제너레이터 속성과 예외
- Author:
- Raymond Hettinger <python at rcn.com>
- Status:
- Withdrawn
- Type:
- Standards Track
- Created:
- 21-Mar-2002
- Python-Version:
- 2.5
- Post-History:
Table of Contents
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
이 PEP는 실행 중인 제너레이터에 예외를 발생시키고 데이터를 공유하는 메커니즘을 제공하여 제너레이터를 개선할 것을 제안합니다.
상태
이 PEP는 철회되었습니다. 예외 발생 메커니즘은 확장되어 PEP 343에 흡수되었습니다. 속성 전달 기능은 지지를 얻지 못했고, 명확한 구현이 없었으며, 실행 중인 제너레이터가 자기 자신의 네임스페이스에 접근할 깔끔한 방법도 없었습니다.
근거
현재는 클래스 기반 이터레이터만 속성과 예외 처리를 제공할 수 있습니다. 그러나 클래스 기반 이터레이터는 작성하기 더 어렵고, 덜 간결하며, 가독성이 떨어지고, 더 느립니다. 더 나은 해결책은 이러한 기능을 제너레이터에서도 사용할 수 있게 하는 것입니다.
속성 대입을 허용하면 실행 중인 제너레이터와 데이터를 주고받을 수 있습니다. 속성을 사용하여 데이터를 공유하는 방식은 Python 전반에 널리 퍼져 있습니다. 다른 방식도 있지만, 그에 비하면 다소 편법적입니다.
또 하나의 발전 단계는 제너레이터에 예외를 전달할 수 있게 하는 제너레이터 메서드를 추가하는 것입니다. 현재는 제너레이터 외부에서 예외를 일으킬 깔끔한 방법이 없습니다. 또한 제너레이터 예외 전달은 제너레이터에서 try/finally를 금지하는 제약을 완화하는 데 도움이 됩니다. 이러한 필요는 종료 시 버퍼를 비우거나 자원을 닫아야 하는 제너레이터에서 특히 절실합니다.
두 제안은 하위 호환성을 유지하며 새로운 키워드를 필요로 하지 않습니다. 이 제안들은 Python 버전 2.5에 권장되고 있습니다.
제너레이터 속성 명세
본질적으로 이 제안은 클래스의 속성 쓰기를 흉내 내는 것입니다. 유일한 문제는 제너레이터에 자기 자신의 인스턴스를 참조할 방법이 없다는 점입니다. 그래서 그 참조를 알아내는 함수를 제공할 것을 제안합니다. 예를 들면 다음과 같습니다:
def mygen(filename):
self = sys.get_generator()
myfile = open(filename)
for line in myfile:
if len(line) < 10:
continue
self.pos = myfile.tell()
yield line.upper()
g = mygen('sample.txt')
line1 = g.next()
print 'Position', g.pos
제너레이터 속성의 용도는 다음과 같습니다:
- 제너레이터 클라이언트에게 추가 정보를 제공합니다(위에서 보인 것처럼).
- 제너레이터의 동작을 제어하는 플래그를 외부에서 설정합니다(예를 들어 제너레이터에게 언제 데이터 그룹 안으로 들어가고 언제 건너뛸지 알려 줄 수 있습니다).
- 복잡한 실행 상태를 가진 지연 소비자를 작성합니다(예를 들면 산술 부호화기 출력 스트림).
- 코루틴을 작성합니다(Mertz 박사의 글 [1]에서 보여 준 것처럼).
이 제안으로 ‘yield’와 ‘next’의 제어 흐름은 바뀌지 않습니다. 유일한 변경점은 제너레이터로 데이터를 전달하고 제너레이터로부터 데이터를 받을 수 있다는 것입니다. 기반 메커니즘은 대부분 이미 갖춰져 있으며, 접근 함수만 추가하면 됩니다.
제너레이터 예외 전달 명세
제너레이터 인터페이스에 .throw(exception) 메서드를 추가합니다:
def logger():
start = time.time()
log = []
try:
while True:
log.append(time.time() - start)
yield log[-1]
except WriteLog:
writelog(log)
g = logger()
for i in [10,20,40,80,160]:
testsuite(i)
g.next()
g.throw(WriteLog)
제너레이터 내부에서 예외를 일으킬 수 있는 기존 우회 방법은 없습니다. 이는 Python에서 실행 중인 코드로, 또는 그 코드를 거쳐서 예외를 전달할 수 없는 유일한 경우입니다.
제너레이터 예외 전달은 제너레이터의 본질적인 제약, 즉 정리 코드를 실행하기 위해 try/finally를 사용할 수 없다는 금지 사항(PEP 255)을 해결하는 데에도 도움이 됩니다.
참고 A: throw 메서드의 이름은 몇 가지 이유로 선택되었습니다. raise는 키워드이므로 메서드 이름으로 사용할 수 없습니다. 현재 실행 지점에서 즉시 예외를 일으키는 raise와 달리, throw는 먼저 제너레이터로 돌아간 다음 예외를 일으킵니다. throw라는 단어는 예외를 다른 위치에 던져 넣는다는 의미를 암시합니다. throw라는 단어는 다른 언어에서도 이미 예외와 연관되어 있습니다.
다른 메서드 이름도 검토되었습니다: resolve(), signal(), genraise(), raiseinto(), flush(). 이 중 어느 것도 throw()만큼 잘 들어맞지 않습니다.
참고 B: throw() 문법을 단순하게 유지하기 위해 raise 문법의 인스턴스 버전만 지원합니다(”raise string”이나 “raise class, instance”의 변형은 지원하지 않습니다).
g.throw(instance)를 호출하는 것은 가장 최근의 yield 바로 뒤에 raise instance를 작성하는 것에 해당합니다.
참고 문헌
Copyright
This document has been placed in the public domain.