繁体   English   中英

Python Enum类(使用tostring fromstring)

[英]Python Enum class (with tostring fromstring)

我找到了一种简单的方法来实现(破解)枚举到Python:

class MyEnum:
  VAL1, VAL2, VAL3 = range(3)

我可以这样称呼它:

bob = MyEnum.VAL1

性感!

好吧,现在我希望能够在给定字符串时获得数值,或者如果给定数值则获得字符串。 假设我希望字符串与Enum键完全匹配

我能想到的最好的是这样的:

class MyEnum:
  VAL1, VAL2, VAL3 = range(3)
  @classmethod
  def tostring(cls, val):
    if (val == cls.VAL1):
      return "VAL1"
    elif (val == cls.VAL2):
      return "VAL2"
    elif (val == cls.VAL3):
      return "VAL3"
    else:
      return None
  @classmethod
  def fromstring(cls, str):
    if (str.upper() == "VAL1"):
      return cls.VAL1
    elif (str.upper() == "VAL2"):
      return cls.VAL2
    elif (str.upper() == "VAL2"):
      return cls.VAL2
    else:
      return None

或类似的东西(忽略我如何捕捉无效案件)

有没有更好的,更蟒蛇为中心的方式去做我上面做的事情? 或者以上内容已经尽可能简洁。

似乎必须有一个更好的方法来做到这一点。

[时间流逝...]

新的Python Enum终于登陆了3.4,并且也被推迟了 所以你的问题的答案现在就是使用它。 :)


一个例子:

>>> from enum import Enum
>>> class Modes(Enum) :
...    Mode1 = "M1"
...    Mode2 = "M2"
...    Mode3 = "M3"
...

>>> Modes.Mode1
<Modes.Mode1: 'M1'>

>>> Modes.Mode1.value
'M1'

>>> Modes.Mode1.value
'M1'

>>> Modes['Mode1']    # index/key notation for name lookup
<Modes.Mode1: 'M1'>

>>> Modes('M1')       # call notation for value lookup
<Modes.Mode1: 'M1'>

>>> Modes("XXX")      # example error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Anaconda3\lib\enum.py", line 291, in __call__
    return cls.__new__(cls, value)
  File "C:\Anaconda3\lib\enum.py", line 533, in __new__
    return cls._missing_(value)
  File "C:\Anaconda3\lib\enum.py", line 546, in _missing_
    raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 'XXX' is not a valid Modes

那么,这就是你要求的:

class MyEnum:
  VAL1, VAL2, VAL3 = range(3)
  @classmethod
  def tostring(cls, val):
    for k,v in vars(cls).iteritems():
        if v==val:
            return k

  @classmethod
  def fromstring(cls, str):
      return getattr(cls, str.upper(), None)

print MyEnum.fromstring('Val1')
print MyEnum.tostring(2)

但我真的不明白Python中的Enums。 它拥有如此丰富的类型系统以及管理状态的生成器和协同程序。

我知道我已经超过12年没有在Python中使用Enums了,也许你也可以摆脱它们;-)

使用词典:

MyEnum = {'VAL1': 1, 'VAL2':2, 'VAL3':3}

没有必要的课程。 Dicts让你的班级节拍,因为1.)他们非常有效率,2。)有一堆令人难以置信的方法,以及3.)是一种通用的语言结构。 它们也是可扩展的:

MyEnum['VAL4'] = 4

在Python中实现C ++(或其他语言)功能并不明智。 如果你发现自己“乱搞枚举”或那种性质的东西,你可以打赌你不是用Python方式做的那个农场。

如果你想采取相反的方式,建立另一个字典。 (例如{'1':'VAL1', ...}

请参阅: 如何在Python中表示“Enum”?

这个很有意思:

class EnumMeta(type):
  def __getattr__(self, name):
    return self.values.index(name)

  def __setattr__(self, name, value):  # this makes it read-only
    raise NotImplementedError

  def __str__(self):
    args = {'name':self.__name__, 'values':', '.join(self.values)}
    return '{name}({values})'.format(**args)

  def to_str(self, index):
    return self.values[index]

class Animal(object):
  __metaclass__ = EnumMeta
  values = ['Horse','Dog','Cat']

使用:

In [1]: Animal.to_str(Animal.Dog)
Out[1]: 'Dog'
In [2]: Animal.Dog
Out[2]: 1
In [3]: str(Animal)
Out[3]: 'Animal(Horse, Dog, Cat)'

它简单轻巧。 这种方法有什么缺点吗?

编辑:AFAIK枚举不是一个非常pythonic作为一个概念,这就是为什么他们没有首先实现。 我从来没有使用它们,也没有在Python中看到它们的任何用例。 枚举在静态类型语言中很有用,因为它们不是动态的;)

这将做你想要的,并简化你的实现,略微减少锅炉板代码:

class EnumBase: # base class of all Enums
    @classmethod
    def tostring(cls, value):
        return dict((v,k) for k,v in cls.__dict__.iteritems())[value]

    @classmethod
    def fromstring(cls, name):
        return cls.__dict__[name]

class MyEnum(EnumBase): VAL1, VAL2, VAL3 = range(3)

print MyEnum.fromstring('VAL1')
# 0
print MyEnum.tostring(1)
# VAL2

你可以使用词典:

class MyEnum:
    VAL1, VAL2, VAL3 = range(3)
    __toString = { VAL1 : "VAL1", VAL2 : "VAL2", VAL3 : "VAL3" }

    @classmethod
    def tostring(cls, val):
        return cls.__toString.get(val)

    @classmethod
    def fromstring(cls, str):
        i = str.upper()
        for k,v in cls.__toString.iteritems():
            if v == i:
                return k
        return None


print MyEnum.tostring(MyEnum.VAL1)
print MyEnum.fromstring("VAL1")

编辑:THC4k答案肯定更好。 但是我的作为天真实施的一个例子。

您不必在类中硬编码您的值 - 您最好有一个枚举器工厂。 除此之外,只需添加Python提供的一些改进,例如,覆盖represntation方法或属性获取:

class Enumerator(object):
    def __init__(self, *names):
        self._values = dict((value, index) for index, value in enumerate (names))
    def __getattribute__(self, attr):
        try:
            return object.__getattribute__(self,"_values")[attr]
        except KeyError:
            return object.__getattribute__(self, attr)
    def __getitem__(self, item):
        if isinstance (item, int):
            return self._values.keys()[self._values.values().index(item)]
        return self._values[item]
    def __repr__(self):
        return repr(self._values.keys())

现在只需使用:

>>> enum = Enumerator("val1", "val2", "val3")
>>> enum
['val3', 'val2', 'val1']
>>> enum.val2
1
>>> enum["val1"]
0
>>> enum[2]
'val3'

(顺便说一句,Python开发人员列表中的人正在讨论这个问题,我们很可能会有更完整的功能,并且具有足够的功能,可以通过Python 3.3本地实现这一功能)

暂无
暂无

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

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