Python/파이썬 오픈소스 배포

Descriptor (1)

monstro 2025. 7. 7. 20:49
728x90
반응형

- 개요

Descriptor는 객체(클래스)안에서 다른 객체(클래스)속성으로 갖고 있는 형태를 의미한다

get, set, delete와 같은 데이터 조작 함수미리 정의할 수 있다는 이점을 갖고 있다

데이터를 수정하는 경우Data Descriptor, 데이터를 수정하지 않는 경우Non Data Descriptor라고 부른다

 

Descriptor를 사용하면 의도하는 방향으로 클래스를 생성할 수 있다

클래스를 생성하는 방법은 다음의 2가지 방법으로 이뤄진다

  • property 클래스를 사용하지 않고 Descriptor 클래스를 정의하는 방식
  • property 클래스를 사용하여 Descriptor 클래스를 정의하는 방식

전자의 방식을 사용하는 경우 정해진 규격에 맞춰 함수를 정의해야 하지만,

후자의 방식을 사용하면 원하는 방식으로 함수를 정의할 수 있다

 

1) property 클래스를 사용하지 않는 방식

class DescriptorEx1():
    def __init__(self, name="Default"):
        self.name = name

    def __get__(self, obj, objtype):
        return f'Get method called / self : {self} / obj : {obj} / objtype : {objtype} / name : {self.name}'

    def __set__(self, obj, name):
        print(f"Set method called")
        if isinstance(name, str):
            self.name = name
        else:
            raise TypeError('Name Should be string')

    def __delete__(self, obj):
        print(f"Delete method called")
        self.name = None

class Sample1():
    name = DescriptorEx1()

s1 = Sample1()
s1.name = "Descriptor Test1"

print(f"{s1.name}")

del s1.name

 

Descriptor 클래스로 사용할 DescriptorEx1 클래스를 위와 같이 정의하였다

정의한 함수는 각각 __init__ / __get__ / __set__ / __delete__ 함수이다

각 함수의 역할은 다음과 같다

  • 인스턴스의 초기화
  • 데이터를 read
  • 데이터를 write
  • 데이터를 delete

 

이때 property 클래스를 사용하지 않았으므로 함수의 규격과 이름을 반드시 지켜서 오버라이드해야 한다

함수들을 오버라이드함으로써 기존의 동작 방식 외에 기능을 확장할 수 있다

 

outer 클래스인 Sample1에서 멤버 변수 name에 Descriptor를 사용하였다

따라서 별다른 로직없이도 name을 사용하면 Descriptor에서 정의한 함수를 호출한다

 

 

코드 실행 결과는 위와 같다

s1.name을 설정하는 코드에서 __set__ 메서드가 호출되었고

s1.name을 출력하는 코드에서 __get__ 메서드가,

s1.name을 del하는 코드에서 __delete__ 메서드가 호출되었다

 

2) property 클래스를 사용하는 방식

property 클래스의 구성 : class property(fget=None, fset=None, fdel=None, doc=None)

 

property 클래스의 경우 위와 같이 구성되어 있다

property 클래스를 사용하여 Descriptor를 구현하는 경우 함수를 임의로 설정할 수 있다

 

class DescriptorEx2():
    def __init__(self, value):
        self._name = value

    def getter(self):
        return f'Get method called / self : {self} / name : {self._name}'

    def setter(self, value):
        print(f'Set method called')
        if isinstance(value, str):
            self._name = value
        else:
            raise TypeError('value should be str')

    def deletter(self):
        print(f'Delete method called')
        self._name = None

    name = property(getter, setter, deletter, 'Property class example')

s2 = DescriptorEx2('Descriptor Test2')

print(f'{s2.name}')

s2.name = "New Name"

del s2.name

print(f"{DescriptorEx2.name.__doc__}")

 

Descriptor 클래스로 사용할 DescriptorEx2 클래스를 위와 같이 정의하였다

1)의 방식과 같은 역할을 수행하지만 이름과 인자를 다르게 구성한 함수들을 정의하였다

 

중요한 부분은 Descriptor 클래스의 마지막에  property 클래스의 인스턴스를 생성해야 한다는 점이다

순서대로 getter 함수 / setter 함수 / deletter 함수 / Descriptor 클래스의 설명을 넘겨 인스턴스를 생성해야 한다

 

 

Descriptor 클래스의 인스턴스로부터 getter / setter / deletter 함수를 호출한 결과는 위와 같다

인스턴스로부터 name을 출력하면서 getter 함수를 호출하고

인스턴스의 name을 새롭게 설정하면서 setter 함수를, 인스턴스의 name을 del 하면서 deletter 함수를 호출한다

마지막에 Descriptor 클래스로부터 클래스의 설명을 가져와 출력한다

 

728x90
반응형

'Python > 파이썬 오픈소스 배포' 카테고리의 다른 글

오픈소스 배포 프로젝트 - 1) 커스텀 패키지 (1)  (0) 2025.07.14
Descriptor (2)  (0) 2025.07.08
메타 클래스 (3)  (0) 2025.07.05
메타 클래스 (2)  (0) 2025.07.05
메타 클래스 (1)  (0) 2025.07.04