Pythonの技法:プロパティによるアクセサの実装

文:Nick Gibson(Builder AU)  翻訳校正:原井彰弘
2008-01-07 18:00:00
  • このエントリーをはてなブックマークに追加
最新特集【一覧】

 まずは、属性をいくつか持った単純なクラスを書くことから始めてみよう。以下のようなクラスを定義する。

class A(object):
    x = 2
    y = 3
    z = 4

 このコードは、予想通り次のように動作するはずだ。

>>> i = A()
>>> i.x, i.y, i.z
(2, 3, 4)
>>> i.x = 0
>>> i.x
0

 このクラスを単純なレコードとして使用している限り、これで何も問題はない。しかし、フィールドを一つ読み取り専用にしなければならなくなった場合はどうすればよいだろうか?次のようにgetterとsetterを記述すればよい。

class B(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"

 この場合、使い方は次のようになる。

>>> i = B()
>>> i.getx(), i.y, i.z
(2, 3, 4)
>>> i.setx()
x is read only
>>> i.x
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'B' object has no attribute 'x'
>>> dir(i)
['_B__x', '__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__str__', '__weakref__', 'getx', 'y', 'z']
>>> i._B__x = 0
>> i.getx()
0

 単に誤って上書きしてしまうことのないようxの値を保護したいだけの場合、この結果は歓迎できるだろう。しかしこの方法では、xの値を探し出して強引に変更することもまだ可能だ。2つのアンダースコアで始まるクラスの属性は、Pythonではクラス名を含む名前に変更されるのである。このしくみによって、一見アクセス不可能だが実は依然としてアクセス可能な「疑似プライベート変数」が定義されるのだ。

 また、Bクラスは明らかにインタフェース上の問題を抱えている。xフィールドへのアクセス方法は、ほかのフィールドへのアクセス方法とまったく異なっているのである。getメソッドとsetメソッドを他の2つのフィールドについても定義し、この問題を修正することも可能だが、それよりもよい方法がある。プロパティを使うのだ。

  • 新着記事
  • 特集
  • ブログ