2014-11-20 6 views
2

그냥 설명자 패턴을 사용하고 싶었지만 잘 작동하지 않았습니다. 다음은 간단한 예제 (단지 보여주기 위해 실제 사용하지 않고)입니다 :비단뱀 __set__ 작동

class Num(object): 
    def__init__(self, val=0): 
    self.val = val 
    def __get__(self, instance, owner): 
    return self.val 
    def __set__(self, instance, val): 
    self.val = val 
    def __str__(self): 
    return "Num(%s)" % self.val 
    def __repr__(self): 
    return self.__str__() 

class Test(object): 
    def __init__(self, num=Num()): 
    self.num = num 

및 테스트 :

>>>t = Test() 
>>>t.num # OK 
Num(0) 
>>>t.num + 3 #OK i know how to fix that, but I thought __get__.(t.num, t, Test) will be called 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'Num' and 'int' 
>>> t.num = 4 # why isn't __set__(t.num, t, 4) called here? 
>>> t.num 
4 

내 오해가 여기에 무엇입니까?

답변

5

설명자는 인스턴스가 아닌 클래스의 속성 일 때만 작동합니다. 수업을 다음과 같이 변경 한 경우 :

class Test(object): 
    num = Num() 

. . 기술자가 작동합니다.

그러나 설명자를 클래스에 설정해야하므로 이는 설명자 인스턴스가 하나만 있다는 것을 의미하므로 설명자가 self에 값을 저장하는 것은 바람직하지 않습니다. 이러한 값은 클래스의 모든 인스턴스에서 공유됩니다. 대신 instance에 값을 설정하십시오.

또한 __str____repr__은 사용자가 생각하는대로 수행되지 않을 수 있습니다. t.num을 호출하면 설명자가 활성화되고 val이 반환되므로 t.num의 결과는 Num 인스턴스가 아닌 일반 숫자 0이됩니다. 기술자의 전체적인 점은 기술자 객체 자체를 보이지 않고 __get__의 결과를 투명하게 반환하는 것입니다. 디스크립터의 다른 버전

>>> t1 = Test() 
>>> t2 = Test() 
>>> t1.num 
0 
>>> Test.num 
0 
# Accessing the descriptor object itself 
>>> Test.__dict__['num'] 
Num(0) 
>>> t1.num = 10 
>>> t1.num 
10 
# setting the value changed it everywhere 
>>> t2.num 
10 
>>> Test.num 
10 

:

는 몇 가지 실례이다 BrenBarn이 기술자는 클래스 변수로 나타나는 바와 같이

class Num(object): 
    def __init__(self, val=0): 
    self.val = val 

    def __get__(self, instance, owner): 
    try: 
     return instance._hidden_val 
    except AttributeError: 
     # use self.val as default 
     return self.val 

    def __set__(self, instance, val): 
    instance._hidden_val = val 

class Test(object): 
    num = Num() 

>>> t1 = Test() 
>>> t2 = Test() 
>>> t1.num 
0 
>>> t1.num = 10 
>>> t1.num 
10 
# Now there is a separate value per instance 
>>> t2.num 
0 
+0

Thx, 클래스 속성이있는 힌트입니다. 방금 그 세부 사항을 놓쳤습니다. repr (t.num)이 예상대로 작동하지 않는다면, 적어도 t.num + 3은 예상대로 작동 할 것이고, 이것은 내가 실제 사용하는 경우에 원했던 것입니다 –

0

. Pythons 속성에 관심이있을 수 있습니다.

class GenericItem(object): 
    """Generic item descriptor""" 

    def __init__(self, value=None, name=""): 
     super().__init__() 

     self.value = value 
     self.name = name 
    # end Constructor 

    def __get__(self, obj, objtype): 
#   print(self, obj, objtype) 
     return self.value 
    # end __get__ 

    def __set__(self, obj, value): 
#   print(self, obj, value) 
     self.value = value 
    # end __set__ 

    def __str__(self): 
     if self.name is None or self.name == "": 
      return str(self.value) 
     return self.name +"("+str(self.value)+")" 
    # end __str__ 
# end class Num 

class Test(object): 
    def __init__(self, value=0): 
     super().__init__() 

     self._num = GenericItem(value, "Number") 
    # end Constructor 

    @property 
    def num(self): 
     """This is a number""" 
     return self._num 
    @num.setter 
    def num(self, value): 
     self._num.__set__(None, value) 
    # end num property 
# end class Test 

if __name__ == "__main__": 
    g = GenericItem(1, "Generic") 
    print(g) 
    g = 5 
    print(g) 


    t = Test() 
    print(t.num) 
    try: 
     t.num + 3 # We didn't implement any sort of addition __add__ 
    except: 
     pass 
    t.num = 4 
    print(t.num) 

결과 : 인스턴스 변수 설정 방법

Generic(1) 
5 
Number(0) 
Number(4) 

속성을 제어하는 ​​데 도움이.