객체 설명자
일반적으로 설명자는 "바인딩 동작"이 있는 객체 속성이며 해당 액세스 제어는 설명자 프로토콜 방법에 의해 재정의됩니다. 이러한 메서드는 __get__(), __set__() 및 __delete__()입니다. 이러한 메소드를 가진 객체를 디스크립터라고 합니다.
속성에 대한 기본 액세스 제어는 객체의 사전(__dict__)에서 가져오기(get), 설정(set) 및 삭제(delete)하는 것입니다. 예를 들어, a.x에 대한 검색 순서는 a.__dict__['x']이고, 그런 다음(a).__dict__['x']를 입력하고, 그런 다음 type(a)(메타클래스 제외)의 상위 클래스를 찾습니다. 찾은 값이 설명자이면 Python은 설명자의 메서드를 호출하여 기본 제어 동작을 재정의합니다. 조회 단계에서 이 재정의가 발생하는 위치는 정의된 설명자 메서드에 따라 다릅니다. 설명자는 새로운 스타일 클래스 내부에서만 작동합니다. 이전 장에서 새로운 스타일 클래스와 이전 스타일 클래스에 대해 언급했습니다. 관심이 있는 경우 이전 장을 확인해 보세요. 새로운 스타일 클래스의 가장 큰 특징은 모든 클래스가 타입 또는 객체 클래스에서 상속된다는 것입니다.
객체 지향 프로그래밍에서 클래스의 속성이 상호 의존적인 경우 설명자를 사용하여 코드를 작성하면 논리를 매우 영리하게 구성할 수 있습니다. Django의 ORM에서 models.Model의 InterField와 같은 필드는 설명자를 통해 해당 기능을 구현합니다.
먼저 다음 예제를 살펴보겠습니다.
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- class User(object): def __init__(self, name='两点水', sex='男'): self.sex = sex self.name = name def __get__(self, obj, objtype): print('获取 name 值') return self.name def __set__(self, obj, val): print('设置 name 值') self.name = val class MyClass(object): x = User('两点水', '男') y = 5 if __name__ == '__main__': m = MyClass() print(m.x) print('\n') m.x = '三点水' print(m.x) print('\n') print(m.x) print('\n') print(m.y)
출력 결과는 다음과 같습니다.
获取 name 值 两点水 设置 name 值 获取 name 值 三点水 获取 name 值 三点水 5
이 예제를 통해 __get__() 및 __set__() 메서드의 호출을 잘 관찰할 수 있습니다.
또 다른 고전적인 예를 보세요
우리는 거리가 "미터" 또는 "피트" 단위로 표현될 수 있다는 것을 알고 있습니다. 이제 거리를 나타내는 클래스를 정의합니다. 이 클래스에는 미터와 피트라는 두 가지 속성이 있습니다.
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- class Meter(object): def __init__(self, value=0.0): self.value = float(value) def __get__(self, instance, owner): return self.value def __set__(self, instance, value): self.value = float(value) class Foot(object): def __get__(self, instance, owner): return instance.meter * 3.2808 def __set__(self, instance, value): instance.meter = float(value) / 3.2808 class Distance(object): meter = Meter() foot = Foot() if __name__ == '__main__': d = Distance() print(d.meter, d.foot) d.meter = 1 print(d.meter, d.foot) d.meter = 2 print(d.meter, d.foot)
출력 결과:
0.0 0.0 1.0 3.2808 2.0 6.5616
위의 예에서 Distance 인스턴스에 값을 할당하기 전에 미터와 피트가 해당 클래스의 인스턴스 개체여야 한다고 생각했지만 출력은 숫자 값입니다. __get__이 작동하기 때문입니다.
미터를 수정하고 int에 할당했지만 발도 수정되었습니다. 여기서 __set__이 작동합니다.
설명자 개체(미터, 피트)는 독립적으로 존재할 수 없으며 다른 소유자 클래스(거리)가 보유해야 합니다. 설명자 개체는 예제에서 Foot의 instance.meter와 같은 소유자 인스턴스의 속성에 액세스할 수 있습니다.