ディスクリプターとは下記のようなメソッドを備えたクラスのことである。
メソッド | 呼び出しタイミング |
---|---|
get(self,obj,type) | アトリビュートを取得するとき |
set(self,obj,value) | アトリビュートを設定するとき |
delete(self,obj) | アトリビュートを削除するとき |
getattr, __setattr__などの特殊メソッドとは異なるメソッドであるため、ディスクリプターとは区別して認識する必要がある。
・アトリビュート操作に関わる挙動を別クラスに切り出せる(=クラスをまたがるアトリビュート関連の機能を再利用できる。)
・特定のアトリビュートに対してのみ適用される挙動を定義できる。(getattr, __setattr__では、そのクラスのすべてのアトリビュートに影響)
な丼メリットがあります。ディスクリプターは、プロパティをはじめ、クラス/静的メソッド、superなどの背後でも利用されています。
#ディスクリプターの定義
class LogProp:
def __init__(self,name): #1
self.name = name #1
#アトリビュートを取得するときの処理
def __get__(self,obj,type): #2
prin(f'{self.name}:get') #2,6
return obj.__dict__[self.name] #2,4
#アトリビュートを設定するときの処理
def __set__(self,obj,value) #3
prin(f'{self.name}:set{value}') #3,7
obj.__dict__[self.name] = value #3,5
class App:
#ディスクリプターの定義
title = LogProp('title') #8
if __name__ == '__main__':
app = App()
app.title = '独習Python' #9
print(app.title) #9
ディスクリプターの側で定義しているのは、init, get, __set__です。まず、__init__メソッド(#1)は、ディスクリプターの対象となるアトリビュート名を受け取り、これを保存しています。後で値を受け渡しするためのキーとなる情報です。
そして、set(#2), get(#3)が値受け渡しのための主となるメソッドです。get, __set__は、引数経由で以下の情報を受け取ります。
obj:対象となるインスタンス
type:対象となるクラス
value:渡された値
この例であれば、__dict__を介してインスタンスの値を取得、参照しています。get, __set__はインスタンスのアトリビュート操作を肩代わりするので、なんらかの値の取得、保存操作が無い場合アトリビュート値の取得、設定は無効になります。
コード中の#4,5のような記述を最低限とし、取得、設定時の追加的な操作を加えておきましょう。この例であれば、取得、設定の結果をprintで出力しています。
定義済みのディスクリプターをアトリビュートに紐づけるには、#8のようにします。(これはproperty関数でプロパティを定義するのと同じ書き方です。)
コード中の#9のようにtitleを設定・sy津億したタイミングでログが出力されることが確認できます。
独習python 第11章オブジェクト指向構文 より引用