Date: 2006-01-04
Tags: python

pythonで辞書に構造体っぽくアクセスするメモ

(2009/3/24 追記)

あるライブラリの関数で引数objに、obj.yearとかobj.monthとかでアクセスする関数があって、テスト用にこのobjをでっち上げる必要が出てきました。素直に書くと

class MockData:
  year = 2000
  month = 1

obj = MockData()

というふうに書かないといけないのですが、このMockを使うのはunittestの中なので、以下のようにして使いたいと思いました。

obj = {'year':2000, 'month':1}

ということで、これを実現するために以下のようなクラスを用意してみました。

class DictMapper(dict):
    def __getattr__(self, name):
        try:
            attr = super(DictMapper, self).__getattr__(name)
        except:
            if not self.has_key(name):
                raise AttributeError,name
            attr = self.get(name)
        return attr

obj = DictMapper({'year':2000, 'month':1})

激しく既出の予感。あともっと簡単な方法がありそうな予感。


2009/3/24 追記

今日,使いたくなって DictWrapper で検索して見つからなかったので、 DictWrapper でも検索されるようにコメントしておく。

それはそれとして手元に__setattr__してる版が見つかった。あと__getattr__で辞書に無い値にアクセスしたときにNoneを返しているあたりRubyっぽい感じで緩い。__getattr__は属性値があればメソッド呼び出されないので、上記エントリに書いていたsuper(...)は不要だった。

class DictMapper(dict):
   def __getattr__(self, name):
       if name in self:
           return self[name]
   def __setattr__(self, name, value):
       self[name] = value

In [1]: obj = DictMapper({'year':2000, 'month':1})
In [2]: obj.keys()
Out[2]: ['year', 'month']
In [3]: obj.keys
Out[3]: <built-in method keys of DictMapper object at 0x02444A48>
In [4]: obj.keys = 1
In [5]: obj.keys
Out[5]: 1