PEP 3152 – 코함수
- Author:
- Gregory Ewing <greg.ewing at canterbury.ac.nz>
- Status:
- Rejected
- Type:
- Standards Track
- Created:
- 13-Feb-2009
- Python-Version:
- 3.3
- Post-History:
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
‘코함수(cofunction)’라고 부르는 특수한 종류의 제너레이터를 정의하고 호출하기 위한 문법을 제안합니다. 이 문법은 제너레이터 기반 코루틴을 더 간결하게 작성하는 방법을 제공합니다. 또한 이런 코드를 작성할 때 저지르기 쉬운 몇 가지 오류를 일찍 발견할 수 있게 합니다. 이런 오류는 이 문법이 없으면 진단하기 어려운 증상을 일으키기 쉽습니다.
이 제안은 PEP 380에서 설명하는 ‘yield from’ 메커니즘을 기반으로 하며, 코함수의 의미 일부를 이 메커니즘을 통해 설명합니다. 하지만 원한다면 코함수를 PEP 380과 독립적으로 정의하고 구현할 수도 있습니다.
거부
https://mail.python.org/pipermail/python-dev/2015-April/139503.html 을 참조하십시오.
명세
코함수 정의
새 키워드 codef를 도입하며, 코함수를 정의할 때 def 대신 이 키워드를 사용합니다. 코함수는 다음과 같은 특징을 가진 특수한 종류의 제너레이터입니다:
- 코함수는
yield나yield from표현식을 전혀 포함하지 않더라도 항상 제너레이터입니다. - 코함수는 일반 함수와 같은 방식으로 호출할 수 없습니다. 코함수를 일반적인 방식으로 호출하려고 하면 예외가 발생합니다.
코호출
한 코함수에서 다른 코함수를 호출할 때는 새 키워드 cocall로 호출을 표시합니다. 다음 표현식은
cocall f(*args, **kwds)
의미상 다음과 동등합니다.
yield from f.__cocall__(*args, **kwds)
다만 __cocall__이 반환하는 객체는 이터레이터여야 하므로, 그 객체에 iter()를 호출하는 단계는 생략됩니다.
코호출 표현식의 전체 문법은 다음 문법 규칙으로 기술됩니다.:
atom: cocall | <existing alternatives for atom>
cocall: 'cocall' atom cotrailer* '(' [arglist] ')'
cotrailer: '[' subscriptlist ']' | '.' NAME
cocall 키워드는 코함수 안에서만 문법적으로 유효합니다. 다른 문맥에서 사용하면 SyntaxError가 발생합니다.
__cocall__을 구현하는 객체는 이터레이터 프로토콜을 따르는 객체를 반환해야 합니다. 코함수는 일반 제너레이터 함수가 __call__에 응답하는 것과 같은 방식으로 __cocall__에 응답합니다. 즉, 제너레이터-이터레이터를 반환합니다.
다른 호출 가능 객체를 감싸는 특정 객체들, 특히 바운드 메서드에는 내부 객체에 위임하는 __cocall__ 구현이 제공될 것입니다.
새로운 내장 함수, 속성 및 C API 함수
코함수를 코루틴이 아닌 코드와 쉽게 연동할 수 있도록 내장 함수 costart를 제공할 것이며, 그 정의는 다음과 동등합니다.
def costart(obj, *args, **kwds):
return obj.__cocall__(*args, **kwds)
이에 대응하는 C API 함수도 제공할 것입니다.
PyObject *PyObject_CoCall(PyObject *obj, PyObject *args, PyObject *kwds)
코함수가 별개의 객체 타입인지, 아니면 제너레이터 함수처럼 특별히 표시된 함수 인스턴스일 뿐인지는 당분간 정하지 않고 남겨 둡니다. 후자라면, 주어진 함수 객체가 코함수인지 검사할 수 있도록 읽기 전용 불리언 속성 __iscofunction__을 제공해야 합니다.
동기와 근거
yield from 문법은 제너레이터 작업의 일부를 다른 함수에 위임하는 목적으로 사용될 때는 그 의미가 상당히 자명합니다. 이 구문은 제너레이터 기반 코루틴을 구현하는 데에도 효과적으로 사용할 수 있지만, 그런 목적으로 사용하면 다소 어색하게 읽히며 코드의 진짜 의도를 흐리는 경향이 있습니다.
게다가 제너레이터를 코루틴으로 사용하는 방식은 다소 오류를 일으키기 쉽습니다. yield from을 사용해야 할 곳에서 사용하는 것을 잊거나 사용하지 말아야 할 곳에서 사용하면, 그 결과로 나타나는 증상이 모호하고 혼란스러울 수 있습니다.
마지막으로, 함수가 아무것도 yield하지 않는데도 코루틴이어야 하는 경우가 가끔 있으며, 이런 경우에는 함수를 강제로 제너레이터로 만들기 위해 if 0: yield와 같은 편법에 의존해야 합니다.
codef와 cocall 구문은 문법이 의도, 즉 해당 함수가 코루틴의 일부를 이룬다는 사실을 직접 반영하도록 함으로써 첫 번째 문제를 해결합니다.
두 번째 문제는 코루틴 코드와 비코루틴 코드를 말이 되지 않는 방식으로 섞을 수 없게 하여 해결합니다. 규칙을 위반하면 무엇이 어디에서 문제인지 정확히 짚어 주는 예외가 발생합니다.
마지막으로, 함수가 코루틴인지 여부를 함수가 담고 있는 내용이 아니라 정의의 형태가 결정하도록 하여 더미 yield의 필요성을 없앱니다.
프로토타입 구현
Python 3.1.2에 대한 패치 형태의 구현은 다음에서 찾을 수 있습니다:
http://www.cosc.canterbury.ac.nz/greg.ewing/python/generators/cofunctions.html
Copyright
This document has been placed in the public domain.