Programmer's Gate / Effective Python /ディスクリプタ

1   ディスクリプタ

ディスクリプタとは代入、参照、削除を扱う属性を持ったオブジェクトのことをいう。 具体的には、__get__、__set__、__delete__のいずれかを定義したオブジェクトをディスクリプタという。

ディスクリプタにより属性のデフォルト lookup の挙動を変更することができる。 property、bound method、unbound method、static method、class method、super もディスクリプタの考え方でC言語で実装されている。

2   シグネチャ

  1. __get__(self, obj, type=None) ⇒ value
  2. __set__(self, obj, value) ⇒ None
  3. __delete__(self, obj) ⇒ None

3   ディスクリプタの起動

もし d が__get__メソッドを定義していれば、通常の属性アクセス obj.d により d.__get__(obj) が自動的に実行される。 d.__get__(obj) により直接実行することも可能。

ディスクリプタ実行の詳細は obj がオブジェクトであるかクラスであるかによって異なる。

覚えておくべき重要なポイントは、

ディスクリプタの例

>>> class RevealAccess(object):
...     def __init__(self, initval=None, name='var'):
...         self.val = initval
...         self.name = name
...     def __get__(self, obj, objtype):
...         print 'Retrieving', self.name
...         return self.val
...     def __set__(self, obj, val):
...         print 'Updating', self.name
...         self.val = val
...
>>> class MyClass(object):
...     x = RevealAccess(10, 'var "x"')
...     y = 5
...
>>> m = MyClass()
>>> m.x
Retrieving var "x"
10
>>> m.x = 20
Updating var "x"
>>> m.x
Retrieving var "x"
20

クラスメソッドの実装例

>>> class ClassMethod(object):
...     "Emulate PyClassMethod_Type() in Objects/funcobject.c"
...
...     def __init__(self, f):
...         self.f = f
...
...     def __get__(self, obj, klass=None):
...         if klass is None:
...             klass = type(obj)
...         def newfunc(*args):
...             return self.f(klass, *args)
...         return newfunc
...
>>> class D:
...     @ClassMethod
...     def f(cls, x):
...         print x
...
>>> d = D()
>>> d.f(1)
1
>>> D.f(1)
1

参考文献:

  1. How-To Guide for Descriptors (http://users.rcn.com/python/download/Descriptor.htm)