【问题标题】:Retrieve bulk data from YAML using Python使用 Python 从 YAML 中检索批量数据
【发布时间】:2018-10-16 06:28:00
【问题描述】:

我有一个如下形式的 yaml 文件:

Solution: 
- number of solutions: 1
  number of solutions displayed: 1
- Gap: None
  Status: optimal
  Message: bonmin\x3a Optimal
  Objective:
    objective:
      Value: 0.010981105395
  Variable:
    battery_E[b1,1,1]:
      Value: 0.25
    battery_E[b1,1,2]:
      Value: 0.259912707017
    battery_E[b1,2,1]:
      Value: 0.120758408109
    battery_E[b2,1,1]:
      Value: 0.0899999972181
    battery_E[b2,2,3]:
      Value: 0.198967393893
    windfarm_L[w1,2,3]:
      Value: 1
    windfarm_L[w1,3,1]:
      Value: 1
    windfarm_L[w1,3,2]:
      Value: 1

使用 Python27,我想从这个 YAML 文件中导入所有的 battery_E 值。我知道我可以遍历 battery_E 字典的键以逐一检索它们(我已经在使用 PyYAML 进行此操作),但我想避免迭代并一次性完成!

【问题讨论】:

    标签: python yaml pyyaml


    【解决方案1】:

    不可能“一口气” - 无论哪种方式,都会有某种迭代,这完全没问题。

    但是,如果内存是一个问题,您可以在 YAML 加载期间加载感兴趣的键的值:

    from __future__ import print_function
    
    import yaml
    
    KEY = 'battery_E'
    
    
    class Loader(yaml.SafeLoader):
        def __init__(self, stream):
            super(Loader, self).__init__(stream)
            self.values = []
    
        def compose_mapping_node(self, anchor):
            start_event = self.get_event()
            tag = start_event.tag
            if tag is None or tag == '!':
                tag = self.resolve(yaml.MappingNode, None, start_event.implicit)
            node = yaml.MappingNode(tag, [],
                                    start_event.start_mark, None,
                                    flow_style=start_event.flow_style)
            if anchor is not None:
                self.anchors[anchor] = node
            while not self.check_event(yaml.MappingEndEvent):
                item_key = self.compose_node(node, None)
                item_value = self.compose_node(node, item_key)
                if (isinstance(item_key, yaml.ScalarNode)
                        and item_key.value.startswith(KEY)
                        and item_key.value[len(KEY)] == '['):
                    self.values.append(self.construct_object(item_value, deep=True))
                else:
                    node.value.append((item_key, item_value))
            end_event = self.get_event()
            node.end_mark = end_event.end_mark
            return node
    
    
    with open('test.yaml') as f:
        loader = Loader(f)
        try:
            loader.get_single_data()
        finally:
            loader.dispose()
    
        print(loader.values)
    

    但请注意,此代码不假定 YAML 文件内树中 battery_E 键的位置 - 它只会加载它们的所有值。

    【讨论】:

    • 做得很好,但你应该指出这和使用yaml.load() 一样不安全。但是,我认为没有理由不继承 yaml.SafeLoader 而不是 yaml.Loader 来规避这个问题。
    • 感谢您分享您的时间和专业知识。您的解决方案似乎很有趣。
    【解决方案2】:

    无需使用PyYAML检索每个条目,您可以加载一次数据,然后使用Pythons选择以下两行的键值对:

    data = yaml.safe_load(open('input.yaml'))
    kv = {k:v['Value']  for k, v in data['Solution'][1]['Variable'].items() if k.startswith('battery_E')}
    

    之后kv 包含:

    {'battery_E[b2,2,3]': 0.198967393893, 'battery_E[b1,1,1]': 0.25, 'battery_E[b1,1,2]': 0.259912707017, 'battery_E[b2,1,1]': 0.0899999972181, 'battery_E[b1,2,1]': 0.120758408109}
    

    【讨论】:

    • 感谢您抽出时间Anthon。是的,你是对的,如果一次加载所有数据,那么为什么不只是迭代。但是,我一直在寻找类似于从 SQL DB 检索数据的方式,但我想这是不可能的。
    • @Mosy 不,这在 PyYAML 中是不可能的。我希望您意识到,对于 SQL 数据库,数据库软件会迭代所有表条目以匹配您指定的条件(当然,除非这些条目以某种方式专门索引)。
    猜你喜欢
    • 1970-01-01
    • 2011-11-05
    • 2016-06-28
    • 2016-11-27
    • 2023-03-19
    • 1970-01-01
    • 2018-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多