在python中订购枚举值


问题内容

我希望能够安排Enum的顺序。是否有人建议如何解决?

以下Enum元类正在使用:

class EnumMeta(type):
    def __new__(typ, name, bases, attrs):
        cls_attrs = {}
        cls_choices = []
        for attr_name, value in attrs.items():
            cls_attrs[attr_name] = attr_name.lower()
            if not attr_name.startswith("__"):
                cls_choices.append((attr_name.lower(), value))

        def choices(cls):
            return cls_choices

        def values(cls, value=None):
            if value is None:
                return {choice[0]: unicode(choice[1]) for choice in cls.choices()}
            elif isinstance(value, list):
                return {choice[0]: unicode(choice[1]) for choice in cls.choices() if choice[0] in value}
            else:
                return unicode(dict(cls.choices()).get(value))

        def keys(cls, nil=False):
            items = [item[0] for item in cls.choices()]
            if nil:
                items.append('')

            return items

        def combined_length(cls):
            return len(",".join(cls.values().keys()))

        def max_length(cls):
            return max(map(len, cls.values().keys()))

        cls_attrs['choices'] = classmethod(choices)
        cls_attrs['values'] = classmethod(values)
        cls_attrs['keys'] = classmethod(keys)
        cls_attrs['combined_length'] = classmethod(combined_length)
        cls_attrs['max_length'] = classmethod(max_length)

        return type(name, bases, cls_attrs)

枚举的示例如下:

class SideHemType:
    __ordering__ = ['double', 'single']
    __metaclass__ = EnumMeta

    Single = "Single side hem for opaque fabrics"
    Double = "Double side hem for transparent fabrics"


  class TestEnumOrdering:
        print SideHemType.keys()
        print SideHemType.values()

通过打印Enum SideHemType,首先打印Double,然后打印Single。但我想先选单,再选双。


问题答案:

您的Enum在3个地方丢失了订单。首先,将类主体上的属性存储在字典中,然后将项目复制到另一个字典中。最后,您values()将返回第三个字典。字典不保存顺序,并且不可能在类主体中获得属性的顺序。

有了这个系统,最简单的就是拥有一个变量

__ordering__ = [ 'single', 'double' ]

并将values()返回值作为元组列表(如dict.items())。

class EnumMeta(type):
    def __new__(typ, name, bases, attrs):
        cls_attrs = {}
        cls_choices = {}

        for attr_name, value in attrs.items():
            cls_attrs[attr_name] = attr_name.lower()
            if not attr_name.startswith("__"):
                cls_choices[attr_name.lower()] = value

        ordering = attrs.get('__ordering__')
        if ordering == None:
            ordering = sorted(cls_choices.keys())

        def choices(cls):
            return dict(cls_choices)

        def values(cls, value=None):
            if value is None:
                return [ (k, cls_choices[k] ) for k in ordering ]
            elif not isinstance(value, basestring):
                return [ (k, cls_choices[k] ) for k in value ]
            else:
                return unicode(cls_choices.get(value))

        def keys(cls, nil=False):
            items = list(ordering)
            if nil:
                items.append('')

            return items

        def combined_length(cls):
            return len(",".join(cls.values().keys()))

        def max_length(cls):
            return max(map(len, cls.values().keys()))

        cls_attrs['choices'] = classmethod(choices)
        cls_attrs['values'] = classmethod(values)
        cls_attrs['keys'] = classmethod(keys)
        cls_attrs['combined_length'] = classmethod(combined_length)
        cls_attrs['max_length'] = classmethod(max_length)

        return type(name, bases, cls_attrs)

class SideHemType:
    __ordering__ = ['double', 'single']
    __metaclass__ = EnumMeta

    Single = "Single side hem for opaque fabrics"
    Double = "Double side hem for transparent fabrics"


print SideHemType.keys()
print SideHemType.values()