【发布时间】:2010-12-18 22:20:13
【问题描述】:
如何在 Python 中解析 YAML 文件?
【问题讨论】:
如何在 Python 中解析 YAML 文件?
【问题讨论】:
不依赖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 文件中的任意代码。
pip install pyyaml,更多选项请参阅此帖子stackoverflow.com/questions/14261614/…
# -*- 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)
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
【讨论】:
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'
如果您的 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)
【讨论】:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128))。我尝试将 yaml.encoding 设置为 utf-8,但由于 YAML 中的加载方法仍然使用 ascii_decode,因此无法正常工作。这是一个错误吗?
首先使用 pip3 安装 pyyaml。
然后导入 yaml 模块并将文件加载到名为 'my_dict' 的字典中:
import yaml
with open('filename.yaml') as f:
my_dict = yaml.safe_load(f)
这就是你所需要的。现在整个 yaml 文件都在 'my_dict' 字典中。
【讨论】:
!!python 开头),则使用yaml.load() 也可能是不安全的(如完全擦除硬盘)。由于这已明确记录,您应该在此处重复该警告(几乎在所有情况下都可以使用 yaml.safe_load())。
import yaml,但这不是内置模块,您也没有指定它是哪个包。在新的 Python3 安装上运行 import yaml 会导致 ModuleNotFoundError: No module named 'yaml'
import yaml; from munch import munchify; f = munchify(yaml.load(…)); print(fo.d.try)
示例:
defaults.yaml
url: https://www.google.com
environment.py
from ruamel import yaml
data = yaml.safe_load(open('defaults.yaml'))
data['url']
【讨论】:
要访问 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'])
【讨论】:
我使用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 并没有死,它只是在不同的地方维护。
【讨论】:
#!/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:]))
【讨论】:
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())
【讨论】:
我不确定以前是如何不建议这样做的,但我强烈建议使用 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 解析字段。
【讨论】: