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의 디스크립터 프로토콜에서는 디스크립터가 객체의 type의 멤버여야 합니다. 이 PEP는 instances의 멤버에 디스크립터 프로토콜을 사용할 수 있도록 디스크립터 프로토콜을 확장할 것을 제안합니다. 이를 통해 모듈에서 프로퍼티를 사용할 수 있습니다.
근거
Python의 디스크립터 프로토콜은 프로그래머가 우아한 API를 설계하도록 이끕니다. 클래스가 데이터와 유사한 멤버를 지원하고, 멤버의 값을 변경할 때 언젠가 코드를 실행해야 할 수도 있다면, 지금은 이를 클래스의 단순한 데이터 멤버로 선언하기만 하도록 권장합니다. 이후에 실제로 코드를 실행해야 한다면 이를 “property”로 변경할 수 있으며, 다행히 API는 변경되지 않습니다.
그러나 모범적인 Python API 설계의 두 번째 원칙을 생각해 보십시오. 싱글턴을 작성한다면 클래스를 작성하지 말고, 코드를 모듈에 직접 구성하십시오. 사용자가 싱글턴 클래스를 인스턴스화하게 하지 말고, 모듈에 저장된 싱글턴 객체를 거쳐 역참조하게 하지도 말고, 모듈 수준 함수와 모듈 수준 데이터만 사용하십시오.
안타깝게도 이 두 가지 모범 사례는 서로 상충합니다. 문제는 모듈에서 프로퍼티가 지원되지 않는다는 것입니다. 모듈은 단일한 일반 module 타입의 인스턴스이며, 이 타입을 수정하거나 서브클래싱하여 모듈에 프로퍼티를 추가하는 것은 현실적이지 않습니다. 따라서 데이터와 유사한 멤버가 모듈에 저장된 싱글턴인 경우, 이러한 API 설계 결정을 마주한 프로그래머는 데이터를 위한 보기 흉한 “getters”와 “setters”를 미리 추가해야 합니다.
순수 Python에서 모듈 프로퍼티를 지원하는 것이 최근 possible; 해졌습니다. Python 3.5부터 Python은 특별히 이 목적을 위해 모듈 객체의 __class__ 속성에 대입하는 것을 허용합니다. 다음은 이 기능을 사용하여 모듈에 프로퍼티를 추가하는 예입니다.:
import sys, types
class _MyModuleType(types.ModuleType):
@property
def prop(self, instance, owner):
...
sys.modules[__name__].__class__ = _MyModuleType
이 방식은 작동하며 지원되는 동작이지만, 번거롭고 잘 알려져 있지 않습니다.
이 PEP는 모듈에서 프로퍼티를 사용할 수 있도록 특별히 설계된, 타입별 옵트인 방식의 디스크립터 프로토콜 확장을 제안합니다. 이 메커니즘은 멤버를 클래스 변수로 선언하지 않고도 클래스 instances의 멤버에 디스크립터 프로토콜을 적용하는 방법입니다.
이것은 일반적인 메커니즘으로 제안되고 있지만, 현재 저자는 이것이 모듈 객체에 유용할 것으로만 예상합니다.
구현
기본 아이디어는 간단합니다. PyModule_Type이 노출하는 tp_descr_get 및 tp_descr_set 함수를 수정하여 상호작용한 속성을 검사하고, 해당 속성이 디스크립터 프로토콜을 지원하면 관련 노출 함수를 호출하는 것입니다.
저희 구현에는 두 가지 문제가 있습니다.
- 이 코드는 메서드에서 속성을 조회할 때마다 실행되므로, 속성에 저장된 객체가 디스크립터가 아닌 일반적인 경우에는 오버헤드를 매우 작게 유지해야 합니다.
- 함수는 디스크립터이므로, 모든 객체에 대해 디스크립터 프로토콜을 준수하지 않도록 주의해야 합니다. 그렇지 않으면 모든 모듈 수준 함수가 갑자기 모듈 객체에서 메서드 호출을 한 것처럼 모듈 인스턴스에 바인딩됩니다. 모듈 핸들이 모든 모듈 수준 함수에 “self” 인자로 전달됩니다.
두 문제는 동일한 접근 방식으로 해결할 수 있습니다. 즉, “이 객체는 디스크립터이며, 인스턴스의 속성으로 조회될 때 이 객체에 디스크립터 프로토콜을 직접 적용해야 합니다”라는 의미의 새로운 “fast subclass” 플래그를 정의합니다. 지금까지 이 플래그는 property 및 collections.abc.InstanceDescriptor라는 두 타입에만 설정되어 있습니다. 후자는 사용자가 정의한 클래스가 이 “fast subclass” 플래그를 상속할 수 있도록 하는 것이 유일한 목적인 추상 베이스 클래스입니다.
프로토타입
이 기능의 프로토타입은 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.