Pythonのデスクリプタをわかりやすく解説

pythonデスクリプタpython
  • デスクリプタの例としてpropertyやメソッドがある
  • 特殊メソッド__get__(), __set__(), __delete__()のいずれか1つでも持っていればそれはデスクリプタだ
  • 特に
    • データデスクリプタ … __set__(), __delete__()のいずれかまたは両方を持つもの
    • 非データデスクリプタ … __get__()しか持たないもの

 

スポンサーリンク

実際にデスクリプタを使ってみる

デスクリプタのインスタンスをクラス変数として利用すると、そのクラス変数をインスタンス変数のように扱えます。

クラスについてはこちらをご覧ください👇

 

属性の取得や代入、削除時にはデスクリプタが実装している__get__()や__set__()、__delete__()の対応するメソッドが呼ばれます。

_set_()を実装する(データデスクリプタ)

属性代入時の処理をオーバーライドするデスクリプタTextFieldです。

 

class TextField:
    def __set_name__(self, owner, name):
        print('~~~__set_name__ was called~~~')
        print(f'{owner=}, {name=}')
        self.name = name
        
    def __set__(self, instance, value):
        print('~~~__set__ was called~~~')
        if not isinstance(value, str):
            raise AttributeError('must be str!')
        instance.__dict__[self.name] = value
        
    def __get__(self, instance, owner):
        print('~~~__get__ was called ~~~')
        return instance.__dict__[self.name]  #下の例でbookがinstance、nameがtitle

このデスクリプタを利用するBookという名のクラスを次のように定義します。

デスクリプタを利用するクラス(つまりBook)では、デスクリプタのインスタンスをクラス変数として利用します。

特殊メソッド__set_name__()には、そのデスクリプタを利用するクラスオブジェクト(ここではBook)と、デスクリプタに割り当てられた変数名が渡さます。

class Book:
    title = TextField()
-------------------------------------------------
#出力
~~~__set_name__ was called~~~
owner=<class '__main__.Book'>, name='title'

Bookクラスを利用するときは、クラス変数titleをインスタンス変数のように使えます。

book = Book()
book.title = 'python practive book'
-------------------------------------------------
#出力
~~~__set__ was called~~~
-------------------------------------------------
book.title
-------------------------------------------------
#出力
~~~__get__ was called ~~~
'python practive book'
-------------------------------------------------
notebook = Book()
notebook.title = 'Notebook'
-------------------------------------------------
#出力
~~~__set__ was called~~~
-------------------------------------------------
notebook.title
-------------------------------------------------
#出力
~~~__get__ was called ~~~
'Notebook'
-------------------------------------------------
book.title = 3
-------------------------------------------------
#出力
-------------------------------------------------
~~~__set__ was called~~~
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in 
----> 1 book.title = 3

 in __set__(self, instance, value)
      8         print('~~~__set__ was called~~~')
      9         if not isinstance(value, str):
---> 10             raise AttributeError('must be str!')
     11         instance.__dict__[self.name] = value
     12 

AttributeError: must be str!
__get__()のみを実装する(非データデスクリプタ)

”非データデスクリプタはインスタンス変数よりも優先度が低い”ということに注意しましょう。

 

class TextField:
    def __init__(self, value):
        if not isinstance(value, str):
            raise AttriubuteError('must be str!')
        self.value = value
        
    def __set_name__(self, owner, name):
        print('~~~__set_name__ was called~~~')
        print(f'{owner=}, {name=}')
        self.name = name
        
    def __get__(self, instance, owner):
        print('~~~__get__ was called~~~')
        return self.value
-------------------------------------------------
class Book:
    title = TextField('Python practice book')
-------------------------------------------------
#出力
~~~__set_name__ was called~~~
owner=<class '__main__.Book'>, name='title'
-------------------------------------------------
book = Book()
book.title
-------------------------------------------------
#出力
~~~__get__ was called~~~
'Python practice book'
-------------------------------------------------
book.title = 'new setting'  #__get__()のみにもかかわらず代入するとインスタンス変数になる
-------------------------------------------------
book.title  #インスタンス変数があると__get__()は呼ばれない
-------------------------------------------------
#出力
'new setting'

 

参考書籍:

『Python実践入門ー言語の力を引き出し、開発効率を高める』

陶山嶺 著

WEB+DB PRESS plusシリーズ

技術評論社

Python実践入門 ──言語の力を引き出し、開発効率を高める
Pythonはここ数年で日本語の書籍も増え,開発現場での利用実績も着実に増えてきています。ご自身の第二,第三の言語の選択肢としてPythonが気になっているという方も多いのではないでしょうか。また,「Pythonを始めてみたけど,実際に業務で利用するには不安が残る」「コードレビューに怯えながらPythonを書いている」...
タイトルとURLをコピーしました