プロパティのアクセス制御
前に述べたように、Python には実際のプライベート プロパティがありません。これにより、Python クラスのカプセル化が不十分になります。 Python でプライベート プロパティを定義し、パブリックにアクセスできる get メソッドと set メソッドを提供できるようにしたい場合があります。 Python は実際に魔法のメソッドを通じてカプセル化を実現できます。
メソッド | 説明 |
__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__ 方法