具有属性的python枚举
考虑:具有属性的python枚举,python,enums,Python,Enums,考虑: class Item: def __init__(self, a, b): self.a = a self.b = b class Items: GREEN = Item('a', 'b') BLUE = Item('c', 'd') 有没有办法使简单枚举的思想适应这种情况?(请参阅)理想情况下,就像在Java中一样,我希望将其全部塞进一个类中 Java模型: enum EnumWithAttrs { GREEN("a", "
class Item:
def __init__(self, a, b):
self.a = a
self.b = b
class Items:
GREEN = Item('a', 'b')
BLUE = Item('c', 'd')
有没有办法使简单枚举的思想适应这种情况?(请参阅)理想情况下,就像在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 */
}
在Python3.4和添加优秀之前,一个好的选择是使用: 现在,任何受支持的Python版本都有
enum
,所以请使用该模块。它使您能够更好地控制如何生成每个枚举值
如果为每个项提供一个值元组,则这些值将作为单独的(位置)参数传递给\uuuuu init\uuuuu
方法,从而可以在枚举值上设置其他属性:
from enum import Enum
class Items(Enum):
GREEN = ('a', 'b')
BLUE = ('c', 'd')
def __init__(self, a, b):
self.a = a
self.b = b
这将生成枚举条目,其值是分配给每个名称的元组,以及两个属性a
和b
:
>>> Items.GREEN, Items.BLUE
(<Items.GREEN: ('a', 'b')>, <Items.BLUE: ('c', 'd')>)
>>> Items.BLUE.a
'c'
>>> Items.BLUE.b
'd'
>>> Items(('a', 'b'))
<Items.GREEN: ('a', 'b')>
我还添加了一个自定义的\uuu repr\uuu
,默认值仅包括self.\u value\uu
。现在,每个条目的值由元组中的第一项定义,并可用于查找枚举条目:
>>> Items.GREEN, Items.BLUE
(<Items.GREEN: ('a', 'b')>, <Items.BLUE: ('c', 'd')>)
>>> Items.BLUE.a
'c'
>>> Items.BLUE.b
'd'
>>> Items('a')
<Items.GREEN: ('a', 'b')>
>Items.GREEN,Items.BLUE
(, )
>>>项目。蓝色。a
“c”
>>>项目。蓝色。b
“d”
>>>项目(‘a’)
有关更多选项,请参见。Python 3.4有一个(已修改为和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'
-->EnumWithAttrs.BLUE
-->EnumWithAttrs.BLUE.a
“c”
1披露:我是,和图书馆的作者 2
aenum
还支持Python 3的NamedConstants
和基于元类的NamedTuples
:
类状态(枚举):
READY=“READY”,“我准备好做任何需要的事情”
ERROR=“ERROR”,“这里出了点问题”
定义新(cls,*ARG,**kwds):
obj=对象。新的(cls)
对象值=参数[0]
返回obj
#忽略第一个参数,因为它已由_new设置__
定义初始化(self,uu:str,description:str=None):
自我描述
定义(自我):
回归自我价值
#这样可以确保描述是只读的
@财产
def说明(自我):
返回自我描述_
您可以按类型将其用作标准枚举或工厂:
打印(状态:就绪)
#准备好了吗
打印(状态.就绪.说明)
#我准备好做任何需要做的事
打印(状态(“就绪”)#这不会创建新对象
#准备好了吗
我认为另一种方法比其他方法更简单,但允许最大的灵活性:
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)
印刷品:
ready
<Status.READY: Status(name='ready', description='I am ready to do whatever is needed')>
I am ready to do whatever is needed
Status(name='ready', description='I am ready to do whatever is needed')
准备好了吗
我准备做任何需要的事
状态(name='ready',description='我已准备好做任何需要的事情')
您可以充分利用和。受其他一些答案的启发,我找到了一种方法,可以在枚举中尽可能“透明”地包含其他字段,从而克服了其他方法的一些缺点。如果没有其他字段,一切都是一样的 枚举就像元组一样是不可变的,枚举的值就像没有其他字段时一样,它的工作原理就像使用
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>
[4]中的Color.GREEN
出[4]:
在[5]中:Color.GREEN.value
Out[5]:1
[6]中:Color.GREEN.r
Out[6]:0
In[7]:Color.GREEN.g
Out[7]:255
[8]中:颜色.绿色.b
Out[8]:0
[9]中:Color.GREEN.r=8
回溯(最近一次呼叫最后一次):
文件“/home/phil/anaconda3/envs/dl/lib/python3.6/site packages/IPython/core/interactiveshell.py”,第3326行,运行代码
exec(代码对象、self.user\u全局、self.user\n)
文件“”,第1行,在
颜色。绿色。r=8
AttributeError:无法设置属性
In[10]:颜色(2)
出[10]:
在[11]中:颜色['BLUE']
出[11]:
从短语“根据本例调整简单枚举的想法”中根本不清楚您想做什么。是否可以使用?但话说回来,不,最好用一个类来代替它。@bmargiles或一些观察者。在这段PyCon谈话的视频记录中,Raymond Hettinger解释了命名元组为什么很棒,它们是如何工作的,以及它们的用例<代码>[11:35-26:00]。他演示的示例包括颜色的枚举类型。不允许我从其名称中选择项目,例如,我希望Items('a')
返回项目。绿色@off99555:此答案在添加enum
模块之前很久就发布了,这就是您现在真正想要使用的。@off99555:我已经更新了答案,以使用enum
,因为这是一个普遍可用的选项。请注意,Enum
不会直接让您将选项元组中的任意项映射到Enum值<代码>项('b')
或项('d')
仍然不起作用,在查找中只支持enum\u value\u
属性。您必须自己定义一个类方法来编码自定义查找规则,例如,@classmethod
,def lookup(cls,value):
,,用于cls中的条目。{entry.a,entry.b}中的值:
如果{entry.a,entry.b}:return entry
@andilab:听起来像是您在要求类似的东西mypy
目前仅支持stdlibEnum
。有人可以从mypy
获取Enum
支持,并将其翻译为aenum.Enum
,但我没有时间。为什么EnumWithAttrs.BLUE.a
返回“c”而不是“a”?我需要从tuple中获取第二个值。@AlexeiMarinichenko:在上面的示例代码中,a
是第一个属性,b
是第二个属性;因此,要访问BLUE
的第二个属性,您需要执行EnumWithAttrs.BLUE.b
。这比公认的答案更具描述性,更易于使用。它不允许我选择
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>