【问题标题】:PyYaml dumping things backwardsPyYaml 向后倾倒东西
【发布时间】:2012-04-14 15:54:13
【问题描述】:

所以我有一个包含许多琐事问题和答案列表的 yaml 文件。但是,每当我尝试加载此文件并使用 pyyaml 转储 python 中的内容时,它会将它们向后转储。我不确定这是我的 yaml 文件还是我的库有问题。

假设我的一个问题/答案对在 yaml 文件中看起来像这样 -

{"question": "What is the name of this sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ...", 
 "answer": ["The Fibonacci Sequence", "The Padovan Sequence", "The Morris Sequence"]}

当我在那个 python 字典上使用 yaml.dump() 时,它会转储这个 -

answer: [fibonacci, padovan, morris]\nquestion: 'what sequence is this: 1, 1, 2, 3, 5, 8, 13, ...'\n"

我期待这个 -

- question: "What is the name of this sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ..."
  answer: ["The Fibonacci Sequence", "The Padovan Sequence", "The Morris Sequence"]

我在这里做错了吗?

【问题讨论】:

    标签: python yaml pyyaml


    【解决方案1】:

    我在这里有一些不同的答案。如果元素的顺序对您来说很重要,而不是出于可读性的原因,那么 dbaupp 的答案是正确的。如果您希望在回答之前显示问题的唯一原因是使文件更易于阅读,那么您不需要使用 !!omap,而是可以使用自定义表示器来获得您想要的顺序。

    首先,没有 - 前面的转储器转储的问题是因为您只转储一个映射,而不是它们的列表。将您的 dict 放入列表中,这将得到修复。所以我们开始:

    d = [{"question": "What is the name of this sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ...", 
     "answer": ["The Fibonacci Sequence", "The Padovan Sequence", "The Morris Sequence"]}]
    

    现在我们有一个我们希望输出的特定顺序,所以我们将指定它,并使用该顺序转换为 OrderedDict:

    from collections import OrderedDict
    order = ['question', 'answer']
    do = [ OrderedDict( sorted( z.items(), key=lambda x: order.index(x[0]) ) ) for z in d ]
    

    接下来,我们需要让 PyYAML 知道如何处理 OrderedDict。在这种情况下,我们不希望它是一个 !!omap,我们只想要一个具有特定顺序的映射。对于我不清楚的一些动机,如果你给 dumper.represent_mapping 一个字典,或者任何带有 items 属性的东西,它会在转储之前对项目进行排序,但是如果你给它 items() 的输出(例如,(key , value) 元组),它不会。因此我们可以使用

    def order_rep(dumper, data):
        return dumper.represent_mapping( u'tag:yaml.org,2002:map', data.items(), flow_style=False )
    yaml.add_representer( OrderedDict, order_rep )
    

    然后,print yaml.dump(do) 的输出结果为:

    - question: 'What is the name of this sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ...'
      answer: [The Fibonacci Sequence, The Padovan Sequence, The Morris Sequence]
    

    有许多不同的方法可以做到这一点。实际上根本不需要使用 OrderedDict,您只需要问题/答案对属于您可以为其编写表示器的某个类。

    再一次,请意识到这只是为了人类的可读性和审美目的。这里的顺序不会有任何 YAML 意义,就像你使用 !!omap 一样。看起来这对您来说主要是为了提高可读性。

    【讨论】:

      【解决方案2】:

      如果在转储中首选顺序,则可以使用以下代码

      import yaml
      
      class MyDict(dict):
         def to_omap(self):
            return [('question', self['question']), ('answer', self['answer'])]
      
      def represent_omap(dumper, data):
         return dumper.represent_mapping(u'tag:yaml.org,2002:map', data.to_omap())
      
      yaml.add_representer(MyDict, represent_omap)
      
      questions = [
         MyDict({'answer': 'My name is Bob.', 'question': 'What is your name?'}),
         MyDict({'question': 'How are you?', 'answer': 'I am fine.'}),
      ]
      print yaml.dump(questions, default_flow_style=False)
      

      输出是:

      - question: What is your name?
        answer: My name is Bob.
      - question: How are you?
        answer: I am fine.
      

      【讨论】:

      • +1 这很整洁,效果很好。我喜欢在MyDict 上使用representer 作为@staticmethod,以保持联系。所以你改用yaml.add_representer(MyDict, MyDict.representer)
      • 但这在使用yaml.safe_dump 倾倒时不起作用。知道如何使用safe_dump 如上所述的自定义代表吗?我得到一个例外:yaml.representer.RepresenterError: cannot represent an object: {'answer': 'My name is Bob.', 'question': 'What is your name?'}
      • 回答我自己之前的评论:使用yaml.SafeDumper.add_representer(...) 而不是yaml.add_representer(...)
      • 这是一个巧妙的技巧;这是我使用 OrderedDict 的版本,它只是另外一行:yaml.add_representer(OrderedDict, lambda dumper, data: dumper.represent_mapping(u'tag:yaml.org,2002:map', data.items()))
      【解决方案3】:

      YAML 关联数组(和 python 字典)不保留其元素的顺序。

      但是,如果 order 是导入的,则 YAML 定义一个 ordered map !!omap,PyYAML 默认将其解析为一个元组列表,例如:

      >>> yaml.load('''!!omap
      ... - a: foo
      ... - b: bar''')
      [('a','foo'),('b','bar')]
      

      This answer 提供了一些有关如何将!!omap 加载到Python OrderedDict 中的详细信息。

      【讨论】:

      • 谢谢,所以我做错了,我只是不知道是什么。
      【解决方案4】:

      如果将它们作为字典加载,它们的顺序是任意的。字典不是有序的容器。

      【讨论】:

      • 我知道,重要的是我如何倾倒它们。我显示的转储字符串都没有表示为字符串或格式正确的答案(第一个前面有 -)
      • @Matt,PyYAML 基本上是 YAML 加载器/转储器的参考实现,因此(特别是因为这种情况是一种常见的操作)它的输出将符合标准。
      猜你喜欢
      • 1970-01-01
      • 2010-12-29
      • 1970-01-01
      • 2013-02-09
      • 2019-08-02
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      • 1970-01-01
      相关资源
      最近更新 更多