프로그래밍 언어/Python

파이썬에서 @property 데코레이터의 작동원리

Rateye 2021. 6. 26. 13:51
728x90
반응형
질문 : @property 데코레이터는 파이썬에서 어떻게 작동합니까?

property 어떻게 작동하는지 이해하고 싶습니다. 나를 혼란스럽게하는 것은 property 을 데코레이터로도 사용할 수 있지만, 내장 함수로 사용할 때만 인수를 사용하고 데코레이터로 사용할 때는 인수를 사용하지 않는다는 것입니다.

이 예는 문서 에서 가져온 것입니다.

class C:
    def __init__(self):
        self._x = None

    def getx(self):
        return self._x

    def setx(self, value):
        self._x = value

    def delx(self):
        del self._x
        x = property(getx, setx, delx, "I'm the 'x' property.")

property 의 인수는 getx , setx , delx 및 doc 문자열입니다.

아래 코드에서 property 은 데코레이터로 사용됩니다. 객체는 x 함수이지만 위의 코드에서는 인수에 객체 함수를위한 위치가 없습니다.

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

이 경우 x.setterx.deleter 데코레이터는 어떻게 생성됩니까?

답변

property() 함수는 특수 설명자 객체를 반환합니다.

>>> property()
<property object at 0x10ff07940>
                                 

추가 메서드가있는 것은이 개체입니다.

>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>
                                                                                   

이것들은 장식 자 역할 합니다. 새 속성 개체를 반환합니다.

>>> property().getter(None)
<property object at 0x10ff079f0>
                                     

이전 개체의 복사본이지만 함수 중 하나가 교체되었습니다.

@decorator 구문은 단지 구문 적 설탕이라는 것을 기억하십시오. 구문 :

@property
def foo(self): return self._foo

정말 같은 의미

def foo(self): return self._foo
foo = property(foo)
                                

그래서 foo 함수는 위에서 본 특별한 객체 인 property(foo) 로 대체됩니다. @foo.setter() 를 사용할 때 property().setter 메서드를 호출하여 속성의 새 복사본을 반환하지만 이번에는 setter 함수를 데코 레이팅 된 메서드로 바꿉니다. .

다음 시퀀스는 이러한 데코레이터 메서드를 사용하여 전체 속성을 만듭니다.

먼저 getter만으로 몇 가지 함수와 property

>>> def getter(self): print('Get!')
...
>>> def setter(self, value): print('Set to {!r}!'.format(value))
...
>>> def deleter(self): print('Delete!')
...
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True
              

다음으로 .setter() 메서드를 사용하여 setter를 추가합니다.

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True
                      

마지막으로 .deleter() 메서드를 사용하여 삭제자를 추가합니다.

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True
                          

마지막으로 property 객체는 설명자 객체 역할을하므로 .__get__() , .__set__().__delete__() 메서드를 사용하여 인스턴스 속성 가져 오기, 설정 및 삭제에 연결합니다.

>>> class Foo: pass
...
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!
                     

Descriptor Howto에는 property() 유형 의 순수 Python 샘플 구현 이 포함되어 있습니다.

class Property:
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
            self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

 

출처 : https://stackoverflow.com/questions/17330160/how-does-the-property-decorator-work-in-python
728x90
반응형