使用字典而不是配置文件中的列表的坏习惯?

时间:2019-01-29 17:06:38

标签: python list dictionary configuration yaml

考虑以下yaml配置文件:

items:
    item_A:
      field_A: some_value
      field_B: some_other_value
    item_B:
      field_A: some_value
      field_B: some_other_value

表示此问题的逻辑方法是在每个项目前面添加破折号,使其成为项目列表:

items:
    - item_A:
        field_A: some_value
        field_B: some_other_value
    - item_B:
        field_A: some_value
        field_B: some_other_value

我想轻松访问对象的名称(item_A等)。

遍历以前的配置时,

for item in items:
    print(item) # here, 'item' will be the keys in the items dict (eg. 'item_A')

相对于后者

for item in items:
    print(item) # here, 'item' will be a full dict (eg. "item_A":{"field_A":"some_value"..)
    # if I want access to the name item_A, I need to do item.keys()[0]- not so friendly

我知道第二种表示形式在逻辑上是正确的,但是我发现使用第一种表示形式更方便,以便能够迭代并直接获得键/对象名称。

所以,我的问题是:

是否像在所提供的示例中那样将列表表示为字典被认为是一种坏习惯,以便轻松访问商品的名称/关键字?

这样做有什么弊端或问题吗?

1 个答案:

答案 0 :(得分:1)

什么是坏习惯,还有什么逻辑是值得商bat的。我认为 您假设由于根级别映射中的密钥items是 复数,该值包含多个项目,应为 顺序。我认为这不一定是正确的。

但是,如果键值在映射中的顺序为value 为items(即具有键item_Aitem_B的键) 比您必须使用列表更重要,您可能想要做:

items:
- name: item_A
  field_A: some_value
  field_B: some_other_value
- name: item_B
  field_A: some_value
  field_B: some_other_value

将其加载到变量data中时,就不再像以前那样容易访问item_B 与您的解决方案。加载后可以执行的操作是:

data['items'] = Items(data['items'])
具有类Items

适当地提供对基础的访问 通过提供__getitem____iter__的数据结构,以便您可以做到

items = data['items']
for item_name in items:
   item = items[item_name]

通过使用标签,您可以在加载后无需后处理步骤的情况下完成操作

items: !Items
- name: item_A
  field_A: some_value_1
  field_B: some_other_value_1
- name: item_B
  field_A: some_value_2
  field_B: some_other_value_2

并注册您的课程Items。但是,这似乎不像 没有标签的版本,尽管在这种情况下,IMO比隐含的要好得多。

假设以上为input.yaml

import sys
from pathlib import Path
import ruamel.yaml

input = Path('input.yaml')

yaml = ruamel.yaml.YAML()

@yaml.register_class
class Items:
    def __init__(self, items):
        self.item_list = items

    @classmethod
    def from_yaml(cls, constructor, node):
        return cls(constructor.construct_sequence(node, deep=True))

    def __getitem__(self, key):
        if isinstance(key, int):
            return self.item_list[key]
        for item in self.item_list:
            if item['name'] == key:
                return item

    def __iter__(self):
        for item in self.item_list:
             yield item['name']

data = yaml.load(input)
items = data['items']
print('item1', items[1]['field_A'])
print('item2', items['item_A']['field_A'])
for item_name in items:
    item = items[item_name]
    print('item3', item['field_B'])

给出:

item1 some_value_2
item2 some_value_1
item3 some_other_value_1
item3 some_other_value_2

如果items是YAML文档根级的唯一密钥, 那么当然完全不需要该键,那么您 应该将标签放在文档的开头,并在其中添加一个 序列作为根节点。