[英]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.