考虑:
class Item:
def __init__(self, a, b):
self.a = a
self.b = b
class Items:
GREEN = Item('a', 'b')
BLUE = Item('c', 'd')
有没有办法让简单枚举的想法适应这种情况? (参见this question)理想情况下,就像在Java中一样,我想将它们全部塞进一个类中。
Java模型:
enum EnumWithAttrs {
GREEN("a", "b"),
BLUE("c", "d");
EnumWithAttrs(String a, String b) {
this.a = a;
this.b = b;
}
private String a;
private String b;
/* accessors and other java noise */
}
答案 0 :(得分:9)
Python 3.4有一个new Enum data type(已backported as enum34
和enhanced as aenum
1 )。 enum34
和aenum
2 都可以轻松支持您的使用案例:
[aenum
py2 / 3]
import aenum
class EnumWithAttrs(aenum.AutoNumberEnum):
_init_ = 'a b'
GREEN = 'a', 'b'
BLUE = 'c', 'd'
[enum34
py2 / 3或stdlib enum
3.4 +]
import enum
class EnumWithAttrs(enum.Enum):
def __new__(cls, *args, **kwds):
value = len(cls.__members__) + 1
obj = object.__new__(cls)
obj._value_ = value
return obj
def __init__(self, a, b):
self.a = a
self.b = b
GREEN = 'a', 'b'
BLUE = 'c', 'd'
并在使用中:
--> EnumWithAttrs.BLUE
<EnumWithAttrs.BLUE: 1>
--> EnumWithAttrs.BLUE.a
'c'
1 披露:我是Python stdlib Enum
,enum34
backport和Advanced Enumeration (aenum
)图书馆的作者。
2 aenum
还支持NamedConstants
和基于元类的NamedTuples
。
答案 1 :(得分:5)
这是我认为比其他方法更简单但又具有最大灵活性的另一种方法:
compromise
按预期工作:
from collections import namedtuple
from enum import Enum
class Status(namedtuple('Status', 'name description'), Enum):
READY = 'ready', 'I am ready to do whatever is needed'
ERROR = 'error', 'Something went wrong here'
def __str__(self) -> str:
return self.name
打印:
print(Status.READY)
print(repr(Status.READY))
print(Status.READY.description)
print(Status.READY.value)
您将获得namedtuple 和 Enum的精华。
答案 2 :(得分:4)
使用namedtuple:
from collections import namedtuple
Item = namedtuple('abitem', ['a', 'b'])
class Items:
GREEN = Item('a', 'b')
BLUE = Item('c', 'd')
答案 3 :(得分:2)
对于Python 3:
class Status(Enum):
READY = "ready", "I'm ready to do whatever is needed"
ERROR = "error", "Something went wrong here"
def __new__(cls, *args, **kwds):
obj = object.__new__(cls)
obj._value_ = args[0]
return obj
# ignore the first param since it's already set by __new__
def __init__(self, _: str, description: str = None):
self._description_ = description
def __str__(self):
return self.value
# this makes sure that the description is read-only
@property
def description(self):
return self._description_
您可以按类型将其用作标准枚举或工厂:
print(Status.READY)
# ready
print(Status.READY.description)
# I'm ready to do whatever is needed
print(Status("ready")) # this does not create a new object
# ready
答案 4 :(得分:1)
受到其他一些答案的启发,我找到了一种方法,可以尽可能“透明地”将附加字段包含到枚举中,从而克服了其他方法的一些缺点。一切正常,就好像没有附加字段一样。
枚举就像元组一样是不可变的,枚举的值就像没有附加字段一样,它的工作方式就像带有 auto()
的普通枚举,并且可以通过值选择枚举。
import enum
# Common base class for all enums you want to create with additional fields (you only need this once)
class EnumFI(enum.Enum):
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls._values = []
def __new__(cls, *args, **kwargs):
value = args[0]
if isinstance(value, enum.auto):
if value.value == enum._auto_null:
value.value = cls._generate_next_value_(None, 1, len(cls.__members__), cls._values[:]) # Note: This just passes None for the key, which is generally okay
value = value.value
args = (value,) + args[1:]
cls._values.append(value)
instance = cls._member_type_.__new__(cls, *args, **kwargs)
instance._value_ = value
return instance
然后您可以在代码中的任何位置执行:
from enum import auto
from collections import namedtuple
class Color(namedtuple('ColorTuple', 'id r g b'), EnumFI):
GREEN = auto(), 0, 255, 0
BLUE = auto(), 0, 0, 255
示例输出:
In[4]: Color.GREEN
Out[4]: <Color.GREEN: 1>
In[5]: Color.GREEN.value
Out[5]: 1
In[6]: Color.GREEN.r
Out[6]: 0
In[7]: Color.GREEN.g
Out[7]: 255
In[8]: Color.GREEN.b
Out[8]: 0
In[9]: Color.GREEN.r = 8
Traceback (most recent call last):
File "/home/phil/anaconda3/envs/dl/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 3326, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-9-914a059d9d3b>", line 1, in <module>
Color.GREEN.r = 8
AttributeError: can't set attribute
In[10]: Color(2)
Out[10]: <Color.BLUE: 2>
In[11]: Color['BLUE']
Out[11]: <Color.BLUE: 2>
答案 5 :(得分:0)
对于小型枚举@property 可能有效:
class WikiCfpEntry(Enum):
'''
possible supported storage modes
'''
EVENT = "Event"
SERIES = "Series"
@property
def urlPrefix(self):
baseUrl="http://www.wikicfp.com/cfp"
if self==WikiCfpEntry.EVENT:
url= f"{baseUrl}/servlet/event.showcfp?eventid="
elif self==WikiCfpEntry.SERIES:
url= f"{baseUrl}/program?id="
return url