或阿呆のブログ

Pythonを好んで使っているプログラマです。Ruby,Perl,PowerShell,VBAなどでもたまに書いています。おバカなことが大好きです。

Python propertyでsetter/getterを実装する。

Pythonを使い始めてからというもの、正直、カプセル化*1なんて気にしたことなかった(笑)

Pythonってこんなことも出来ちゃうし。

組み込み関数の上書き

>>> type(sum)
<type 'builtin_function_or_method'>
>>> sum = 0
>>> type(sum)
<type 'int'>

定義値の上書き

>>> True = False
>>> True
False

ここまで来ると、、、

変数に破壊的な代入やろうが、プログラマの責任じゃね?!的な意識が芽生えてくる。

propertyとかsetterとかgetterとか

こんどは、カプセル化を意識して、propertyとかsetterとかgetterとかを使って実装してみる。

以下のようなクラスがあったとする。クラスサンプルAは、クラス変数を直接操作する実装。つまり、クラスを使う側が、クラス変数をどんな風に使おうと勝手というわけです。文字列を期待しているものに数値を入れようが、クラスインスタンスを入れようが勝手というわけです。

クラスサンプルBは、クラス変数を操作するのに、setter/getterを使い、間接的に操作する。こうすることによって、クラス変数は隠蔽される。カプセル化によるメリットは、内部処理を隠すことによって、変更に強くなるというメリットが生まれる。クラス内部のデータ構造や、振る舞いを意識する必要があると、どうしてもクラス間の結合が蜜になり、変更に弱くなる。

クラスサンプルA

>>> class A():
...     def __init__(self):
...         self.x = 'spam'
... 

xはクラスAの属性

>>> a = A()
>>> dir(a)
['__doc__', '__init__', '__module__', 'x']

インスタンスaを生成をしdir関数でaの属性を見るとxが見えている。

xの参照/設定/削除
>>> a.x
'spam'
>>> a.x = 'ham'
>>> a.x
'ham'
>>> del a.x
>>> dir(a)
['__doc__', '__init__', '__module__']

直接xに代入して、削除しますよという話。

クラスサンプルB

>>> class B():
...      def getx(self): return self._x
...      def setx(self, value): self._x = value
...      def delx(self): del self._x
...      x = property(getx, setx, delx, "I'm the 'x' property.")

x,_xはクラスBの属性

>>> b = B()
>>> dir(b)
['__doc__', '__module__', 'delx', 'getx', 'setx', 'x']

インスタンス生成をしdir関数でbの属性を見るとxが見えている。_xは見えていない。というか、変数_xに代入をしていないので生成すらされていない。

xの参照/設定/削除
>>> b.x
Traceback (most recent call last):
  File "<ipython-input-39-4fa97807159e>", line 1, in <module>
    b.x
  File "<ipython-input-34-58b786e1bd44>", line 2, in getx
    def getx(self): return self._x
AttributeError: B instance has no attribute '_x'

インスタンスbの属性xを参照しようとすると、_xが無いよと怒られる。つまり、xを参照すると、内部にある_xが参照されているということ。

>>> b.x = 'spam'
>>> dir(b)
['__doc__', '__module__', 'delx', 'getx', 'setx', 'x']

インスタンスbの属性xに値を設定した。先ほどと同様、dir関数でbの属性を見るとxが見えているが、_xは見えていない。

>>> b.x
'spam'

インスタンスbの属性xを参照した。内部的には_xの値が返却される。

>>> del b.x
>>> dir(b)
['__doc__', '__module__', 'delx', 'getx', 'setx', 'x']

インスタンスbの属性xを削除した。dir関数でbの属性を見るとxが見えている。内部的には_xが削除されている。

>>> b.x
Traceback (most recent call last):
  File "<ipython-input-51-4fa97807159e>", line 1, in <module>
    b.x
  File "<ipython-input-34-58b786e1bd44>", line 2, in getx
    def getx(self): return self._x
AttributeError: B instance has no attribute '_x'
>>>

再びインスタンスbの属性xを参照すると_xが無いと怒られる。

まとめ

Pythonでも、オブジェクト指向で言うところのproperty/setter/getterは、実装出来る。C#みたいに、勝手にsetter/getterを作ってくれると便利なんだけどなぁ。。。

初めてのPython 第3版

初めてのPython 第3版


独習C# 第3版

独習C# 第3版

  • 作者: ハーバート・シルト,エディフィストラーニング株式会社矢嶋聡
  • 出版社/メーカー: 翔泳社
  • 発売日: 2010/12/03
  • メディア: 大型本
  • 購入: 5人 クリック: 55回
  • この商品を含むブログ (6件) を見る

*1:情報隠蔽のこと。オブジェクト指向において重要な概念