如何在Python中解析YAML文件


Answers:


803

不依赖C标头的最简单,最纯净的方法是PyYaml(文档),可以通过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规范之前的版本。如果需要YAML 1.2规范支持,请参见ruamel.yaml,本答案中所述


96
我要补充一点,除非您希望序列化/反序列化任意对象,否则最好使用yaml.safe_load它,因为它无法执行YAML文件中的任意代码。
ternaryOperator 2014年

4
Yaml yaml =新Yaml(); 对象obj = yaml.load(“ a:1 \ nb:2 \ nc:\ n-aaa \ n-bbb”);
MayTheSchwartzBeWithYou 2014年


4
您可能需要先安装PyYAML包pip install pyyaml,看到这个帖子了更多的选择stackoverflow.com/questions/14261614/...
罗曼

7
在此示例中捕获异常有什么意义?这是怎么回事反正打印,它只是使更多令人费解的例子..
naught101

115

使用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

备择方案

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

  • 其他编程语言的支持
  • 阅读/写作表现
  • 紧凑度(文件大小)

另请参阅:数据序列化格式的比较

如果您想寻找一种制作配置文件的方法,则可能需要阅读我的短文《Python中的配置文件》。


在Windows上的输出是€。有人知道原因吗?
Cloud Cho

文件有什么编码?您确定它是utf-8编码的吗?
马丁·托马

1
感谢您的建议。我的文件具有utf-8编码。我不得不更改您的代码行io.open(doc_name, 'r', encoding='utf8')以读取特殊字符。YAML版本0.1.7
Cloud Cho

嗯,很有趣。我将在明天尝试重现该问题,如果可以的话,将调整该问题。谢谢!
马丁·托马

1
您可以使用内置的open(doc_name, ..., encodung='utf8')读写功能,而无需导入io
dexteritas

61

如果您具有符合YAML 1.2规范(2009年发布)的YAML,则应使用ruamel.yaml(免责声明:我是该软件包的作者)。它本质上是PyYAML的超集,它支持大多数YAML 1.1(自2005年起)。

如果希望在往返时保留您的注释,则当然应该使用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而无法正常工作。这是错误吗?
SnwBr

27

首先使用pip3安装pyyaml。

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

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

这就是您所需要的。现在,整个yaml文件都在“ my_dict”字典中。


6
这会关闭文件句柄吗?
yangmillstheory

2
如果您的文件包含“-hello world”行,则不宜调用变量my_dict,因为它将包含一个列表。如果该文件包含特定的标签(以开头!!python),则使用它也可能是不安全的(例如在完整的硬盘擦除后)yaml.load()。正如明确记录的那样,您应该在此处重复该警告(几乎yaml.safe_load()可以使用所有情况)。
Anthon '18年

4
您使用import yaml,但这不是内置模块,也没有指定它是哪个软件包。import yaml在全新的Python3安装上运行,结果是ModuleNotFoundError: No module named 'yaml'
cowlinator

11

例:


defaults.yaml

url: https://www.google.com

环境

from ruamel import yaml

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

保存不关闭流是否保存?
qrtLs

3

我使用ruamel.yaml详情和辩论在这里

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

@ abalter我道歉,似乎我从他们的官方网站或这里的帖子中获得了信息stackoverflow.com/a/36760452/5510526
Oleksandr Zelentsov

@OleksandrZelentsov我可以看到混乱。曾经有一段很长的死亡时期。github.com/yaml/pyyaml/graphs/contributors。但是,他们的网站仍在运行中,并显示了SO帖子发布后发布的有关PyYaml灭亡的版本。因此,可以公平地说,它仍然存在,尽管相对于ruamel的方向显然是不确定的。另外,最近的帖子在这里进行了长时间的讨论。我添加了一条评论,现在我的是唯一的一条。我想我不了解封闭问题的工作方式。github.com/yaml/pyyaml/issues/145
abalter

@abalter FWIW,发布该答案时,过去总共进行了9次提交,不到7年。其中之一是错误语法的自动“修复”。其中两个涉及发布几乎未更改的新版本。其余的都是相对较小的调整,大部分是在答案发布前五年完成的。除了自动修复以外,其他所有操作均由一个人完成。对于将PyYAML称为“长期死亡”,我不会做出苛刻的回答。
基金莫妮卡的诉讼案

-1
#!/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:]))

1
该代码实际上不执行任何操作。您是要注释掉代码吗?
Cowlinator '19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.