[Rejected] PEP 549 - Instance Descriptors
원문 링크: PEP 549 - Instance Descriptors
상태: Rejected 유형: Standards Track 작성일: 04-Sep-2017
PEP 549 – 인스턴스 디스크립터 (Instance Descriptors)
- 작성자: Larry Hastings
- 상태: Rejected (거부됨)
- 생성일: 2017년 9월 4일
- Python 버전: 3.7
- 요약: 이 PEP는 인스턴스의 멤버에 대해서도 디스크립터 프로토콜을 사용할 수 있도록 Python의 디스크립터 프로토콜 확장을 제안합니다. 이는 모듈 내에서
property
를 사용하는 것을 가능하게 할 것입니다.
거부 통지 (Rejection Notice)
이 PEP는 Python-Dev 메일링 리스트에서 논의된 후 거부되었습니다.
개요 (Abstract)
Python의 디스크립터 프로토콜은 디스크립터가 객체 “타입(type)”의 멤버여야 한다고 요구합니다. 이 PEP는 디스크립터 프로토콜을 “인스턴스(instance)”의 멤버에 대해서도 사용할 수 있도록 확장할 것을 제안합니다. 이는 모듈 내에서 property
를 사용하는 것을 허용할 것입니다.
제안 배경 (Rationale)
Python의 디스크립터 프로토콜은 프로그래머들이 우아한 API를 설계하도록 돕습니다. 예를 들어, 클래스가 데이터와 유사한 멤버를 지원하고, 나중에 이 멤버의 값이 변경될 때 코드를 실행해야 할 수도 있다면, 현재로서는 이를 클래스의 간단한 데이터 멤버로 선언하도록 권장됩니다. 만약 미래에 코드를 실행해야 할 필요가 생긴다면, API를 변경하지 않고도 이를 property
로 바꿀 수 있습니다.
하지만, 또 다른 Python API 설계 모범 사례를 고려해봅시다. 만약 싱글턴(singleton)을 작성한다면, 클래스를 작성하는 대신 코드를 모듈에 직접 빌드하는 것이 좋습니다. 사용자들에게 싱글턴 클래스를 인스턴스화하거나, 모듈에 저장된 싱글턴 객체를 통해 역참조하도록 강요하는 대신, 모듈 레벨 함수와 모듈 레벨 데이터를 사용하도록 합니다.
안타깝게도 이 두 가지 모범 사례는 서로 상충됩니다. 문제는 property
가 모듈에서는 지원되지 않는다는 것입니다. 모듈은 단일한 일반 모듈 타입(types.ModuleType
)의 인스턴스이며, 특정 모듈에 property
를 추가하기 위해 이 타입을 수정하거나 서브클래스화하는 것은 실용적이지 않습니다. 이는 데이터와 유사한 멤버가 모듈에 저장된 싱글턴인 경우, 프로그래머들이 API 설계 결정에 직면했을 때 데이터를 위한 “게터(getters)”와 “세터(setters)”를 선제적으로 추가해야 하는 불편함으로 이어집니다.
순수 Python에서 모듈 property
지원을 추가하는 것은 최근에 가능해졌습니다. Python 3.5부터, 모듈 객체의 __class__
속성에 할당하는 것이 특별히 이러한 목적을 위해 허용되었습니다. 다음은 이 기능을 사용하여 모듈에 property
를 추가하는 예시입니다:
import sys, types
class _MyModuleType(types.ModuleType):
@property
def prop(self, instance, owner):
...
sys.modules[__name__].__class__ = _MyModuleType
이 코드는 작동하며 지원되는 동작이지만, 다소 어색하고 이해하기 어렵습니다.
이 PEP는 특히 모듈 내 property
를 가능하게 하기 위해 설계된, 타입별 옵트인(opt-in) 방식의 디스크립터 프로토콜 확장을 제안합니다. 이 메커니즘은 멤버가 클래스 변수로 선언되지 않아도 클래스 인스턴스 멤버에 대해 디스크립터 프로토콜을 존중하는 방법을 제공합니다.
이것이 일반적인 메커니즘으로 제안되었지만, 현재 작성자는 이것이 모듈 객체에만 유용할 것으로 예상하고 있습니다.
구현 (Implementation)
기본 아이디어는 간단합니다. PyModule_Type
에 의해 노출되는 tp_descr_get
및 tp_descr_set
함수를 수정하여 상호작용하는 속성을 검사하고, 만약 해당 속성이 디스크립터 프로토콜을 지원한다면 관련 노출 함수를 호출하는 것입니다.
이 구현은 두 가지 과제에 직면합니다:
- 이 코드는 메서드에서 속성을 조회할 때마다 실행될 것이므로, 해당 속성에 저장된 객체가 디스크립터가 아닌 일반적인 경우에는 오버헤드를 거의 발생시키지 않아야 합니다.
- 함수도 디스크립터이므로, 모든 객체에 대해 디스크립터 프로토콜을 무조건 존중하지 않도록 주의해야 합니다. 그렇지 않으면, 모든 모듈 레벨 함수가 모듈 객체의 메서드 호출인 것처럼 모듈 인스턴스에 바인딩될 것입니다. 모듈 핸들이 모든 모듈 레벨 함수에 “self” 인수로 전달될 것입니다.
두 가지 과제는 동일한 접근 방식으로 해결할 수 있습니다. 새로운 “fast subclass” 플래그를 정의합니다. 이 플래그는 “이 객체는 디스크립터이며, 이 객체가 인스턴스의 속성으로 조회될 때 직접 존중되어야 한다”는 의미를 가집니다. 현재 이 플래그는 property
와 collections.abc.InstanceDescriptor
두 가지 타입에만 설정됩니다. 후자는 추상 베이스 클래스이며, 사용자 클래스가 이 “fast subclass” 플래그를 상속받을 수 있도록 하는 유일한 목적을 가집니다.
프로토타입 (Prototype)
이 기능의 프로토타입은 GitHub에서 개발 중이었습니다.
감사 (Acknowledgements)
Armin Rigo는 “모듈 property
” 아이디어가 제시되었을 때 본질적으로 이 메커니즘을 제안했으며, 문제의 복잡성과 적절한 해결책에 대해 작성자에게 교육했습니다. Nathaniel J. Smith는 모듈 객체에서 __class__
에 할당하는 Python 3.5 확장을 지적하고 예시를 제공했습니다.
⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.
Comments