【问题标题】:Skip converting entities while loading a yaml string (using PyYAML)加载 yaml 字符串时跳过转换实体(使用 PyYAML)
【发布时间】:2018-06-17 21:49:05
【问题描述】:

在将 YAML 字符串加载到 yaml 包时,是否有一种很好的方法可以防止实体转换为 python 对象?特别是,我不希望将时间戳字符串转换为日期时间对象。

这是一个例子:

import yaml
yaml.load("""d: 2018-06-17\nn: 42""")

给了

{'d': datetime.date(2018, 6, 17), 'n': 42}

但我想拥有

{'d': '2018-06-17', n: 42}

其中日期字符串保留为字符串,其他类型被转换。我不想更改输入字符串,例如,通过指定特定的数据类型。也许有一个替代的 YAML 加载器/解析器包。我正在使用 python3.6 和 PyYAML==3.12。

【问题讨论】:

  • 这并不能解决我的问题。特别是,例外的答案建议修改我不想要的输入
  • 您可能的选择是修改 yaml 读取结果 - 将 datetime.date(2018, 6, 17) 转换为字符串

标签: python yaml


【解决方案1】:

YAML 有几个模式,由于您在 PyYAML 中使用默认(不安全)加载,您可以获得它支持的 Python 对象的所有构造,包括您想要的 int 和 @987654322 的一个@你不想要的。

由于要转换整数,所以不能使用 baseloader:

import yaml
data = yaml.load("""d: 2018-06-17\nn: 42""", Loader=yaml.BaseLoader)
print(data)

因为这会在任何地方提供字符串:

{'d': '2018-06-17', 'n': '42'}

将匹配的日期时间对象作为字符串处理可能是最简单的。在我的 ruamel.yaml 库中,您可以使用:

import ruamel.yaml

yaml = ruamel.yaml.YAML(typ='safe')
yaml.constructor.yaml_constructors[u'tag:yaml.org,2002:timestamp'] = \
   yaml.constructor.yaml_constructors[u'tag:yaml.org,2002:str']
data = yaml.load("""d: 2018-06-17\nn: 42""")
print(data)

如果你只需要支持旧的 YAML 1.1 规范,你可以在 PyYAML 中做同样的事情:

import yaml
import yaml.constructor
yaml.constructor.SafeConstructor.yaml_constructors[u'tag:yaml.org,2002:timestamp'] = \
    yaml.constructor.SafeConstructor.yaml_constructors[u'tag:yaml.org,2002:str']

data = yaml.safe_load("""d: 2018-06-17\nn: 42""")
print(data)

两个打印:

{'d': '2018-06-17', 'n': 42}

【讨论】:

  • 如果您既想要“​​正常”加载又想要不解释日期,那么您不能使用上述解决方案,因为 yaml_constructors 是一个类变量。在这种情况下,您需要将SafeLoader 子类化并将其.add_constructor 用于除timestamp 之外的所有项目
  • 这是我想要的。谢谢。有没有关于 pyyaml 中的构造函数的好文档?
  • @desiato 不是。在 ruamel.yaml 中开发往返更改的更改时,我收集了分析代码的“见解”。
  • @Anthon 建议的选项用字符串构造函数替换时间戳构造函数会产生副作用。输出中的值是单引号的。为了克服这个问题,我不得不完全删除构造函数:yaml.constructor.yaml_constructors.pop(u'tag:yaml.org,2002:timestamp', None)
【解决方案2】:

我认为这种行为深深植根于 YAML 规范中,我尝试了ruamel,但结果是一样的。

from ruamel.yaml import YAML
from datetime import date

yaml=YAML(typ="unsafe")
assert yaml.load("""d: 2018-06-17\nn: 42""") == \
       {'d': date(2018, 6, 17), 'n': 42}

如果我遇到这个问题,我会尝试在需要的地方将 YAML 导入转换回 .strftime('YYYY-MM-DD')

【讨论】:

  • YAML 1.2 和 PyYAML 遵循的过时的 YAML 1.1 规范中都提到了 YAML tag repositoryunsafesafe 加载器实现了所有这些(不安全的也是语言特定的,这使得它不安全)。你也有 BaseLoader,它把所有东西都变成了一个字符串。所以我不确定这样写“深深植根于 YAML 规范”是否正确。
  • @Anthon:正确的说法是什么? 默认行为,除非使用 BaseLoader?
  • 这是我所知道的所有 Python YAML 解析器的默认行为。尽管 PyYAML 的 load() 默认值是危险的,因为它允许的不仅仅是来自标签存储库的标签,但并非所有内容都是字符串,实际上使它很有用。大多数情况下,智能对象创建是您想要的,这就是库所提供的,但这并没有 IMO 使其深深植根于规范中,而只是实现的默认值。
猜你喜欢
  • 2012-03-01
  • 2011-10-12
  • 2012-12-16
  • 2019-05-24
  • 2017-12-06
  • 1970-01-01
  • 2020-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多