将 PyYAML 3.11 与 Python 2.7.6 结合使用,让我们转储一个简单的字典,该字典只有一个字符串键(长度为 122 个字符),映射到值“1”:
>>> print yaml.dump({'12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012': 1})
{'12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012': 1}
这正如预期一样工作 - 简单、人类可读的 YAML。但现在我们将该字符串键的长度增加到 123 个字符。现在 PyYAML 创建一个不太人类可读的复杂键,以“?”开头,并将值“1”分流到新行:
>>> print yaml.dump({'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123': 1})
{? '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123'
: 1}
PyYAML 为什么要这样做?有什么办法可以禁用该行为吗?这会导致我转储的 YAML 代码缺乏视觉一致性,具体取决于字符串键的长度。
您获得显式密钥标记
?
的原因是您超过了简单密钥的长度限制。在发射器中的函数中将其与 128 进行比较(隐式标签 !!str
的长度将其推过该阈值)。您可以重写检查键的完整函数以使其变得简单,但没有简单的方法可以做到这一点,因为该值是硬编码在函数内的。
我一直无法在 YAML 规范中找到 this 特定阈值的原因。在 PyYAML 源中也不行,因为在解析器端它能够处理如此长的键(有或没有
?
)。
在 ruamel.yaml 1 中,您可以通过更改转储器实例来更改阈值:
from __future__ import print_function
import sys
import ruamel.yaml as yaml
yaml_str = """\
- {'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123': 1}
"""
data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)
dumper = yaml.RoundTripDumper
print('MAX_SIMPLE_KEY_LENGTH', dumper.MAX_SIMPLE_KEY_LENGTH)
yaml.dump(data, sys.stdout, Dumper=dumper)
dumper.MAX_SIMPLE_KEY_LENGTH = 256
print('After raising the threshold:')
yaml.dump(data, sys.stdout, Dumper=dumper)
会给你:
MAX_SIMPLE_KEY_LENGTH 128
- {? '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123'
: 1}
After raising the threshold:
- {'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123': 1}
当我通常在 80 列的终端窗口上工作时,我仍然发现那么长的按键很难阅读,当然 YMMV。尤其是在往返 YAML 时,需要对密钥以这种方式更改的时间进行精细控制。
¹ 免责声明:我是 PyYAML 增强版的作者。
简单的问题解决:
from ruamel.yaml.emitter import Emitter
Emitter.MAX_SIMPLE_KEY_LENGTH = 1024
在更现代的
ruamel
0.18.6
中,无需修改全局变量:
import ruamel.yaml
y = ruamel.yaml.YAML(typ='safe', pure=True)
y.emitter.MAX_SIMPLE_KEY_LENGTH = 1_000_000
y.dump(...)