날짜: 2024-11-30
파이썬에서 디스크립터(Descriptor)는 객체 속성에 대한 접근 방식을 사용자 정의할 수 있는 방법을 제공합니다. 디스크립터는 적어도 하나의 특별 메서드(__get__
, __set__
, __delete__
)를 구현한 클래스를 말합니다. 이를 통해 속성에 접근할 때의 동작을 재정의할 수 있습니다.
__get__(self, instance, owner)
:
instance
: 디스크립터가 속한 객체입니다. 클래스에서 호출될 경우 None
이 전달됩니다.owner
: 소유 클래스입니다.__set__(self, instance, value)
:
value
: 설정할 값입니다.__delete__(self, instance)
:
__get__
과 __set__
또는 __delete__
를 모두 구현한 경우.__dict__
보다 높은 우선순위를 가집니다.__get__
만 구현한 경우.__dict__
에 값이 있을 경우 이를 우선 사용합니다.__dict__
와 디스크립터의 관계__dict__
:
__dict__
에 저장됩니다.__dict__
를 확인합니다.__dict__
:
__dict__
에 저장됩니다.__dict__
에 정의됩니다. 디스크립터가 정의된 속성에 접근하면, Python은 디스크립터를 먼저 확인합니다.파이썬의 속성 접근 순서는 다음과 같습니다:
obj.attr
):
__get__
메서드가 호출됩니다. 인스턴스의 __dict__
보다 우선합니다.__dict__
를 확인합니다.__dict__
에 값이 없을 때 호출됩니다.obj.attr = value
):
__set__
메서드가 호출됩니다.__dict__
에 저장됩니다.del obj.attr
):
__delete__
를 구현했다면, 해당 메서드가 호출됩니다.__dict__
에서 속성을 삭제합니다.class ReadOnlyDescriptor:
def __get__(self, instance, owner):
return "읽기 전용 값"
class MyClass:
attr = ReadOnlyDescriptor()
obj = MyClass()
print(obj.attr) # 출력: 읽기 전용 값
class PositiveNumber:
def __get__(self, instance, owner):
return instance.__dict__.get('_value', 0)
def __set__(self, instance, value):
if value < 0:
raise ValueError("값은 양수여야 합니다.")
instance.__dict__['_value'] = value
class MyClass:
value = PositiveNumber()
obj = MyClass()
obj.value = 10 # 올바른 값
print(obj.value) # 출력: 10
obj.value = -5 # ValueError: 값은 양수여야 합니다.
__dict__
보다 우선class DataDescriptor:
def __get__(self, instance, owner):
return "데이터 디스크립터 값"
def __set__(self, instance, value):
instance.__dict__['attr'] = value
class MyClass:
attr = DataDescriptor()
obj = MyClass()
obj.attr = "인스턴스 값"
print(obj.attr) # 출력: 데이터 디스크립터 값
print(obj.__dict__) # 출력: {'attr': '인스턴스 값'}
__get__
메서드가 호출됩니다.__dict__
에 값이 있어도 무시됩니다.__dict__
보다 나중에 호출class NonDataDescriptor:
def __get__(self, instance, owner):
return "비데이터 디스크립터 값"
class MyClass:
attr = NonDataDescriptor()
obj = MyClass()
obj.__dict__['attr'] = "인스턴스 값"
print(obj.attr) # 출력: 인스턴스 값
__dict__
에 값이 있을 경우 이를 우선 사용합니다.class DeletableDescriptor:
def __get__(self, instance, owner):
return instance.__dict__.get('attr', None)
def __set__(self, instance, value):
instance.__dict__['attr'] = value
def __delete__(self, instance):
print("속성 삭제됨")
del instance.__dict__['attr']
class MyClass:
attr = DeletableDescriptor()
obj = MyClass()
obj.attr = "값 설정"
print(obj.attr) # 출력: 값 설정
del obj.attr # 출력: 속성 삭제됨
print(obj.__dict__) # 출력: {}
__delete__
를 구현하여 속성 삭제를 제어할 수 있습니다.property()
는 디스크립터의 한 구현입니다.__dict__
보다 우선합니다.__dict__
에 속성이 없을 때만 동작합니다.__dict__
를 우회합니다.