Help us understand the problem. What is going on with this article?

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

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

{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
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away