PHpullh
학습 라이브러리/Python/Descriptor & __get__ __set__

PYTHON · 기초 문법

Descriptor & __get__ __set__

Python의 속성 접근 메커니즘을 제어하는 디스크립터 프로토콜.

기초 문법고급descriptor__get____set____set_name__validator

핵심 설명

Python의 속성 접근 메커니즘을 제어하는 디스크립터 프로토콜.

Python code

class Validator:
    """값 검증 디스크립터"""
    def __set_name__(self, owner, name):
        self.name = name
        self.private = f"_{name}"

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self  # 클래스에서 접근 시
        return getattr(obj, self.private, None)

    def __set__(self, obj, value):
        self._validate(value)
        setattr(obj, self.private, value)

    def _validate(self, value): ...

class PositiveInt(Validator):
    def _validate(self, value):
        if not isinstance(value, int) or value <= 0:
            raise ValueError(f"{self.name}은 양의 정수여야 함: {value}")

class RangeFloat(Validator):
    def __init__(self, lo, hi):
        self.lo, self.hi = lo, hi

    def _validate(self, value):
        if not (self.lo <= value <= self.hi):
            raise ValueError(f"{self.name}은 {self.lo}~{self.hi} 범위: {value}")

class Product:
    price    = PositiveInt()
    quantity = PositiveInt()
    discount = RangeFloat(0.0, 1.0)

    def __init__(self, price, quantity, discount):
        self.price = price
        self.quantity = quantity
        self.discount = discount

    @property
    def total(self):
        return self.price * self.quantity * (1 - self.discount)

p = Product(1000, 5, 0.1)
print(p.total)   # 4500.0

try:
    p.price = -100
except ValueError as e:
    print(e)

학습 팁

__set_name__은 Python 3.6+에서 클래스 정의 시 자동으로 호출됩니다. 디스크립터가 어느 클래스의 어떤 이름으로 사용되는지 알 수 있습니다.

주의할 점

__get__에서 obj is None 체크를 하지 않으면 클래스에서 직접 접근할 때(Product.price) 오류가 발생합니다.

자주 묻는 질문

Descriptor & __get__ __set__란 무엇인가요?

Python의 속성 접근 메커니즘을 제어하는 디스크립터 프로토콜.

Descriptor & __get__ __set__ 학습 시 주의할 점은 무엇인가요?

__get__ 에서 obj is None 체크를 하지 않으면 클래스에서 직접 접근할 때( Product.price ) 오류가 발생합니다.