寻求支持嵌套AttrDict直接赋值的attrdict库替代方案
问题描述
项目中有大量配置参数需要集中存储,希望通过属性(点)符号访问配置对象,因此编写了对接YAML的配置模块,使用了AttrDict库,但该库不支持直接嵌套赋值。
原代码如下:
import yaml from attrdict import AttrDict def get_cfg(): return cfg_node def dump(out_filepath): with open(out_filepath, 'w') as file: yaml.dump(attrdict_to_dict(cfg_node), file) def load_yaml(filepath): global cfg_node with open(filepath, 'r') as file: cfg_node = dict_to_attrdict(yaml.safe_load(file)) def attrdict_to_dict(myAttrdict): dictionary = dict(myAttrdict) for k in myAttrdict: value = dictionary[k] if isinstance(value, AttrDict): dictionary[k] = attrdict_to_dict(value) return dictionary def dict_to_attrdict(dictionary): myAttrdict = AttrDict() for k in dictionary: value = dictionary[k] if isinstance(value, dict): myAttrdict.__setattr__(k, attrdict_to_dict(value)) return myAttrdict cfg_node = AttrDict() cfg_node.b = "value_b" cfg_node.a = AttrDict() cfg_node.a.b = AttrDict() cfg_node.a.c = "nested_c" cfg_node.a.b.e= "double_nested_e"
执行后输出:
print(cfg_node) >>> {'b': 'value_b', 'a': AttrDict({})}
只有显式创建嵌套对象才能生效,但这种方式不符合使用需求:
cfg_node = AttrDict() cfg_node.b = "value_b" a = AttrDict() a.c = "nested_value_c" cfg_node.a = a print(cfg_node) >>> {'b': 'value_b', 'a': AttrDict({'c':'nested_value_c'})}
现寻求支持直接嵌套AttrDict赋值的替代方案。
替代方案推荐
1. 使用 munch 库
munch 是专门支持属性访问字典的库,原生支持嵌套赋值,无需提前创建嵌套对象。
安装
pip install munch
适配代码示例
import yaml from munch import Munch, munchify, unmunchify def get_cfg(): return cfg_node def dump(out_filepath): with open(out_filepath, 'w') as file: yaml.dump(unmunchify(cfg_node), file) def load_yaml(filepath): global cfg_node with open(filepath, 'r') as file: cfg_node = munchify(yaml.safe_load(file)) # 直接嵌套赋值测试 cfg_node = Munch() cfg_node.b = "value_b" cfg_node.a.b = Munch() cfg_node.a.c = "nested_c" cfg_node.a.b.e = "double_nested_e" print(cfg_node) # 输出:Munch({'b': 'value_b', 'a': Munch({'b': Munch({'e': 'double_nested_e'}), 'c': 'nested_c'})})
2. 使用 addict 库
addict 同样支持自动嵌套的属性访问,语法更简洁,赋值时会自动创建嵌套对象。
安装
pip install addict
适配代码示例
import yaml from addict import Dict def get_cfg(): return cfg_node def dump(out_filepath): with open(out_filepath, 'w') as file: yaml.dump(dict(cfg_node), file) def load_yaml(filepath): global cfg_node with open(filepath, 'r') as file: cfg_node = Dict(yaml.safe_load(file)) # 直接嵌套赋值测试 cfg_node = Dict() cfg_node.b = "value_b" cfg_node.a.b.e = "double_nested_e" # 无需提前创建a和b,自动生成嵌套Dict cfg_node.a.c = "nested_c" print(cfg_node) # 输出:{'b': 'value_b', 'a': {'b': {'e': 'double_nested_e'}, 'c': 'nested_c'}}
3. 自定义实现嵌套AttrDict
如果不想引入第三方库,可以自己实现一个支持自动嵌套的类:
import yaml class NestedAttrDict(dict): def __getattr__(self, key): if key not in self: self[key] = NestedAttrDict() return self[key] def __setattr__(self, key, value): self[key] = value def __delattr__(self, key): del self[key] def get_cfg(): return cfg_node def dump(out_filepath): def attrdict_to_dict(obj): if isinstance(obj, NestedAttrDict): return {k: attrdict_to_dict(v) for k, v in obj.items()} return obj with open(out_filepath, 'w') as file: yaml.dump(attrdict_to_dict(cfg_node), file) def load_yaml(filepath): global cfg_node def dict_to_attrdict(d): if isinstance(d, dict): attr_dict = NestedAttrDict() for k, v in d.items(): attr_dict[k] = dict_to_attrdict(v) return attr_dict return d with open(filepath, 'r') as file: cfg_node = dict_to_attrdict(yaml.safe_load(file)) # 直接嵌套赋值测试 cfg_node = NestedAttrDict() cfg_node.b = "value_b" cfg_node.a.b.e = "double_nested_e" cfg_node.a.c = "nested_c" print(cfg_node) # 输出:{'b': 'value_b', 'a': {'b': {'e': 'double_nested_e'}, 'c': 'nested_c'}}
内容的提问来源于stack exchange,提问作者Wippo
相关产品推荐
相关产品推荐

