【问题标题】:How can I parse a YAML file in Python如何在 Python 中解析 YAML 文件
【发布时间】:2010-12-18 22:20:13
【问题描述】:

如何在 Python 中解析 YAML 文件?

【问题讨论】:

    标签: python yaml


    【解决方案1】:

    不依赖C头文件最简单最纯粹的方法是PyYaml (documentation),可以通过pip install pyyaml安装:

    #!/usr/bin/env python
    
    import yaml
    
    with open("example.yaml", "r") as stream:
        try:
            print(yaml.safe_load(stream))
        except yaml.YAMLError as exc:
            print(exc)
    

    就是这样。还存在一个普通的 yaml.load() 函数,但应该始终首选 yaml.safe_load(),除非您明确需要提供任意对象序列化/反序列化以避免引入任意代码执行的可能性。

    请注意,PyYaml 项目支持 YAML 1.1 specification 以上的版本。如果需要YAML 1.2 specification 支持,请参阅ruamel.yaml,如this answer 中所述。

    此外,您还可以使用 pyyaml 的替代品,以保持您的 yaml 文件的顺序与您拥有它的方式相同,称为oyaml。查看synk of oyaml here

    【讨论】:

    • 我要补充一点,除非您希望序列化/反序列化任意对象,否则最好使用yaml.safe_load,因为它无法执行 YAML 文件中的任意代码。
    • Yaml yaml = new Yaml();对象 obj = yaml.load("a: 1\nb: 2\nc:\n - aaa\n - bbb");
    • 您可能需要先安装 PyYAML 包pip install pyyaml,更多选项请参阅此帖子stackoverflow.com/questions/14261614/…
    • 在这个例子中捕获异常有什么意义?无论如何它都会打印出来,它只会让示例更加复杂......
    【解决方案2】:

    使用 Python 2+3(和 unicode)读写 YAML 文件

    # -*- coding: utf-8 -*-
    import yaml
    import io
    
    # Define data
    data = {
        'a list': [
            1, 
            42, 
            3.141, 
            1337, 
            'help', 
            u'€'
        ],
        'a string': 'bla',
        'another dict': {
            'foo': 'bar',
            'key': 'value',
            'the answer': 42
        }
    }
    
    # Write YAML file
    with io.open('data.yaml', 'w', encoding='utf8') as outfile:
        yaml.dump(data, outfile, default_flow_style=False, allow_unicode=True)
    
    # Read YAML file
    with open("data.yaml", 'r') as stream:
        data_loaded = yaml.safe_load(stream)
    
    print(data == data_loaded)
    

    创建 YAML 文件

    a list:
    - 1
    - 42
    - 3.141
    - 1337
    - help
    - €
    a string: bla
    another dict:
      foo: bar
      key: value
      the answer: 42
    

    常见的文件结尾

    .yml.yaml

    替代方案

    对于您的应用程序,以下内容可能很重要:

    • 其他编程语言的支持
    • 读/写性能
    • 紧凑性(文件大小)

    另请参阅:Comparison of data serialization formats

    如果您正在寻找一种制作配置文件的方法,您可能想阅读我的短文Configuration files in Python

    【讨论】:

    • 文件有什么编码?你确定它是 utf-8 编码的吗?
    • 感谢您的建议。我的文件有 utf-8 编码。我必须将您的代码行更改为 io.open(doc_name, 'r', encoding='utf8') 才能读取特殊字符。 YAML 版本 0.1.7
    • 嗯,有趣。明天我会尝试重现,如果可以的话,我会调整这个问题。谢谢!
    • 可以使用内置的open(doc_name, ..., encodung='utf8')进行读写,无需导入io
    • 你使用import yaml,但这不是一个内置模块,你没有指定它是哪个包。在新的 Python3 安装上运行 import yaml 会导致 ModuleNotFoundError: No module named 'yaml'
    【解决方案3】:

    如果您的 YAML 符合 YAML 1.2 specification(2009 年发布),那么您应该使用 ruamel.yaml(免责声明:我是该软件包的作者)。 它本质上是 PyYAML 的超集,支持大部分 YAML 1.1(从 2005 年开始)。

    如果您希望在往返时能够保留您的 cmets,您当然应该使用 ruamel.yaml。

    升级@Jon 的例子很简单:

    import ruamel.yaml as yaml
    
    with open("example.yaml") as stream:
        try:
            print(yaml.safe_load(stream))
        except yaml.YAMLError as exc:
            print(exc)
    

    使用safe_load(),除非你真的完全控制输入,需要它(很少发生)并且知道你在做什么。

    如果您使用 pathlib Path 来操作文件,则最好使用 ruamel.yaml 提供的新 API:

    from ruamel.yaml import YAML
    from pathlib import Path
    
    path = Path('example.yaml')
    yaml = YAML(typ='safe')
    data = yaml.load(path)
    

    【讨论】:

    • 你好@Anthon。我使用的是 ruamel,但遇到了不符合 ascii 的文档的问题 (UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128))。我尝试将 yaml.encoding 设置为 utf-8,但由于 YAML 中的加载方法仍然使用 ascii_decode,因此无法正常工作。这是一个错误吗?
    【解决方案4】:

    首先使用 pip3 安装 pyyaml。

    然后导入 yaml 模块并将文件加载到名为 'my_dict' 的字典中:

    import yaml
    with open('filename.yaml') as f:
        my_dict = yaml.safe_load(f)
    

    这就是你所需要的。现在整个 yaml 文件都在 'my_dict' 字典中。

    【讨论】:

    • 如果您的文件包含“-hello world”行,则调用变量 my_dict 是不合适的,因为它将包含一个列表。如果该文件包含特定标签(以!!python 开头),则使用yaml.load() 也可能是不安全的(如完全擦除硬盘)。由于这已明确记录,您应该在此处重复该警告(几乎在所有情况下都可以使用 yaml.safe_load())。
    • 您使用import yaml,但这不是内置模块,您也没有指定它是哪个包。在新的 Python3 安装上运行 import yaml 会导致 ModuleNotFoundError: No module named 'yaml'
    • Munch, stackoverflow.com/questions/52570869/… import yaml; from munch import munchify; f = munchify(yaml.load(…)); print(fo.d.try)
    【解决方案5】:

    示例:


    defaults.yaml

    url: https://www.google.com
    

    environment.py

    from ruamel import yaml
    
    data = yaml.safe_load(open('defaults.yaml'))
    data['url']
    

    【讨论】:

    【解决方案6】:

    要访问 YAML 文件中列表的任何元素,如下所示:

    global:
      registry:
        url: dtr-:5000/
        repoPath:
      dbConnectionString: jdbc:oracle:thin:@x.x.x.x:1521:abcd
    

    您可以使用以下 python 脚本:

    import yaml
    
    with open("/some/path/to/yaml.file", 'r') as f:
        valuesYaml = yaml.load(f, Loader=yaml.FullLoader)
    
    print(valuesYaml['global']['dbConnectionString'])
    

    【讨论】:

      【解决方案7】:

      我使用ruamel.yaml详情和辩论here

      from ruamel import yaml
      
      with open(filename, 'r') as fp:
          read_data = yaml.load(fp)
      

      ruamel.yaml 的使用与 PyYAML 的旧用法兼容(有一些简单的可解决问题),正如我提供的链接中所述,使用

      from ruamel import yaml
      

      而不是

      import yaml
      

      它会解决你的大部分问题。

      编辑:事实证明,PyYAML 并没有死,它只是在不同的地方维护。

      【讨论】:

      • @Oleksander:PyYaml 在过去 7 个月内有提交,最近关闭的问题是 12 天前。你能定义“长死”吗?
      • @abalter 抱歉,我似乎是从他们的官方网站或这里的帖子stackoverflow.com/a/36760452/5510526获得信息的@
      • @OleksandrZelentsov 我可以看到混乱。它死了有一段很长的时期。 github.com/yaml/pyyaml/graphs/contributors。但是,他们的网站已启动并显示发布在 SO 帖子之后发布的版本,该帖子指的是 PyYaml 的消亡。所以公平地说,在这一点上它仍然活着,尽管它相对于 ruamel 的方向显然是不确定的。此外,最近的帖子在这里进行了长时间的讨论。我添加了一条评论,现在我的评论是唯一的。我想我不明白关闭的问题是如何工作的。 github.com/yaml/pyyaml/issues/145
      • @abalter FWIW,当发布该答案时,过去总共有 9 次提交......不到 7 年。其中之一是对错误语法的自动“修复”。其中两个涉及发布几乎没有变化的新版本。其余的都是相对微小的调整,大部分是在答案之前 5 年做出的。除自动修复外,其他所有操作均由一个人完成。我不会因为将 PyYAML 称为“早已死去”而严厉地判断这个答案。
      【解决方案8】:
      #!/usr/bin/env python
      
      import sys
      import yaml
      
      def main(argv):
      
          with open(argv[0]) as stream:
              try:
                  #print(yaml.load(stream))
                  return 0
              except yaml.YAMLError as exc:
                  print(exc)
                  return 1
      
      if __name__ == "__main__":
          sys.exit(main(sys.argv[1:]))
      

      【讨论】:

      • 这段代码实际上并没有做任何事情。您的意思是注释掉代码吗?
      • 我认为它的预期输入。即 python main.py example.yaml。也许 print(yaml.safe_load(stream)) 用于打印?
      【解决方案9】:

      read_yaml_file 函数将所有数据返回到字典中。

      def read_yaml_file(full_path=None, relative_path=None):
         if relative_path is not None:
              resource_file_location_local = ProjectPaths.get_project_root_path() + relative_path
      else:
          resource_file_location_local = full_path
      
      with open(resource_file_location_local, 'r') as stream:
          try:
              file_artifacts = yaml.safe_load(stream)
          except yaml.YAMLError as exc:
              print(exc)
      return dict(file_artifacts.items())
      

      【讨论】:

        【解决方案10】:

        建议:使用 yq(可通过 pip 获得)

        我不确定以前是如何不建议这样做的,但我强烈建议使用 yq,它是 YAML 的 jq 包装器。

        yq 使用 jq like syntax,但可以处理 yaml 文件以及 json。


        示例:

        1) 读取一个值:

        yq e '.a.b[0].c' file.yaml
        

        2 ) 来自标准输入的管道:

        cat file.yaml | yq e '.a.b[0].c' -
        

        3 ) 就地更新 yaml 文件

        yq e -i '.a.b[0].c = "cool"' file.yaml
        

        4 ) 使用环境变量更新:

        NAME=mike yq e -i '.a.b[0].c = strenv(NAME)' file.yaml
        

        5 ) 合并多个文件:

        yq ea '. as $item ireduce ({}; . * $item )' path/to/*.yml
        

        6 ) 对一个 yaml 文件的多次更新:

        yq e -i '
          .a.b[0].c = "cool" |
          .x.y.z = "foobar" |
          .person.name = strenv(NAME)
        ' file.yaml
        

        (*) 详细了解如何使用基于 jq filters 的 yaml 解析字段。


        其他参考:

        https://github.com/mikefarah/yq/#install

        https://github.com/kislyuk/yq

        【讨论】:

          猜你喜欢
          • 2018-02-16
          • 2021-01-28
          • 1970-01-01
          • 2011-04-22
          • 2017-06-03
          • 2021-11-04
          • 2022-12-22
          • 1970-01-01
          相关资源
          最近更新 更多