gpt4 book ai didi

python - PyYAML 自动将某些键转换为 bool 值

转载 作者:太空狗 更新时间:2023-10-30 00:31:33 27 4
gpt4 key购买 nike

几个月来,我一直在使用 PyYAML 解析器来转换文件类型,作为数据管道的一部分。我发现解析器有时非常特殊,今天我似乎偶然发现了另一种奇怪的行为。我当前正在转换的文件包含以下部分:

off:
yes: "Flavor text for yes"
no: "Flavor text for no"

我在字典中保留了一个当前嵌套的列表,这样我就可以构建一个平面文档,但保存嵌套以便稍后转换回 YAML。我得到一个 TypeError 说我正在尝试将 strbool 类型连接在一起。我调查并发现 PyYaml 实际上是将我上面的文本部分转换为以下内容:

with open(filename, "r") as f:
data = yaml.load(f.read())
print data

>> {False: {True: "Flavor text for yes", False: "Flavor text for no}}

我快速检查了一下,发现 PyYAML 正在为 yesnotrue 执行此操作, falseonoff。如果键未被引用,它只会进行此转换。引用的值和键将被正常传递。在寻找解决方案时,我发现记录了此行为 here .

虽然知道引用 key 将阻止 PyYAML 执行此操作可能对其他人有帮助,但我没有此选项,因为我不是这些文件的作者并且已经编写了我的代码尽可能少地接触数据。

是否有针对此问题的解决方法或覆盖 PyYAML 中的默认转换行为的方法?

最佳答案

PyYAML 是 YAML 1.1 conformant用于解析和发出,对于 YAML 1.1,这是 at least partly documented行为,所以根本没有特质,而是有意识的设计。

在 YAML 1.2(2009 年取代了 2005 年的 1.1 规范)中,Off/On/Yes/No 的这种用法被删除,还有其他变化。

ruamel.yaml (免责声明:我是该包的作者),round_trip_loader 是一个默认为 YAML 1.2 行为的 safe_loader:

import ruamel.yaml as yaml

yaml_str = """\
off:
yes: "Flavor text for yes" # quotes around value dropped
no: "Flavor text for no"
"""

data = yaml.round_trip_load(yaml_str)
assert 'off' in data
print(yaml.round_trip_dump(data, indent=4))

给出:

off:
yes: Flavor text for yes # quotes around value dropped
no: Flavor text for no

如果您的输出需要与 1.1 版兼容,那么您可以转储明确的 version=(1, 1)

由于嵌套映射的标量值周围的引号是不必要的,因此它们不会在写出时发出。


如果您需要使用 PyYAML 执行此操作,请重写它用于 bool 识别的(全局)规则:

import  yaml
from yaml.resolver import Resolver
import re

yaml_str = """\
off:
yes: "Flavor text for yes" # quotes around value dropped
no: "Flavor text for no"
"""

# remove resolver entries for On/Off/Yes/No
for ch in "OoYyNn":
if len(Resolver.yaml_implicit_resolvers[ch]) == 1:
del Resolver.yaml_implicit_resolvers[ch]
else:
Resolver.yaml_implicit_resolvers[ch] = [x for x in
Resolver.yaml_implicit_resolvers[ch] if x[0] != 'tag:yaml.org,2002:bool']

data = yaml.load(yaml_str)
print(data)
assert 'off' in data
print(yaml.dump(data))

给出:

{'off': {'yes': 'Flavor text for yes', 'no': 'Flavor text for no'}}
off: {no: Flavor text for no, yes: Flavor text for yes}

之所以可行,是因为 PyYAML 保留了一个全局字典 (Resolver.yaml_implicit_resolvers),它将第一个字母映射到 (tag, re.match_pattern) 值的列表。对于oOyY只有一个这样的模式(可以删除) ,但是对于n/N你也可以匹配null/Null,所以你必须删除正确的模式.

删除后 yesnoonOff 不再被识别为 bool,但是 TrueFalse 仍然是。

关于python - PyYAML 自动将某些键转换为 bool 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36463531/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com