3. Descriptor 란
__get__(self, instance, class), __set__(self,
instance, value), __delete__(self, instance )
3개의 메소드를 가지는 클래스
Self는 Descriptor 클래스의 인스턴스
Instance는 class로 생성되는 인스턴스
다른 클래스 변수에 descriptor 인스턴스를 할
당해서 사용
4. Descriptor aggregation 구조
인스턴스에서 클래스변수(aggregation)를 호출하
면 descriptor 인스턴스가 descriptor 메소드를
호출하여 인스턴스 내부 변수와 할당값을 세팅
Descriptor
class
User
defined
class
변수
Descriptor
instance
User
defined
instance
_변수
__init__
__get__
__set__
__delete__
1. 인스턴스.변수 호출
2. 클래스 내의 변수 확
인
3. Descriptor 인스턴
스가 get/set 메소
드 호출
4. 인스턴스.__dict__에
_변수 할당
5. Descriptor aggregation 주의사
항 : 변수명
사용자 인스턴스 저장되는 변수를 클래스 내부에
정의된 변수와 구별 필요 ( _변수명)
Descriptor
class
User
defined
class
변수
Descriptor
instance
User
defined
instance
_변수
__init__
__get__
__set__
__delete__
1. 인스턴스.변수 호출
2. 클래스 내의 변수 확
인
3. Descriptor 인스턴
스가 get/set 메소
드 호출
4. 인스턴스.__dict__에
_변수 할당
6. Descriptor aggregation 주의사
항 : get
인스턴스.변수명을 사용하면 __get__가 호출되므
로 인스턴스._변수명이 미존재하므로 초기값 정의
필요
Descriptor
class
User
defined
class
변수
Descriptor
instance
User
defined
instance
_변수
__init__
__get__
__set__
__delete__
1. 인스턴스.변수 호출
2. 클래스 내의 변수 확
인
3. Descriptor 인스턴
스가 get/set 메소
드 호출
4. 인스턴스.__dict__에
_변수 할당
7. Descriptor 상속 구조
Descriptor 상속관계로 구현시 실제 descriptor 인
스턴스에 값을 보관하여 처, 실제 __get__을 사용
해서 값을 검색해야 함
Descriptor
class
User
defined
class
User
defined
instance
변수
__init__
__get__
Descriptor
인스턴스
변수
8. Descriptor 상속 구조 사용
descriptor 클래스를 상속해서 get 만 사용하는
경우
class D(object) :
def __init__(self, x=None) :
self.x = x
def __get__(self,instance=None,cls=None) :
return self.x
class D1(D) :
def __init__(self, x,y) :
self.x = D(x)
self.y = D(y)
d1 = D1(2,3)p
rint (" d1")
print (d1.__dict__)
print (d1.x)
print(d1.y)
print (" direct call",d1.x.__get__(), d1.y.__get__())
print (" Class binding call x ", D1.__get__(d1.x,d1.x))
print (" Class binding call y ", D1.__get__(d1.y,d1.y))
print (" class binding",type(d1).__get__(d1.x,d1.x))
D1
{'x': <__main__.D object at
0x113f46400>, 'y':
<__main__.D object at
0x113f461d0>}
<__main__.D object at
0x113f46400>
<__main__.D object at
0x113f461d0>
direct call 2 3
Class binding call x 2
Class binding call y 3
class binding 2
10. Descriptor 처리 절차
Descriptor class를 생성하여 실제 구현 클래스
내부의 속성에 대한 init/getter/setter/deleter
를 통제할 수 있도록 구조화
Class Decriptor :
def __init__
def __get__
def __set__
def __del__
class Person() :
name= Descriptor()
user = Person()
user.name = ‘Dahl’
Descriptor class 생성
구현 class 정의시 속성에
대한인스턴스 생성
구현class에 대한 인스턴
스 생성 및 인스턴스 속성
에 값 세팅
11. Descriptor class 정의
클래스에 인스턴스를 관리하는 생성자와 실제 인스
턴스의 값을 관리 get/set/delete 메소드 정의
class Descriptor(object)
def __init__(self,name):
self.name = ‘_’ + str(name)
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):
instance.__dict__[self.name] = value
def __delete__(self, instance):
del instance.__dict__[self.name]
인스턴스 객체의 변수명
으로 세팅될 변수명 저장
12. __get__/__set__ 검색1
getattr,setattr 함수를 이용해서 내부의 값을
직접 검색 및 갱신
def __get__(self, instance, owner):
return getattr(instance, self.name)
def __set__(self, instance, value):
setattr(instance,self.name,value)
13. __get__/__set__ 검색2
Instance 내부의 값을 직접 검색
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):
instance.__dict__[self.name] = value
14. Data descriptor 여부 확인
Inspect 모듈을 이용해서 data descriptor 여
부 확인
import inspect
print(inspect.isdatadescriptor(descriptor()) #true
15. Descriptor 사용 class 정의/실행
1. 구현 클래스에는 속성에 descriptor인스턴스 생성
2. 인스턴스 객체의 변수에 직접 값을 할당(set)
3. 인스턴스 객체의 변수로 조회(get)
class Person(object):
name = Descriptor(“name”)
user = Person()
print user.__dict__ # {}
user.name = 'john smith‘
print user.__dict__ # {'_name': 'john smith'}
print "user.name ",user.name # user.name john smith
인스턴스의 변수와
내부 관리 변수의
name을 상이하게
관리도 가능
16. Descriptor 메소드 호출 예시
2개 호출 처리는 동일 한 결과가 나온다.
실제 구현시 첫번째 방식이 가독성이 높음
user = Person()
user.name = 'john smith’ # Descriptor.__set__ 호출
print user.name # Descriptor.__get__ 호출
print user.__dict__
user1 = Person()
Descriptor.__set__(Descriptor(),user1,"dahl")
Descriptor.__get__(Descriptor(),user1,Descriptor)
print user1.__dict__
21. Descriptor 종류
Method descriptor와 Data descripter 로 구분
Method descriptor는 __get__(self, instance,
owner) 구현
Data descriptor는 __get__(self, instance,
owner), __set__(self,instance, value) or
__delete__(self, instance) 구현
22. Creating data descriptor
Data Descriptor 클래스를 생성해서 처리하는
방법
class Descriptor(object):
def __init__(self):
self._name = ''
def __get__(self, instance, owner):
print "Getting: %s" % self._name
return self._name
def __set__(self, instance, name):
print "Setting: %s" % name
self._name = name.title()
def __delete__(self, instance):
print "Deleting: %s" %self._name
del self._name
class Person(object):
name = Descriptor()
>>> user = Person()
>>> user.name = 'john smith'
Setting: john smith
>>> user.name
Getting: John Smith
'John Smith‘
>>> del user.name
Deleting: John Smith
24. Descriptor : init 메소드 수정
Descriptor class에 생성자 메소드에 변수명, 변
수 타입, 변수값을 받아 생성하도록 만듦
Class Decriptor :
# 변수명, 값타입, 디폴트값,
def __init__(self, var_name, var_type, var_default) :
self.var_name = “_”+var_name
self.var_type = var_type
self.var_default = var_default if var_default else type()
25. Descriptor : get/set 함수 수정
Descriptor class에 생성자 메소드에 변수명, 변
수 타입, 변수값을 받아 생성하도록 만듦
Class Decriptor :
def __get__(self, instance, cls):
return getattr(instance, self.name, self.default)
def __set__(self,instance,value):
if not isinstance(value,self.type):
raise TypeError("Must be a %s" % self.type)
setattr(instance,self.name,value)
def __delete__(self,instance):
raise AttributeError("Can't delete attribute")
# 처리시 주의 사항
setattr(instance,self.name,va
lue)
self.name의 “_” 없는 값을
넣을 경우 런타임오류 발생
RuntimeError: maximum
recursion depth exceeded
while calling a Python object
26. 구현 class 처리:
클래스 내부의 변수에 descriptor 인스턴스를 생
성함.
class Person(object):
name =Descriptor ("name",str)
age = Descriptor("age",int,42)
user = Person()