1

私は Python のプロパティ マジックを学ぶために時間を費やしました。しかし、単純なケースを小さな間違いで書いていると、奇妙な結果が得られます。これが私のコードです:

class PropertyShow(object):
    def __init__(self):
        self.__num = 90 

    def setNum(self,value):
        self.__num = value

    def getNum(self):
        return self.__num

    def delNum(self):
        del self.__num

    #num = property(getNum,setNum,delNum)
    # I made a mistake here!
    __num = property(getNum,setNum,delNum)


class PropertyTwo(object):
    def __init__(self):
        self.__num = None

    @property
    def num(self):
        """OK, use a decorator, you can do something here!"""
        return self.__num

    @num.setter
    def num(self,value):
        self.__num = value

    @num.deleter
    def num(self):
        del self.__num

one = PropertyShow()
print one.num 
two = PropertyTwo()
print two.num

要点は「num = property(getNum,setNum,delNum)」です。この行をこの不注意に変更して、「__num = property(getNum,setNum,delNum)」のようになりました。

このコードの結果:

File "property.py", line 6, in setNum
    self.__num = value
RuntimeError: maximum recursion depth exceeded
  1. numに置き換えると、なぜこの予期しない結果が得られるの__numですか?
  2. プライベート変数の魔法を理解する方法property()と、なぜプライベート変数を使用する必要があるのですか?*
4

1 に答える 1

4

この行self.__num = valueにより、プロパティ セッターが呼び出されます。

プロパティ セッターが を設定しようとするとself.__num、プロパティ セッターが呼び出されます。プロパティ セッターが を設定しようとするとself.__num、プロパティ セッターが呼び出されます。プロパティ セッターが を設定しようとするとself.__num、プロパティ セッターが呼び出されます。プロパティ セッターが を設定しようとするとself.__num、プロパティ セッターが呼び出されます。プロパティ セッターが を設定しようとするとself.__num、プロパティ セッターが呼び出されます。プロパティ セッターが を設定しようとするとself.__num、プロパティ セッターが呼び出されます。プロパティ セッターが を設定しようとするとself.__num、プロパティ セッターが呼び出されます。プロパティ セッターが を設定しようとするとself.__num、プロパティ セッターが呼び出されます。

無限再帰が検出されました。

プロパティの名前が でない__num場合、これは明らかに起こりません。

明確にするために:Pythonは行self.__num = valueSTORE_ATTRオペコードと見なします:

>>> import dis
>>> def setNum(self, value):
...     self.__num = value
... 
>>> dis.dis(setNum)
  2           0 LOAD_FAST                1 (value)
              3 LOAD_FAST                0 (self)
              6 STORE_ATTR               0 (__num)
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE        

の実装は、STORE_ATTR最初にクラスのデータ記述子を探し、__num propertyオブジェクトを見つけます。次に、呼び出しは次のように効果的に変換されます。

PropertyShow.__num.__set__(self, value)

propertyオブジェクトは、設定されたセッター関数を検索し、それPropertyShow.setNumを として呼び出しますPropertyShow.setNum(self, value)。これがself.__num = value再び呼び出され、そこから再帰が引き継がれます。

于 2013-08-29T15:16:56.080 に答える