StoryEdit 開発日誌

ウェブアプリ StoryEditを作ってましたが延期。普通のブログ。

Pythonで__slots__を使う

Pythonも遊び程度で使ってきたので詳しくしらなかったのですが,便利な機能があるのですね.

てわけで,とりあえず気に入った__slots__について.

スクリプト言語は,クラスを作ったとして,フィールドをいつでもどこでも加えられるように辞書型のフィールドを保持していることがほとんどですね.Javascriptのプロトタイプベースのクラスも良い例です.配列もってます.Pythonは,クラスをネイティブにサポートしていますが,デフォルトでは普通に辞書をもっているようです.

しかし,さすが,長年使われてきただけあって,ネイティブクラスの動作をいろいろカスタマイズできちゃうわけですね.う〜ん.時間がたったソフトウェアってこういうところがすてきだなぁ.

今回紹介する__slots__は,クラスの変数名前保管用の配列です.
普段は,ここに辞書を使っているらしいのですが,slotsを指定すれば,固定長の配列になります.
フィールドの名前を固定長配列にするメリットは以下です.

  • メモリを節約できる.マップーー>配列になるので
  • まちがった代入がおきない!

この二点です.どちらも魅力的ですね.私なんかは動的言語のデバッグ難易度が極度に高くて嫌いです.
しかし,この__slots__を使えば,おかしな代入を行えなくなります.以下のコードをみてください.

  class T1(object):
   def  __init__ (self):
    self.isSuccess = False;
   
   def setSuccess(self):
    self.isSucccess = True;

  def printIsSuccess(self):
    print self.isSuccess;

  t =T1();
  t.printIsSuccess();
  t.setSuccess();
  t.printIsSuccess();

実行結果

$ python hoge.py 
False
False

さぁ,こういうことありますよね!そう,スペルミスです!
X Succcess
O Success
ですね.便利さの代償の高さを物語っています.さぁこれを,__slots__を使って検出しちゃいましょう.

class T1(object):
  __slots__ = ['isSuccess']
  def  __init__ (self):
    self.isSuccess = False;

  def setSuccess(self):
    self.isSucccess = True;

  def printIsSuccess(self):
    print self.isSuccess;

t = T1();
t.printIsSuccess();
t.setSuccess();
t.printIsSuccess();

実行結果

$ python hoge.py 
False
Traceback (most recent call last):
  File "hoge.py", line 15, in <module>
    t.setSuccess();
  File "hoge.py", line 7, in setSuccess
    self.isSucccess = True;
AttributeError: 'T1' object has no attribute 'isSucccess'

すてきですね.これでだいぶデバッグが楽になります.

注意:クラスの宣言に class T1ではなく,class T1(object) としないとこれらの機能はうまく使えないみたいです.(ここは理由は知りませんw)

しばらくは__slots__のお世話になります.しかし,書きにくいっちゃあ書きにくい.
フレームワークとかでこのへんがんばってくれればいいのに.