0Pricing
Python Academy · 강의

디스크립터: __get__, __set__, __delete__

속성 액세스 제어를 위해 디스크립터 프로토콜을 구현합니다.

디스크립터: __get__, __set__, __delete__은(는) CoddyKit의 무료 Python Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Python Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Python Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

Descriptor란 무엇인가

디스크립터는 __get__, __set__ 또는 __delete__를 정의하고 클래스 속성으로 할당되는 객체입니다. Python은 속성에 접근할 때 이러한 메서드를 호출합니다.

class Descriptor:
    def __get__(self, obj, objtype=None):
        print(f"__get__ called, obj={obj}")
        return 42

class MyClass:
    attr = Descriptor()

print(MyClass().attr)   # __get__ called ... 42

데이터 디스크립터와 비데이터 디스크립터 비교

데이터 디스크립터는 __set__ 또는 __delete__를 정의하며 인스턴스의 __dict__보다 우선합니다. 비데이터 디스크립터는 __get__만 정의하며 __dict__에 우선권을 양보합니다.

class DataDesc:
    def __get__(self, obj, t): return "data"
    def __set__(self, obj, val): pass

class NonDataDesc:
    def __get__(self, obj, t): return "nondata"

class C:
    d = DataDesc()
    n = NonDataDesc()

c = C()
c.__dict__["n"] = "instance"  # shadows the non-data desc
c.__dict__["d"] = "instance"  # does NOT shadow data desc
print(c.n)   # instance
print(c.d)   # data

__get__ 시그니처

__get__(self, obj, objtype)에서 obj는 인스턴스입니다(클래스에서 접근하면 None). objtype은 클래스입니다.

class Verbose:
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self   # accessed on class
        return f"value for {obj!r}"

class Widget:
    label = Verbose()

print(Widget.label)        # <Verbose object>
print(Widget().label)      # value for <Widget object>

__set__과 유효성 검사

값을 저장하기 전에 유효성을 검사하거나 변환하려면 __set__(self, obj, value)를 구현하세요.

class PositiveInt:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, obj, t):
        return obj.__dict__.get(self.name)

    def __set__(self, obj, val):
        if not isinstance(val, int) or val <= 0:
            raise ValueError(f"{self.name} must be a positive int")
        obj.__dict__[self.name] = val

class Rect:
    width  = PositiveInt()
    height = PositiveInt()

r = Rect()
r.width = 10
# r.width = -1  # ValueError

__set_name__

Python 3.6 이상에서는 디스크립터가 클래스에 할당될 때 __set_name__(owner, name)을 호출하여 디스크립터가 자신의 속성 이름에 접근할 수 있게 합니다.

class Typed:
    def __set_name__(self, owner, name):
        self.public  = name
        self.private = "_" + name

    def __get__(self, obj, t):
        return None if obj is None else getattr(obj, self.private, None)

    def __set__(self, obj, val):
        setattr(obj, self.private, val)

class User:
    name = Typed()

u = User()
u.name = "Alice"
print(u.name)     # Alice

속성 제거를 위한 __delete__

del obj.attr을 가로채려면 __delete__(self, obj)를 정의하세요.

class Protected:
    def __set_name__(self, owner, name): self.name = name
    def __get__(self, obj, t):
        return obj.__dict__.get(self.name)
    def __set__(self, obj, v): obj.__dict__[self.name] = v
    def __delete__(self, obj):
        raise AttributeError(f"Cannot delete {self.name}")

class Config:
    host = Protected()

c = Config(); c.host = "localhost"
# del c.host   # AttributeError

함수는 비데이터 디스크립터입니다

함수는 __get__을 구현하여 인스턴스에서 접근할 때 바인딩된 메서드를 반환합니다. 이것이 Python에서 메서드 바인딩이 작동하는 방식입니다.

def greet(self):
    return f"Hello from {self}"

class C: pass
C.greet = greet

c = C()
print(c.greet())    # Hello from <C object>

classmethod와 staticmethod는 디스크립터입니다

classmethod와 staticmethod는 함수를 감싸고 __get__의 반환값을 변경하는 내장 디스크립터 클래스입니다.

class MyClass:
    @classmethod
    def from_string(cls, s):
        return cls()

# classmethod.__get__ returns a bound method with cls
# staticmethod.__get__ returns the plain function

지연 속성 디스크립터

값을 한 번 계산한 뒤 인스턴스별로 캐시하는 디스크립터를 만들어 보세요.

class LazyAttr:
    def __init__(self, func): self.func = func
    def __set_name__(self, owner, name): self.name = name
    def __get__(self, obj, t):
        if obj is None: return self
        val = self.func(obj)
        obj.__dict__[self.name] = val   # shadows descriptor
        return val

class Report:
    @LazyAttr
    def summary(self):
        print("computing...")
        return "done"

r = Report()
print(r.summary)   # computing... done
print(r.summary)   # done (cached)

property는 디스크립터입니다

property 자체가 C로 구현된 데이터 디스크립터입니다. 디스크립터를 이해하면 @property, @classmethod, @staticmethod가 모두 작동하는 방식을 이해하는 데 도움이 됩니다.

class Circle:
    def __init__(self, r): self._r = r

    @property
    def radius(self): return self._r

    @radius.setter
    def radius(self, v):
        if v < 0: raise ValueError
        self._r = v

# property is: property.__get__ = fget, property.__set__ = fset

디스크립터 조회 순서

파이썬 속성 조회 순서: 1) 타입(MRO)의 데이터 디스크립터, 2) 인스턴스 __dict__, 3) 비데이터 디스크립터와 클래스 변수입니다.

# Pseudocode for obj.attr:
# 1. Check type(obj).__mro__ for a data descriptor
# 2. Check obj.__dict__
# 3. Check type(obj).__mro__ for non-data descriptor or class var
# 4. Raise AttributeError

빠른 확인

인스턴스 __dict__보다 우선하는 디스크립터 유형은 무엇입니까?

복습

디스크립터는 __get__, __set__, __delete__를 통해 속성 접근을 가로챕니다. 데이터 디스크립터는 인스턴스 __dict__를 가리지만, 비데이터 디스크립터는 그렇지 않습니다. __set_name__을 사용하면 속성 이름을 알 수 있습니다. property, classmethod, staticmethod는 모두 디스크립터입니다.

자주 묻는 질문

“디스크립터: __get__, __set__, __delete__” 강의는 무료인가요?

네 — “디스크립터: __get__, __set__, __delete__” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Python Academy 강의 전체를 잠금 해제할 수 있습니다. Python Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“디스크립터: __get__, __set__, __delete__”에서 뭘 배우나요?

속성 액세스 제어를 위해 디스크립터 프로토콜을 구현합니다. 브라우저에서 직접 실행하는 실습 코드로 Python Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Python Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Python Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“디스크립터: __get__, __set__, __delete__” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Python Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Python Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Python 클래스가 생성되는 방식
  2. 사용자 정의 메타클래스 작성
  3. 디스크립터: __get__, __set__, __delete__
  4. __slots__와 메모리 최적화
← Python Academy(으)로 돌아가기