プロパティのアクセス制御
前に述べたように、Python には実際のプライベート プロパティがありません。これにより、Python クラスのカプセル化が不十分になります。 Python でプライベート プロパティを定義し、パブリックにアクセスできる get メソッドと set メソッドを提供できるようにしたい場合があります。 Python は実際に魔法のメソッドを通じてカプセル化を実現(xiàn)できます。
メソッド | 説明 |
__getattr__(self, name) | このメソッドの定義存在しないプロパティにアクセスしようとしたときの動作を変更します。したがって、このメソッドをオーバーロードすると、スペルミスを検出してリダイレクトしたり、一部の非推奨の屬性について警告したりすることができます。 |
__setattr__(self, name, value) | は、屬性の割り當ておよび変更時の動作を定義します。オブジェクトの屬性が存在するかどうかに関係なく、屬性への代入が許可されます。注意すべき點は、__setattr__ を実裝するときに、「無限再帰」エラー ( |
) を回避する必要があることです。 __delattr__(self , name) | __delattr__ は __setattr__ とよく似ていますが、屬性を削除するときの動作を定義する點が異なります。 __delattr__ を実裝すると、「無限再帰」エラーを同時に回避できます。 |
__getattribute__(self, name) | __getattribute__ は、屬性にアクセスしたときの動作を定義します。 __getattr__ は、屬性が存在しない場合にのみ機能します。したがって、__getattribute__ をサポートする Python バージョンでは、「無限再帰」エラーを避けるために、__getattr__ を呼び出す前に __getattribute__``__getattribute__ を呼び出す必要があります。 |
上記のメソッド表からわかるように、屬性アクセス制御を定義する際にエラーが発生しやすくなります。次の例を見てください:
def __setattr__(self, name, value): self.name = value # 每當屬性被賦值的時候, ``__setattr__()`` 會被調用,這樣就造成了遞歸調用。 # 這意味這會調用 ``self.__setattr__('name', value)`` ,每次方法會調用自己。這樣會造成程序崩潰。 def __setattr__(self, name, value): # 給類中的屬性名分配值 self.__dict__[name] = value # 定制特有屬性
上記メソッドの具體的な呼び出し例は以下のとおりです:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- class User(object): def __getattr__(self, name): print('調用了 __getattr__ 方法') return super(User, self).__getattr__(name) def __setattr__(self, name, value): print('調用了 __setattr__ 方法') return super(User, self).__setattr__(name, value) def __delattr__(self, name): print('調用了 __delattr__ 方法') return super(User, self).__delattr__(name) def __getattribute__(self, name): print('調用了 __getattribute__ 方法') return super(User, self).__getattribute__(name) if __name__ == '__main__': user = User() # 設置屬性值,會調用 __setattr__ user.attr1 = True # 屬性存在,只有__getattribute__調用 user.attr1 try: # 屬性不存在, 先調用__getattribute__, 后調用__getattr__ user.attr2 except AttributeError: pass # __delattr__調用 del user.attr1
出力結果:
調用了 __setattr__ 方法 調用了 __getattribute__ 方法 調用了 __getattribute__ 方法 調用了 __getattr__ 方法 調用了 __delattr__ 方法