Python 階層化されたDictから指定の階層を探し、なければ作成する

# 問題点
JSONのような階層構造の辞書型でデータを扱うケースはよくあると思います。
階層が深くなり指定のデータにたどり着くために、以下のコードのように階層によって爆増するコードを書いてませんか？

```Python

if 'key1' in target_dict:
   target_dict_key1 = target_dict['key1']
   if 'key2' in target_dict_key1 :
        target_dict_key2 = target_dict_key1['key2']
        ...
   else:
        target_dict_key1.setdefault('key2',dict())
        ....

```

# やりたいこと
- 階層化された辞書型から指定の階層の辞書型を取得したい。
- また、もし階層途中がなければ、指定階層まで辞書を作成し、最終層の辞書型を取得したい。

データは以下のようになっていたとします。

```Python
data_dict = {
    'tokyo':{
        'shinjuku':{
            'zaiko':{
                'A':3,
                'B':4,
                'C':5,
            },
        },
        'shibuya':{
            'zaiko':{
                'A':5,
                'B':8,
            },
        },
    }
}

```
tokyoのsinjukuの在庫データを取得したい。
データ階層のキーワードがあるかどうかの確認もしつつ探し出さなければなりません。

さらに、新しく'D'という在庫を追加したい。とか、'yoyaku'という新しい管理データを挿入したいというとき、冒頭のようなコードを記述していると大変なことになります。


# 解決
以下のような、二つの関数をネストさせれば、コードの膨張を防ぐことができます。


```Python
def _serach_dict_(target_dict,dict_layer):
    result_dict = None
    if isinstance(dict_layer,list):
        if dict_layer:
            key = dict_layer[0]
            if key in target_dict:
                if not isinstance(target_dict[key],dict):
                    target_dict[key] = dict()
                target_dict = target_dict[key]
                dict_layer = dict_layer[1:]
                if dict_layer:
                    result_dict = _serach_dict_(target_dict,dict_layer)
                else:
                    return target_dict
            else:
                result_dict = _create_dict_(target_dict,dict_layer)

    return result_dict
```

```Python
def _create_dict_(target_dict,dict_layer):
    result_dict = None
    if isinstance(dict_layer,list) and isinstance(target_dict,dict):
        if dict_layer:
            key = dict_layer[0]
            target_dict.setdefault(key, dict())
            result_dict = target_dict[key]
            dict_layer = dict_layer[1:]
            if dict_layer:
                result_dict = _create_dict_(result_dict,dict_layer)
            else:
                return result_dict
    return result_dict
```

_serach_dict_関数内で、_create_dict_を使用します。
_serach_dict_関数の引数
target_dict：辞書型データ
dict_layer：探し出す階層構造リスト
dict_layeの例は以下の通り。

```Python
dict_layer = ['tokyo','shinjuku','zaiko']
```

# 使用方法

tokyoのsinjukuの在庫データを取得

```Python
dict_layer = ['tokyo','shinjuku','zaiko']

import json

result_dict = _serach_dict_(data_dict,dict_layer)

print(json.dumps(data_dict,indent=2))

result_dict.setdefault('D', 30)

print(json.dumps(data_dict,indent=2))

```
結果

```Python
{
  "tokyo": {     
    "shinjuku": {
      "zaiko": { 
        "A": 3,  
        "B": 4,  
        "C": 5   
      }
    },
    "shibuya": { 
      "zaiko": {
        "A": 5,
        "B": 8
      }
    }
  }
}
{
  "tokyo": {
    "shinjuku": {
      "zaiko": {
        "A": 3,
        "B": 4,
        "C": 5,
        "D": 30
      }
    },
    "shibuya": {
      "zaiko": {
        "A": 5,
        "B": 8
      }
    }
  }
}

```

shinjukuにyoyakuデータを作り、Aを15個登録します。

```Python

dict_layer = ['tokyo','shinjuku','yoyaku']

import json

result_dict = _serach_dict_(data_dict,dict_layer)

print(json.dumps(data_dict,indent=2))

result_dict.setdefault('A', 15)

print(json.dumps(data_dict,indent=2))


```
結果

```Python
{
  "tokyo": {      
    "shinjuku": { 
      "zaiko": {  
        "A": 3,   
        "B": 4,   
        "C": 5    
      },
      "yoyaku": {}
    },
    "shibuya": {
      "zaiko": {
        "A": 5,
        "B": 8
      }
    }
  }
}
{
  "tokyo": {
    "shinjuku": {
      "zaiko": {
        "A": 3,
        "B": 4,
        "C": 5
      },
      "yoyaku": {
        "A": 15
      }
    },
    "shibuya": {
      "zaiko": {
        "A": 5,
        "B": 8
      }
    }
  }
}
```

# 注意点
このコードではdict_layer で指定したキーワードをdict型に置き換えてしまいます。
list型の混在やそのほかデータ型を保護するためには、_serach_dict_関数に多少手を入れる必要があります。