【问题标题】:dump an python object as yaml file将 python 对象转储为 yaml 文件
【发布时间】:2014-02-11 07:31:04
【问题描述】:

我在将下面显示的 Python 对象转储到 yaml 文件时遇到问题。我想知道是否有任何特定的对象类型/格式。

class CameraBrand():

  def __init__(self, name, url):
    self.rank = ""
    self.name = name
    self.url = url
    self.models = []

  def __str__(self):
      return self.name + ": " + self.url

此对象包含对象列表,我尝试使用yaml.safe_dump

  yaml.safe_dump(brandObject, file)

但是我收到了这个错误:

yaml.representer.RepresenterError: cannot represent an object: Canon: /cameras/canon/

这个对象有问题吗?

【问题讨论】:

    标签: python yaml


    【解决方案1】:

    这是一篇旧帖子,但要补充Jayanth Koushik's answer

    不确定没有实现__repr__ 是这里的罪魁祸首。我尝试实现它,它仍然会引发错误,所以解决方案可能不正确:

    import yaml
    
    class CameraBrand():
    
      def __init__(self, name, url):
        self.rank = ""
        self.name = name
        self.url = url
        self.models = []
    
      def __str__(self):
          return repr(self)
    
      def __repr__(self):
          return self.name + ": " + self.url
    
    
    brand_object = CameraBrand('foo', 'http://foo.com')
    print(yaml.safe_dump(brand_object))
    

    还是加注yaml.representer.RepresenterError: cannot represent an object: foo: http://foo.com

    其实答案可以在PyYaml documentation找到:“safe_dump只产生标准的YAML标签,不能代表任意的Python对象。”。因此,您只需要使用dump 而不是safe_dump

    >>> print(yaml.dump(brand_object))
    
    !!python/object:__main__.CameraBrand
    models: []
    name: foo
    rank: ''
    url: http://foo.com
    

    然而,一旦你这样做了,你会看到加载你的对象回来

    • 不安全不推荐yaml.load
    • 但是使用强烈推荐的safe_load 会变得有点棘手。为此,您必须深入研究YAMLObject 和其他 PyYaml 类,这有点棘手。

    或者,您可以使用 yamlable 库,它会为您自动执行其中一些 PyYaml 技巧。我写它是为了解决我们生产代码中的类似情况,以便更容易控制对象到 yaml 的绑定过程。在您的情况下,以下方法可以解决问题:

    import yaml
    from yamlable import YamlAble, yaml_info
    
    @yaml_info(yaml_tag_ns='myyaml')
    class CameraBrand(YamlAble):
    
        def __init__(self, name, url):
            self.rank = ""
            self.name = name
            self.url = url
            self.models = []
    
        def __str__(self):
            return self.name + ": " + self.url
    
        def to_yaml_dict(self):
            return {'name': self.name, 'url': self.url}
    
        # @classmethod
        # def from_yaml_dict(cls, dct, yaml_tag):
        #     return CameraBrand(**dct)
    
    
    brand_object = CameraBrand('foo', 'http://foo.com')
    print(yaml.safe_dump(brand_object))
    

    产量

    !yamlable/myyaml.CameraBrand {name: foo, url: 'http://foo.com'}
    

    print(yaml.safe_load("""!yamlable/myyaml.CameraBrand
    name: foo
    url: http://bar.com
    """))
    

    正确加载对象并显示其字符串表示:

    foo: http://bar.com
    

    请注意,如果您希望在加载对象时执行一些自定义操作,也可以取消注释 from_yaml_dict 方法。详情请见yamlable documentation

    【讨论】:

    • 它是否也适用于嵌套定义?喜欢:dict[in][out] = value
    • @alper 应该是的,只要 pyyaml 支持它
    【解决方案2】:

    如果你还想safe_dump怎么办? 没有 dump 并且为每个对象编写一个表示器,也没有另一个依赖项?

    好吧,您可以编写一个包罗万象的方法,例如 JSON dumpers 的“默认”参数,然后覆盖在 YAML SafeRepresenter 中引发异常的那个。

    使用PyAML 3.12 的概念证明。

    import yaml
    
    yaml.SafeDumper.yaml_representers[None] = lambda self, data: \
        yaml.representer.SafeRepresenter.represent_str(
            self,
            str(data),
        )
    

    例子:

    >>> import collections
    >>> yaml.safe_dump([collections.namedtuple('Foo', 'bar')(1)])                                                                                                  
    '[Foo(bar=1)]\n'
    
    >>> yaml.safe_dump(CameraBrand('Canon', '/cameras/canon/'))
    "'Canon: /cameras/canon/'\n"
    

    注意:namedtuple 特定主题,请参阅:Serializing namedtuples via PyYAML

    【讨论】:

      【解决方案3】:

      您需要为该类实现 __repr__。您可以将 __str__ 用作 __repr__。

      【讨论】:

        猜你喜欢
        • 2018-11-23
        • 2014-06-11
        • 1970-01-01
        • 2021-04-25
        • 2012-10-12
        • 2019-05-21
        • 2020-09-01
        • 2016-01-03
        • 2017-11-03
        相关资源
        最近更新 更多