Pythonの中のdescriptor説明器は簡明に手引きを使用します。

2942 ワード

ローズマリーを定義するとき、説明は反復プロトコルを実装するオブジェクトであり、すなわち、__uiter_メソッドの対象。同じように、説明器とは、記述子プロトコル、すなわち、___uget_,_set_同前delete_uメソッドの対象。
定義だけを見ると、やはり抽象的です。talk is cheap。コードを見てください

class WebFramework(object):
  def __init__(self, name='Flask'):
    self.name = name

  def __get__(self, instance, owner):
    return self.name

  def __set__(self, instance, value):
    self.name = value


class PythonSite(object):

  webframework = WebFramework()

In [1]: PythonSite.webframework
Out[1]: 'Flask'

In [2]: PythonSite.webframework = 'Tornado'

In [3]: PythonSite.webframework
Out[3]: 'Tornado'

クラスWebFraameweorkを定義し、ディスクリプタプロトコルを実現しました。ゲットする同前set_,このオブジェクト(クラスもオブジェクトで、すべてが対象)は、説明器になります。同時に実現しますゲットする同前set_のことを資料記述器と言います。ただ叶うだけゲットするを選択します。両者の違いは、実例に対する辞書の優先度である。
例の辞書に記述器と同名の属性がある場合、説明器が資料記述器である場合は、資料記述器を優先的に使用し、非資料記述器であれば、辞書の属性を優先的に使用する。
説明器の呼び出し
このような魔法に対しては、その呼び方は直接的には使われない場合が多いです。例えば、飾り器は@記号で呼び出す必要があります。頻繁に繰り返されるプロセスで、またはnextメソッドを使用して起動されます。説明器は簡単です。オブジェクト属性の場合は呼び出します。

In [15]: webframework = WebFramework()

In [16]: webframework.__get__(webframework, WebFramework)
Out[16]: 'Flask'

説明器の応用
記述器の役割は主に方法と属性の定義にある。私たちはクラスの属性をもう一度説明することができますので、この魔法はクラスの行動を変えることができます。最も簡単なアプリケーションは、装飾器に合わせてクラスの属性を書くことができるキャッシュです。Flashkの作者はwerkzugネットワークツールライブラリを書きました。ここでは説明器の特性を使ってバッファを実現しました。

class _Missing(object):
  def __repr__(self):
    return 'no value'

  def __reduce__(self):
    return '_missing'


_missing = _Missing()


class cached_property(object):
  def __init__(self, func, name=None, doc=None):
    self.__name__ = name or func.__name__
    self.__module__ = func.__module__
    self.__doc__ = doc or func.__doc__
    self.func = func

  def __get__(self, obj, type=None):
    if obj is None:
      return self
    value = obj.__dict__.get(self.__name__, _missing)
    if value is _missing:
      value = self.func(obj)
      obj.__dict__[self.__name__] = value
    return value


class Foo(object):
  @cached_property
  def foo(self):
    print 'first calculate'
    result = 'this is result'
    return result


f = Foo()

print f.foo  # first calculate this is result
print f.foo  # this is result

運転の結果、ファーストコール時に計算されただけで結果がキャッシュされます。このような利点は、ネットワークプログラミングにおいて、HTTPプロトコルの解析は、通常HTTPのheaderをpythonの辞書に解析していますが、ビュー関数の場合は、一回の訪問は知らないかもしれないので、このheaderを記述器でキャッシュして、余分な解析を減らすことができます。
説明器はpythonで広く使われています。一般的にアクセサリーと一緒に使用されます。強大な魔法は強大な責任から来ます。記述器はまた、ORMにおけるsql文の「プリコンパイル」を実現するために使用されてもよい。説明器を適切に使うことで、Pythonコードをより優雅にすることができます。