Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有属性的python枚举_Python_Enums - Fatal编程技术网

具有属性的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
目前仅支持stdlib
Enum
。有人可以从
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>