简体   繁体   English

将 python 对象转储为 yaml 文件

[英]dump an python object as yaml file

I am having problems dumping the Python object shown below to a yaml file.我在将下面显示的 Python 对象转储到 yaml 文件时遇到问题。 I was wondering whether there is any specific object type/format.我想知道是否有任何特定的对象类型/格式。

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

This object contains a list of objects, and I tried to use yaml.safe_dump这个对象包含一个对象列表,我尝试使用yaml.safe_dump

  yaml.safe_dump(brandObject, file)

But I got this error:但我收到了这个错误:

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

Is there a problem with this object?这个对象有问题吗?

This is an old post but to complement Jayanth Koushik's answer :这是一篇旧帖子,但要补充Jayanth Koushik 的回答

Not sure that having __repr__ not implemented is the culprit here.不确定没有实现__repr__是这里的罪魁祸首。 I tried implementing it and it still raises an error, so the solution is probably not correct:我尝试实现它,但它仍然引发错误,因此解决方案可能不正确:

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))

still raises yaml.representer.RepresenterError: cannot represent an object: foo: http://foo.com仍然引发yaml.representer.RepresenterError: cannot represent an object: foo: http://foo.com

Actually the answer can be found in PyYaml documentation : " safe_dump produces only standard YAML tags and cannot represent an arbitrary Python object.".实际上答案可以在PyYaml 文档中找到:“ safe_dump只生成标准的 YAML 标签,不能代表任意的 Python 对象。”。 Therefore you simply need to use dump instead of safe_dump :因此,您只需要使用dump而不是safe_dump

>>> print(yaml.dump(brand_object))

!!python/object:__main__.CameraBrand
models: []
name: foo
rank: ''
url: http://foo.com

However, once you do that, you will see that loading your object back但是,一旦你这样做,你会看到加载你的对象

  • is ok with the unsafe and not recommended yaml.load ,可以使用不安全且不推荐的yaml.load
  • but becomes a bit tricky with the highly recommended safe_load .但是使用强烈推荐的safe_load变得有点棘手。 For this you would have to dig a little bit into YAMLObject and other PyYaml classes, and that is a bit tricky.为此,您必须深入研究YAMLObject和其他 PyYaml 类,这有点棘手。

Alternatively, you can use the yamlable library, which automates a few of these PyYaml tricks for you.或者,您可以使用yamlable库,它会为您自动执行一些 PyYaml 技巧。 I wrote it to solve similar cases in our production code, in order to make it easier to control the object-to-yaml binding process.我写它是为了解决我们生产代码中的类似情况,以便更容易控制对象到 yaml 的绑定过程。 In your case, the following would do the trick:在您的情况下,以下方法可以解决问题:

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))

yields产量

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

and

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

loads the object correctly back and displays its string representation:正确加载对象并显示其字符串表示形式:

foo: http://bar.com

Note that you can also uncomment the from_yaml_dict method if you wish to perform some custom action when loading the object.请注意,如果您希望在加载对象时执行某些自定义操作,也可以取消注释from_yaml_dict方法。 See yamlable documentation for details.有关详细信息,请参阅yamlable 文档

What if you still want to safe_dump ?如果你仍然想要safe_dump怎么safe_dump No dump and bothering to write a representer for every object, nor another dependency?没有dump和麻烦为每个对象编写一个代表,也没有另一个依赖?

Well, you could write a method which will catch-all, like the "default" argument to the JSON dumpers and overwrite the one raising an exception in the YAML SafeRepresenter .好吧,您可以编写一个方法来捕获所有内容,例如JSON SafeRepresenter的“默认”参数,并覆盖在 YAML SafeRepresenter引发异常的SafeRepresenter

Proof of concept using PyAML 3.12.使用PyAML 3.12 的概念证明。

import yaml

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

Example:例子:

>>> 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"

Note: for the namedtuple specific topic, see : Serializing namedtuples via PyYAML注意:有关namedtuple特定主题,请参阅:通过PyYAML 序列化namedtuples

You need to implement __repr__ for the class.您需要为该类实现 __repr__ 。 You could just use your __str__ as __repr__.您可以将 __str__ 用作 __repr__。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM