将python对象转储为yaml文件

时间:2014-02-11 07:31:04

标签: python yaml

我在将下面显示的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.save_dump

  yaml.safe_dump(brandObject, file)

但我收到了这个错误:

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

这个对象有问题吗?

3 个答案:

答案 0 :(得分:5)

这是旧帖子,但补充了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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

如果您仍然想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