Pythonの技法:プロパティによるアクセサの実装
プロパティは関数の属性値の設定、取得、削除を定義する一つの方法である。プロパティが提供するメソッドを用いると、フィールドへのアクセス方法を定義して、フィールドの標準的なインタフェースを使用することが可能になる。
先ほどのクラスを別の方法で実装してみよう。
class C(object): y = 3 z = 4 def __init__(self): self.__x = 2 def getx(self): return self.__x def setx(self, val): print "x is read only" x = property(getx, setx)
このクラスでは変数xをプロパティとし、getx関数とsetx関数を用いてアクセスできるようにしている(オプションの第3引数を指定すると、値の削除が可能になる。また、第4引数ではdocstringを指定できる。しかし、それらは今のところ気にしなくてよいだろう)。
このようにして定義されたCクラスでは、より自然な方法でフィールドを使用できる。
>>> i = C() >>> i.x, i.y, i.z (2, 3, 4) >>> i.x = 5 x is read only >>> dir(i) ['_C__x', '__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'getx', 'setx', 'x', 'y', 'z'] >>> i._C__x = 5 >>> i.x, i.y, i.z (5, 3, 4)
ただし、プロパティを用いても、内部をよく調べればまだ変数に直接アクセスすることが可能だ。
プロパティを用いずに同様の機能を実現する手法としては、属性を設定する際にデフォルトで用いられるメソッドをオーバーライドしてしまう方法がある。この手法を用いた場合、コードは次のようになる。
class D(object):
x = 2
y = 3
z = 4
def __setattr__(self, name, val):
if name != 'x':
self.__dict__[name] = val
else:
print "%s is read only" % (name)
使い方はほとんど同じだ。
>>> i = D() >>> i.x, i.y, i.z (2, 3, 4) >>> i.x = 5 x is read only >>> dir(i) ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'x', 'y', 'z'] >>> i.__dict__['x'] = 5 >>> i.x, i.y, i.z (5, 3, 4)
Pythonの哲学である「There’s only one way to do it」(それを実行する方法は一通りしかない)からは逸脱することになるかもしれないが、どの手法を用いるかはあなた自身が決めることである。本稿で挙げたような小規模な例では、プロパティを用いるとgetterやsetterをそれぞれのフィールドに記述する必要が生じ、コード量が増加してしまう。しかし、それぞれに異なった動作をさせたい場合は、__setattr__関数にすべてを詰め込もうとすると、ずっと読みにくく保守しにくいコードになってしまうだろう。
この記事は海外CNET Networks発のニュースをシーネットネットワークスジャパン編集部が日本向けに編集したものです。海外CNET Networksの記事へ
- ホワイトペーパー



