LoginSignup
1
6

More than 5 years have passed since last update.

辞書のテンプレートをクラスで定義する

Last updated at Posted at 2018-11-26

(たぶんけっこう基本的な話)

{key1: value1,
 key2: value2, ...,
 subdic1: {
     key_s1: value_s1,
     key_s2: value_s2, ...
 },
 subdic2: {
     sub2sub1: {
         key_s2s1: value_s2s1,
     }
}

のような構造の辞書をクラスで定義して簡単に生成できないかなーと思ってやってみた。

まずは1階層のクラス。

class MyData:
    def __init__(self):
        self.prop1 = 0

data = MyData()
print(data)
<__main__.MyData instance at 0x...>

うん、これじゃない。これを回避するには組み込み関数vars()を使うといいとのこと。

data = vars(MyData())
print(data)
{'prop1': 0}

そうそう、こういうこと。次に2階層では、

class MyData:
    class MySubData:
        def __init__(self):
            self.subprop1 = 0
    def __init__(self):
        self.prop1 = 0
        self.sub1 = MyData.MySubData()

data = MyData()
print(data)
{'prop1': 0, 'sub1': <__main__.MySubData instance at 0x...>}

うん、これじゃない。これを回避するには、

        self.sub1 = vars(MyData.MySubData())
{'prop1': 0, 'sub1': {'subprop1': 0}}

そうそう、こういうこと。

・・・でもなんか違う。子の要素を直接設定することもできなくはないけど、なんとなくこれじゃないと誰かが叫んでいる。

教えてぐーぐる先生!ということで、

こちらの記事 (http://blog.beanz-net.jp/happy_programming/2008/11/python-5.html) が参考になった。(ありがとうございます。)

共通のメソッドは親で定義して、

class Oya:
  def __str__(self):
    return str(self.__dict__)
  def __repr__(self):
    return str(self.__dict__)
  def __iter__(self):
    return self.__dict__.iteritems()
  def __getitem__(self, key):
    return self.__dict__[key]
  def __setitem__(self, key, value):
    self.__dict__[key] = value

class MyData(Oya):
    class MySubData(Oya):
        def __init__(self):
            self.subprop1 = 0
    def __init__(self):
        self.prop1 = 0
        self.sub1 = MyData.MySubData()

data = MyData()
data.prop1 = 9
data['sub1']['subprop1'] = 99
print(data)
{'prop1': 9, 'sub1': {'subprop1': 99}}

たぶんこれでいい。

階層がどんなに深くなってもOK。プロパティには辞書的にもプロパティ的にもアクセスできる。辞書として使うときにはvars()なりで。

(追記)
と思ったんだけど、vars()で取り出した辞書でtype(data['sub1'])すると<type 'instance'>ってなっちゃうので、inner classまではうまく辞書化できていない模様。これは難しい。

暫定対処としてinner classは個別にvars()して置換してあげればなんとかならないことはない。

とりあえずinstanceとかいう意味不明なものに判定されないよう、クラスの定義時に

class Oya(object):

としておくと、typeしたときクラス名で表示されるようになるようだ。(python 2.x)
あとは再帰的にvars()するような関数を持たせる感じかなぁ。

こんな感じ。

def zenvars(obj):
    dic = {}
    if isinstance(obj, Oya): dic = vars(obj)
    else: return dic
    for i in dic:
        if isinstance(dic[i], Oya):
            dic[i] = zenvars(dic[i])
    return dic
1
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
6