PEP 549 – 인스턴스 디스크립터
- Author:
- Larry Hastings <larry at hastings.org>
- Discussions-To:
- Python-Dev list
- Status:
- Rejected
- Type:
- Standards Track
- Created:
- 04-Sep-2017
- Python-Version:
- 3.7
- Post-History:
- 04-Sep-2017
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
거부 공지
https://mail.python.org/pipermail/python-dev/2017-November/150528.html
초록
Python의 디스크립터 프로토콜은 디스크립터가 객체의 타입의 멤버일 것을 요구합니다. 이 PEP는 인스턴스의 멤버에 대해서도 디스크립터 프로토콜을 사용할 수 있도록 디스크립터 프로토콜을 확장할 것을 제안합니다. 이를 통해 모듈에서 프로퍼티를 사용할 수 있게 됩니다.
근거
Python의 디스크립터 프로토콜은 프로그래머가 우아한 API를 설계하도록 이끌어 줍니다. 클래스가 데이터와 유사한 멤버를 지원하고, 언젠가 그 멤버의 값을 변경할 때 코드를 실행해야 할 수도 있다면, 지금은 그냥 클래스의 단순한 데이터 멤버로 선언해 두는 것이 권장됩니다. 나중에 실제로 코드를 실행해야 하게 되면 이를 “프로퍼티”로 바꾸면 되고, 다행히 API는 바뀌지 않습니다.
하지만 Python API 설계의 두 번째 모범 사례를 생각해 보십시오. 싱글턴을 작성한다면 클래스를 작성하지 말고 코드를 모듈에 직접 넣으십시오. 사용자가 싱글턴 클래스를 인스턴스화하게 하지 말고, 모듈에 저장된 싱글턴 객체를 거쳐 역참조하게 하지도 말고, 그냥 모듈 수준 함수와 모듈 수준 데이터를 두십시오.
안타깝게도 이 두 모범 사례는 서로 충돌합니다. 문제는 모듈에서 프로퍼티가 지원되지 않는다는 점입니다. 모듈은 하나의 제네릭 module 타입의 인스턴스이며, 자신의 모듈에 프로퍼티를 추가하기 위해 이 타입을 수정하거나 서브클래스로 만드는 것은 현실적으로 불가능합니다. 이는 데이터와 유사한 멤버가 모듈에 저장된 싱글턴인 상황에서 이러한 API 설계 결정을 마주한 프로그래머가 해당 데이터에 대해 보기 흉한 “게터”와 “세터”를 미리 추가해야 한다는 뜻입니다.
순수 Python으로 모듈 프로퍼티를 지원하는 것이 최근에 가능해졌습니다. Python 3.5부터 Python은 바로 이 목적을 위해 모듈 객체의 __class__ 속성에 대입하는 것을 허용합니다. 다음은 이 기능을 사용하여 모듈에 프로퍼티를 추가하는 예입니다:
import sys, types
class _MyModuleType(types.ModuleType):
@property
def prop(self, instance, owner):
...
sys.modules[__name__].__class__ = _MyModuleType
이 방법은 동작하며 지원되는 동작이기도 하지만, 번거롭고 알기 어렵습니다.
이 PEP는 모듈에서 프로퍼티를 사용할 수 있도록 특별히 설계된, 타입별로 선택하여 적용하는 디스크립터 프로토콜 확장을 제안합니다. 이 메커니즘은 멤버를 클래스 변수로 선언하지 않고도 클래스 인스턴스의 멤버에 대해 디스크립터 프로토콜을 따르도록 하는 방법입니다.
이 메커니즘은 범용 메커니즘으로 제안되고 있지만, 저자는 현재로서는 모듈 객체에만 유용할 것으로 예상합니다.
구현
기본 아이디어는 간단합니다. PyModule_Type이 노출하는 tp_descr_get 및 tp_descr_set 함수를 수정하여 상호 작용 대상 속성을 검사하고, 그 속성이 디스크립터 프로토콜을 지원하면 노출된 관련 함수를 호출하도록 합니다.
이 구현에는 두 가지 과제가 있습니다.
- 이 코드는 메서드에서 속성을 조회할 때마다 실행되므로, 속성에 저장된 객체가 디스크립터가 아닌 일반적인 경우에는 오버헤드를 거의 추가하지 않아야 합니다.
- 함수도 디스크립터이므로, 모든 객체에 대해 디스크립터 프로토콜을 따르지 않도록 주의해야 합니다. 그렇지 않으면 모든 모듈 수준 함수가 마치 모듈 객체의 메서드 호출인 것처럼 갑자기 모듈 인스턴스에 바인딩됩니다. 그러면 모듈 핸들이 모든 모듈 수준 함수에 “self” 인자로 전달될 것입니다.
두 과제 모두 같은 방법으로 해결할 수 있습니다. “이 객체는 디스크립터이며, 이 객체가 인스턴스의 속성으로 조회될 때 이를 직접 따라야 한다”는 의미의 새로운 “빠른 서브클래스” 플래그를 정의하는 것입니다. 현재 이 플래그는 두 가지 타입에만 설정되어 있습니다. property와 collections.abc.InstanceDescriptor입니다. 후자는 추상 베이스 클래스이며, 사용자 클래스가 이 “빠른 서브클래스” 플래그를 상속할 수 있도록 하는 것이 유일한 목적입니다.
프로토타입
이 기능의 프로토타입은 GitHub [github]에서 개발 중입니다.
감사의 글
Armin Rigo는 “모듈 프로퍼티”라는 아이디어를 접했을 때 사실상 이 메커니즘을 제안했으며, 문제의 복잡성과 올바른 해결책 모두에 대해 저자에게 가르쳐 주었습니다. Nathaniel J. Smith는 모듈 객체의 __class__에 대입하는 것에 관한 3.5 확장을 지적하고, 그 예제를 제공했습니다.
참고 문헌
- The branch is here:
- https://github.com/larryhastings/cpython/tree/module-properties
- A pull request against the main CPython repo is here:
- https://github.com/python/cpython/pull/3534
Copyright
This document has been placed in the public domain.