[Python]Descriptor (디스크립터)
Descriptor에 대해 알아보자.
"""
Python Advanced - Descriptor
디스크립터
1. 객체에서 서로다른 객체를 속성값으로 가지는 것.
2. Read, Write, Delete 등을 미리 정의 가능
3. Data descriptor(set, del), non-data descriptor(get)
4. 읽기 전용객체 생성에 장점, 클래스를 의도하는 방향으로 생성가능
"""
# 예1 : 기본적인 Descriptor 예제
class DescriptorEx1:
def __init__(self, name='Default'):
self.name = name
def __get__(self, instance, owner):
return f'Get method called. -> self : {self}, instance : {instance}, owner : {owner}, name : {self.name}'
def __set__(self, obj, name):
print('Set method called.')
if isinstance(name, str):
self.name = name
else:
raise TypeError('Name이 문자형이 아닙니다.')
def __delete__(self, instance):
print('Delete method called')
self.name = None
class Sample1:
name = DescriptorEx1()
s1 = Sample1()
s1.name = 'My name is jigi'
# s1.name = 10 --> TypeError: Name이 문자형이 아닙니다.
print('예1 > ', s1.name)
del s1.name
print('예1 > ', s1.name)
print()
"""
Set method called.
예1 > Get method called. -> self : <__main__.DescriptorEx1 object at 0x1025aefd0>, instance : <__main__.Sample1 object at 0x1025aef70>, owner : <class '__main__.Sample1'>, name : My name is jigi
Delete method called
예1 > Get method called. -> self : <__main__.DescriptorEx1 object at 0x1025aefd0>, instance : <__main__.Sample1 object at 0x1025aef70>, owner : <class '__main__.Sample1'>, name : None
"""
# 예2 : Property 클래스 사용 (Descriptor 직접구현)
# class property(fget=None, fset=None, fdel=None, doc=None)
class DescriptorEx2:
def __init__(self, value):
self._name = value
def getVal(self):
return f'Get method called -> self : {self}, name : {self._name}'
def setVal(self, value):
print('Set method called.')
if isinstance(value, str):
self._name = value
else:
raise TypeError('value가 문자형이 아닙니다.')
def delVal(self):
print('Delete method called')
self._name = None
name = property(getVal, setVal, delVal, 'Property Method Example')
s2 = DescriptorEx2('테스트 중입니다.')
# 최초값 확인
print('예2 > ', s2.name)
s2.name = '값을 변경함'
# s2.name = 10 --> TypeError: value가 문자형이 아닙니다.
del s2.name
print('예2 > ', s2.name)
print('예2 > ', DescriptorEx2.name.__doc__)
"""
예2 > Get method called -> self : <__main__.DescriptorEx2 object at 0x1025aebe0>, name : 테스트 중입니다.
Set method called.
Delete method called
예2 > Get method called -> self : <__main__.DescriptorEx2 object at 0x1025aebe0>, name : None
예2 > Property Method Example
"""
"""
Python Advanced - Descriptor
디스크립터
1. 상황에 맞는 메소드 구현을 통한 객체 지향 프로그래밍 구현
2. Property와 달리 reuse(재사용) 가능
3. ORM Framework 사용
"""
# 예1 : 지정한 경로의 파일 개수 확인
import os
class DirectoryFileCount:
def __get__(self, instance, obj_type=None):
print(os.listdir(instance.dirname))
return len(os.listdir(instance.dirname))
class DirectoryPath:
# Descriptor instance;
size = DirectoryFileCount()
def __init__(self, dirname):
self.dirname = dirname
# 현재 경로
s = DirectoryPath('./')
print('./ size = ', s.size)
"""
['py_ad_1_5.py', 'py_ad_2_2.py', 'py_ad_3_3.py', 'py_ad_1_1.py', 'py_ad_1_4.py', 'py_ad_2_3.py', 'py_ad_3_2.py', '__init__.py', 'py_ad_2_4.py', 'testfile4.txt', 'py_ad_1_3.py', 'py_ad_3_5.py', 'py_ad_3_1.py', 'testfile2.txt', 'py_ad_2_1.py', 'testfile3.txt', 'py_ad_2_5.py', 'testfile1.txt', 'py_ad_1_2.py', 'py_ad_3_4.py']
./ size = 20
"""
# 이전 경로
g = DirectoryPath('../')
print('../ size = ', g.size)
print()
"""
['level3', 'level2', 'venv', '.idea']
../ size = 4
"""
print('예1 dir >> ', dir(DirectoryPath))
print('예1 __dict__ >> ', DirectoryPath.__dict__)
print('예1 dir(s) >> ', dir(s))
print('예1 s.__dict__ >> ', s.__dict__)
print()
print()
"""
예1 dir >> ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'size']
예1 __dict__ >> {'__module__': '__main__', 'size': <__main__.DirectoryFileCount object at 0x102c2bfd0>, '__init__': <function DirectoryPath.__init__ at 0x102b25ca0>, '__dict__': <attribute '__dict__' of 'DirectoryPath' objects>, '__weakref__': <attribute '__weakref__' of 'DirectoryPath' objects>, '__doc__': None}
예1 dir(s) >> ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'dirname', 'size']
예1 s.__dict__ >> {'dirname': './'}
"""
# 예2
import logging
logging.basicConfig(
format='%(asctime)s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S'
)
class LoggedScoredAccess:
def __init__(self, value=50):
self.value = value
def __get__(self, instance, owner=None):
logging.info('Accessing %r giving %r', 'score', self.value)
return self.value
def __set__(self, instance, value):
logging.info('Updating %r giving %r', 'score', value)
self.value = value
class Student:
# Descriptor instance
score = LoggedScoredAccess()
def __init__(self, name):
# Regular instance attribute
self.name = name
s1 = Student('Im')
s2 = Student('Jigi')
# 점수확인(s1)
print('예2 s1.score : ', s1.score)
s1.score = 70
print('예2 s1.score : ', s1.score)
"""
예2 s1.score : 50
예2 s1.score : 70
"""
# 점수확인(s2)
print('예2 s2.score : ', s2.score)
s2.score += 30
print('예2 s2.score : ', s2.score)
"""
예2 s2.score : 70
예2 s2.score : 100
"""
# __dict__ 확인
print('예2 vars(s1) : ', vars(s1))
print('예2 vars(s2) : ', vars(s2))
print('예2 s1.__dict__ : ', s1.__dict__)
print('예2 s2.__dict__ : ', s2.__dict__)
"""
예2 vars(s1) : {'name': 'Im'}
예2 vars(s2) : {'name': 'Jigi'}
예2 s1.__dict__ : {'name': 'Im'}
예2 s2.__dict__ : {'name': 'Jigi'}
"""
"""
2023-07-05 19:19:48 Accessing 'score' giving 50
2023-07-05 19:19:48 Updating 'score' giving 70
2023-07-05 19:19:48 Accessing 'score' giving 70
2023-07-05 19:19:48 Accessing 'score' giving 70
2023-07-05 19:19:48 Accessing 'score' giving 70
2023-07-05 19:19:48 Updating 'score' giving 100
2023-07-05 19:19:48 Accessing 'score' giving 100
"""
최신 댓글