C#にプロパティというものがある。例えばリストLがあったときに
リストの長さをL.length()やL.size()でなく、L.lengthやL.sizeで書けたら
便利である。しかし、メソッドでなく、変数で実現すると、例えばエラーチェック
などの処理を入れることができない。構文は変数で、機能的にはメソッドの方式を
利用できるものを実現するのがプロパティである。
>>> class Foo(object):
... def __init__(self):
... self.__x = None
... def getx(self):
... print 'getx() is called.'
... return self.__x
... def setx(self, val):
... print 'setx() is called.'
... self.__x = val
... x = property(getx, setx, None, 'property of x')
...
>>> f = Foo()
>>> f.x = 1
setx() is called.
>>> f.x
getx() is called.
1
また、propertyは新スタイルクラスのみで対応しているので、新スタイルクラスで定義する必要がある。
上記のサンプルは通常の方法だと思うが、Fooクラスに対してgetx、setxという名前を追加してしまう。
これを回避するには、以下のようにする。
>>> class Foo2(object):
... def __init__(self):
... self.__x = None
... def x():
... doc = 'property of x'
... def fget(self):
... return self.__x
... def fset(self, value):
... self.__x = value
... return locals()
... x = property(**x())
...
>>> set(dir(Foo2)) - set(dir(Foo))
set(['getx', 'setx'])
x = property(**x()) の部分は、以下のようにデコレータを用いても良い。
>>> class Foo2(object):
... def __init__(self):
... self.__x = None
... def nested_property(c):
... return property(**c())
... @nested_property
... def x():
... doc = 'property of x'
... def fget(self):
... return self.__x
... def fset(self, value):
... self.__x = value
... return locals()
但し、逆に Foo に nested_property という名前が追加されてしまう。
ここで、self.xでなくself.__xとしているのは、 データ・マングリング という
機能を使用しているためで、外側から直接self.__xでアクセスできないようにしている。
>>> f.__x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__x'
>>> f._Foo__x
1
このようにアンダーバーを2つ重ねて変数を書くと、この場合では、__xは
クラスFooの中で自動的に、_Foo__xに変換されてクラスの外側からは隠される
(逆に言えば、f._Foo__xでアクセスできる)。
インスタンスメソッドでなく、クラスメソッドを定義するには以下の方法を用いる。
>>> class Foo:
... @staticmethod
... def foo1():
... print 'staticmethod'
... @classmethod
... def foo2(cls):
... print 'classmethod', cls
...
>>> Foo().foo1()
staticmethod
>>> Foo().foo2()
classmethod __main__.Foo
@は デコレータ と呼ばれているもので、
上記の場合、foo1 = staticmethod(foo1)、foo2 = classmethod(foo2)を意味する。
つまり、関数のラッパーとして機能する単なるシンタックスシュガーである。
参考文献:
- 『Python Cookbook 2nd Edition』; 20. Descriptor, Decorators, and Metaclasses; 20.2 Coding Properties as Nested Functions