Python類属性アクセスの魔法方法

4730 ワード

Python類属性アクセスの魔法方法:
1. __getattr__(self,name)-ユーザーが存在しない属性を取得しようとしたときの動作を定義します.
2. __getattribute__(self,name)-クラスのプロパティがアクセスされたときの動作を定義します.
注意:getattr__と_getattribute__同時に書き換える場合、属性にアクセスする場合、優先的に__を呼び出すgetattribute__,アクセスされた属性が存在しない場合にのみトリガーされます.getattr__
3. __setattr__(self,name,value)-プロパティが設定されているときの動作を定義します.
4. __delattr__(self,name)-属性が削除されたときの動作を定義します.
>>> class C:
    def __getattribute__(self, name):
        print("getattribute")
        return super().__getattribute__(name) #      return  ,  ,c.x   __getattr__    ,       c.x   
    def __getattr__(self, name):
        print("getattr")
    def __setattr__(self, name, value):
        print("setattr")
        super().__setattr__(name, value) #     ,      ,         。         :self.name = value?      __setattr__        
    def __delattr__(self, name):
        print("delattr")
# super().__delattr__(name), , ,
>>> c = C() >>> c.x getattribute getattr >>> c.x = 999 setattr >>> c.x getattribute 999 >>> del c.x delattr
# c.x, , , , __delattr__
super().__delattr__(name)
>>> c.x
getattribute
999
>>>

また、_setattr__デッドサイクルトラップがあります.
>>> class Rect():
    def __init__(self, width=0, height=0):
        self.width = width
        self.height = height
    def __setattr__(self, name, value):
        if name == 'square':
            self.width = value
            self.height = value
        else:
            self.name = value
    def getArea(self):
        return self.width * self.height

    
>>> r = Rect(2,8)
Traceback (most recent call last):
  File "<pyshell#144>", line 1, in <module>
    r = Rect(2,8)
  File "<pyshell#143>", line 3, in __init__
    self.width = width
  File "<pyshell#143>", line 10, in __setattr__
    self.name = value
  File "<pyshell#143>", line 10, in __setattr__
    self.name = value
  File "<pyshell#143>", line 10, in __setattr__
    self.name = value
  File "<pyshell#143>", line 10, in __setattr__
……

どうしてこんなことになったの?
主に_init__内、widthとheightに値を付けると自動的にトリガーされます_setattr__メソッドは、パラメータ2,8がwidthとheightにそれぞれ入力されたときに初期化されると、付与トリガ_setattr__,2はwidth属性に渡されるのでsuqareではなくelseの文(self.name=value)が実行されますが、elseの文はまた付与文であり、自動的に__がトリガーされますsetattr__,だから、死の循環をもたらします.その解決方法は2つあります.
1.self.name=valueこの文はsuper(.)に変更されました.setattr__(name,value),親クラスの__を使用setattr__(なぜループしないの?聞かないで、どうせPythonの設計者がこの問題を解決した)
2.self.name=valueこの文はself._に変更されました.dict__[name]=value、これも賦値ですが、なぜ死循環ではないのでしょうか.ハハ、トリガー_setattr__の場合はアクセスオブジェクトのプロパティですが、ここではたまたまアクセスするのは__です.dict__(オブジェクトの特殊な属性は、現在のオブジェクトを格納するための属性の辞書です).