简体   繁体   English

ruamel.yaml可以编码枚举吗?

[英]Can ruamel.yaml encode an enum?

The following is not working for me, with Python 3.4.7, ruamel.yaml version 0.15.35: 以下对我来说不起作用,使用Python 3.4.7,ruamel.yaml版本0.15.35:

import sys
import enum

import ruamel.yaml
from ruamel.yaml import yaml_object
yaml = ruamel.yaml.YAML()

@yaml_object(yaml)
class Speed(enum.IntEnum):
    Reverse = 0
    Neutral = 1
    Low = 2
    Drive = 3
    Park = 999

print("Neutral:", repr(Speed.Neutral))

yaml.dump(Speed.Neutral, sys.stdout)

I get a totally reasonable repr : 我得到了一个完全合理的repr

Neutral: <Speed.Neutral: 1>

but the .dump() raises: .dump()提出:

ruamel.yaml.representer.RepresenterError: cannot represent an object: <enum 'Speed'>

If enum 's are not supported, is there something I can do to extend the enum class I am using (or the subclass enum.IntEnum I have created), eg a dunder method? 如果不支持enum ,我可以做些什么来扩展我正在使用的enum类(或者我创建的子类enum.IntEnum ),例如dunder方法?

enum is not supported out-of-the-box, essentially because the default dump method is safe and therefore doesn't support arbitrary Python objects. enum不支持开箱即用,主要是因为默认的dump方法是安全的,因此不支持任意Python对象。 That safety excludes types as enum from the standard library as well. 该安全性也将标准库中的类型排除为enum

What you should do is add a to_yaml classmethod to your Speed class as described in the ruamel.yaml documentation : 你应该做的就是添加一个to_yaml classmethod ,以你的Speed类作为中描述ruamel.yaml文档

import sys
import enum

import ruamel.yaml
from ruamel.yaml import yaml_object
yaml = ruamel.yaml.YAML()

@yaml_object(yaml)
class Speed(enum.IntEnum):
    Reverse = 0
    Neutral = 1
    Low = 2
    Drive = 3
    Park = 999

    @classmethod
    def to_yaml(cls, representer, node):
        return representer.represent_scalar(
            u'!Speed',
            '{}-{}'.format(node._name_, node._value_)
        )

yaml.dump(Speed.Neutral, sys.stdout)

which gives: 这使:

!Speed Neutral-1
...

You can of course adapt the string representation to your liking (and add a from_yaml to be able to load the output back in). 您当然可以根据自己的喜好调整字符串表示(并添加from_yaml以便能够将输出加载回来)。

Please note that you cannot add yaml_tag as in the documentation example, as this would interfere with the enum values. 请注意,您不能像文档示例中那样添加yaml_tag ,因为这会干扰enum值。

I think you'll need to pass the enum by value. 我认为你需要通过值传递枚举。

https://docs.python.org/3/library/enum.html#programmatic-access-to-enumeration-members-and-their-attributes https://docs.python.org/3/library/enum.html#programmatic-access-to-enumeration-members-and-their-attributes

yaml.dump(Speed.Neutral.value, sys.stdout)

Extended answer to add a @classmethod which calls .value as it's being passed 扩展答案添加@classmethod,在传递时调用.value

http://yaml.readthedocs.io/en/latest/dumpcls.html http://yaml.readthedocs.io/en/latest/dumpcls.html

import sys
import enum
import ruamel.yaml
from ruamel.yaml import yaml_object
yaml = ruamel.yaml.YAML()

@yaml_object(yaml)
class Speed(enum.IntEnum):
    Reverse = 0
    Neutral = 1
    Low = 2
    Drive = 3
    Park = 999

    @classmethod
    def to_yaml(cls, representer, node):
        return representer.represent_scalar(u'!enum:', u'{.value}'.format(node))

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

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