【问题标题】:How can I add a python tuple to a YAML file using pyYAML?如何使用 pyYAML 将 python 元组添加到 YAML 文件?
【发布时间】:2012-02-28 10:53:55
【问题描述】:

标题是不言自明的。

当我将元组保存到 YAML 文件时,我得到如下所示的内容:

ambient:  !!python/tuple [0.3, 0.3 ,0.3]

当我尝试使用 yaml.safe_load(file_object) 加载它时,我不断收到错误消息:

yaml.constructor.ConstructorError:  could not determine a constructor for the tag 'tag:yaml.org,2002:python/tuple'

需要做什么?

【问题讨论】:

    标签: python pyyaml


    【解决方案1】:

    在 pyyaml 中,SafeLoader 不包含用于 python 原生类型的加载器,仅包含 yaml 规范中定义的类型。您可以在下面的交互示例中查看SafeLoaderLoader 的类型。

    你可以定义一个新的 Loader 类,添加到 python 元组中,但不能添加其他类型,所以它应该仍然很安全:

    import yaml
    
    class PrettySafeLoader(yaml.SafeLoader):
        def construct_python_tuple(self, node):
            return tuple(self.construct_sequence(node))
    
    PrettySafeLoader.add_constructor(
        u'tag:yaml.org,2002:python/tuple',
        PrettySafeLoader.construct_python_tuple)
    
    doc = yaml.dump(tuple("foo bar baaz".split()))
    print repr(doc)
    thing = yaml.load(doc, Loader=PrettySafeLoader)
    print thing
    

    导致:

    '!!python/tuple [foo, bar, baaz]\n'
    ('foo', 'bar', 'baaz')
    

    有关与 SafeLoader 和 Loader 类关联的构造函数,请参见下文。

    >>> yaml.SafeLoader.yaml_constructors
    {None: <unbound method SafeConstructor.construct_undefined>,
     u'tag:yaml.org,2002:binary': <unbound method SafeConstructor.construct_yaml_binary>,
     u'tag:yaml.org,2002:bool': <unbound method SafeConstructor.construct_yaml_bool>,
     u'tag:yaml.org,2002:float': <unbound method SafeConstructor.construct_yaml_float>,
     u'tag:yaml.org,2002:int': <unbound method SafeConstructor.construct_yaml_int>,
     u'tag:yaml.org,2002:map': <unbound method SafeConstructor.construct_yaml_map>,
     u'tag:yaml.org,2002:null': <unbound method SafeConstructor.construct_yaml_null>,
     u'tag:yaml.org,2002:omap': <unbound method SafeConstructor.construct_yaml_omap>,
     u'tag:yaml.org,2002:pairs': <unbound method SafeConstructor.construct_yaml_pairs>,
     u'tag:yaml.org,2002:seq': <unbound method SafeConstructor.construct_yaml_seq>,
     u'tag:yaml.org,2002:set': <unbound method SafeConstructor.construct_yaml_set>,
     u'tag:yaml.org,2002:str': <unbound method SafeConstructor.construct_yaml_str>,
     u'tag:yaml.org,2002:timestamp': <unbound method SafeConstructor.construct_yaml_timestamp>}
    
    >>> yaml.Loader.yaml_constructors
    {None: <unbound method SafeConstructor.construct_undefined>,
     u'tag:yaml.org,2002:binary': <unbound method SafeConstructor.construct_yaml_binary>,
     u'tag:yaml.org,2002:bool': <unbound method SafeConstructor.construct_yaml_bool>,
     u'tag:yaml.org,2002:float': <unbound method SafeConstructor.construct_yaml_float>,
     u'tag:yaml.org,2002:int': <unbound method SafeConstructor.construct_yaml_int>,
     u'tag:yaml.org,2002:map': <unbound method SafeConstructor.construct_yaml_map>,
     u'tag:yaml.org,2002:null': <unbound method SafeConstructor.construct_yaml_null>,
     u'tag:yaml.org,2002:omap': <unbound method SafeConstructor.construct_yaml_omap>,
     u'tag:yaml.org,2002:pairs': <unbound method SafeConstructor.construct_yaml_pairs>,
     u'tag:yaml.org,2002:python/bool': <unbound method Constructor.construct_yaml_bool>,
     u'tag:yaml.org,2002:python/complex': <unbound method Constructor.construct_python_complex>,
     u'tag:yaml.org,2002:python/dict': <unbound method Constructor.construct_yaml_map>,
     u'tag:yaml.org,2002:python/float': <unbound method Constructor.construct_yaml_float>,
     u'tag:yaml.org,2002:python/int': <unbound method Constructor.construct_yaml_int>,
     u'tag:yaml.org,2002:python/list': <unbound method Constructor.construct_yaml_seq>,
     u'tag:yaml.org,2002:python/long': <unbound method Constructor.construct_python_long>,
     u'tag:yaml.org,2002:python/none': <unbound method Constructor.construct_yaml_null>,
     u'tag:yaml.org,2002:python/str': <unbound method Constructor.construct_python_str>,
     u'tag:yaml.org,2002:python/tuple': <unbound method Constructor.construct_python_tuple>,
     u'tag:yaml.org,2002:python/unicode': <unbound method Constructor.construct_python_unicode>,
     u'tag:yaml.org,2002:seq': <unbound method SafeConstructor.construct_yaml_seq>,
     u'tag:yaml.org,2002:set': <unbound method SafeConstructor.construct_yaml_set>,
     u'tag:yaml.org,2002:str': <unbound method SafeConstructor.construct_yaml_str>,
     u'tag:yaml.org,2002:timestamp': <unbound method SafeConstructor.construct_yaml_timestamp>}
    

    【讨论】:

    • 这很有意义。非常感谢!
    【解决方案2】:

    至少按照the PyYAML documentation

    yaml.safe_load 函数将这种能力限制为简单的 Python 对象,如整数或列表。

    as you can see in the source 列表更广泛,但不包括 tag:yaml.org,2002:python/tuple

    看来,如果您在 YAML 文件中生成 !!python/tuple 类型,则您使用的是 dump(),而不是 safe_dump()。如果是这种情况,您可能应该改用load() 代替safe_load(),因为dump() 创建的文件不能保证safe_load() 可以加载。 (见description of safe_dump())。

    【讨论】:

    • 我添加了缺少的单词 not,但我不确定您是否真的不想反过来表述它...
    • 在什么情况下一个理性的人会认为使用 yaml.loader(而不是 safe_loader)是危险的?我正在编写一个加载 YAML 文件中定义的资产的游戏。恶意下载可能会覆盖我的 YAML 文件,从而让我的游戏加载危险代码,但这似乎是最终用户的问题。我能做的不多……对吧?
    • @blz YAML 可用于不同项目之间的配置和通信。如果您的 YAML 来自您无法控制的来源,则您不想使用 yaml.load
    【解决方案3】:

    对于那些正在寻找最新答案的人。

    目前,这个问题可以通过yaml.FullLoader解决。

    import yaml
    yaml_file = open("path/to/filename.yaml", 'r')
    loaded_yaml = yaml.load(yaml_file, Loader=yaml.FullLoader)
    

    然后标记为如下元组的条目将被正确解析而没有任何问题。

    !!python/tuple [0.3, 0.3 ,0.3]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-15
      • 2020-05-29
      • 2019-04-08
      • 2021-05-17
      • 2015-10-23
      • 2012-07-20
      • 2017-01-25
      • 2012-12-16
      相关资源
      最近更新 更多