带有属性的python枚举

bma*_*ies 10 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')
Run Code Online (Sandbox Code Playgroud)

有没有办法让简单枚举的想法适应这种情况?(参见这个问题)理想情况下,就像在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 */
}
Run Code Online (Sandbox Code Playgroud)

小智 24

对于 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_
Run Code Online (Sandbox Code Playgroud)

您可以按类型将其用作标准枚举或工厂:

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
Run Code Online (Sandbox Code Playgroud)

  • 最好能解释一下为什么在这种情况下需要“__new__”,因为其他类可能不需要它。 (13认同)

Eth*_*man 13

Python 3.4有一个新的Enum数据类型(已经向后移植enum34增强为aenum1).两者enum34aenum2都轻松支持您的用例:

[ aenumpy2/3]

import aenum
class EnumWithAttrs(aenum.AutoNumberEnum):
    _init_ = 'a b'
    GREEN = 'a', 'b'
    BLUE = 'c', 'd'
Run Code Online (Sandbox Code Playgroud)

[ enum34py2/3或stdlib enum3.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'
Run Code Online (Sandbox Code Playgroud)

在使用中:

--> EnumWithAttrs.BLUE
<EnumWithAttrs.BLUE: 1>

--> EnumWithAttrs.BLUE.a
'c'
Run Code Online (Sandbox Code Playgroud)

1披露:我是Python stdlibEnum,enum34backportAdvanced Enumeration(aenum) 库的作者.

2 aenum还支持NamedConstants基于元类和NamedTuples.

  • 在你的第二个例子中`__new__`做了什么?为什么需要它? (3认同)
  • @Gavin:它创建枚举成员,并且需要它来使“.value”属性为“1”、“2”等,并将成员属性“a”和“b”分配给传入的值。 (3认同)
  • 这仍然是推荐使用的方法吗?或者此后有什么相关的变化吗? (3认同)
  • 使用“enum.StrEnum”可以实现此方法吗?如何? (2认同)

lea*_*eal 11

这是我认为比其他方法更简单的另一种方法,但具有最大的灵活性:

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
Run Code Online (Sandbox Code Playgroud)

按预期工作:

print(Status.READY)
print(repr(Status.READY))
print(Status.READY.description)
print(Status.READY.value)
Run Code Online (Sandbox Code Playgroud)

印刷:

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')
Run Code Online (Sandbox Code Playgroud)

您可以充分利用namedtuple Enum

  • @off99555 你可以用 `Status["READY"]` 来做到这一点 (4认同)
  • 它不允许我按名称选择状态,例如“Status('ready')”。当您希望用户从名称列表中选择状态时需要它,并且他们将键入一个名称,例如“就绪” (3认同)
  • 这比接受的答案更具描述性且易于使用。 (2认同)
  • 我同意这比其他解决方案干净得多。对于任何想要属性上的类型提示的人来说,它还可以使用“typing.NamedTuple”而不是“collections.namedtuple”。 (2认同)

Edu*_*cio 10

经过大量搜索后,我找到了这两个工作示例!

这就是我的朋友们!

代码...

from enum import Enum


class StatusInt(int, Enum):
    READY = (0, "Ready to go!")
    ERROR = (1, "Something wrong!")

    def __new__(cls, value, description):
        obj = int.__new__(cls, value)
        obj._value_ = value
        obj._description_ = description
        return obj

    @property
    def description(self):
        return self._description_


class StatusObj(Enum):
    READY = (0, "Ready to go!")
    ERROR = (1, "Something wrong!")

    def __init__(self, value, description):
        self._value_ = value
        self._description_ = description

    @property
    def description(self):
        return self._description_


print(str(StatusInt.READY == StatusInt.ERROR))
print(str(StatusInt.READY.value))
print(StatusInt.READY.description)

print(str(StatusObj.READY == StatusObj.ERROR))
print(str(StatusObj.READY.value))
print(StatusObj.READY.description)
Run Code Online (Sandbox Code Playgroud)

输出...

False
0
Ready to go!
False
0
Ready to go!
Run Code Online (Sandbox Code Playgroud)

[参考文献: https://docs.python.org/3/library/enum.html#when-to-use-new-vs-init,https://docs.python.org/3/library /enum.html#planet ]

  • 您的第一个示例似乎与 Ovidiu 的答案相同,但第二个示例要好得多! (2认同)
  • 干净直观 (2认同)

Mar*_*ers 5

使用namedtuple

from collections import namedtuple

Item = namedtuple('abitem', ['a', 'b'])

class Items:
    GREEN = Item('a', 'b')
    BLUE = Item('c', 'd')
Run Code Online (Sandbox Code Playgroud)

  • @off99555:我已经更新了答案以使用“enum”,因为这是一个普遍可用的选项。请注意,“Enum”不会直接让您将选项元组中的任意项映射到枚举值;`Items('b')` 或 `Items('d')` 仍然不起作用,查找中仅支持枚举 `_value_` 属性。您必须自己定义一个类方法来编码自定义查找规则,例如 `@classmethod`、`def Lookup(cls, value):`、`for Entry in cls.__members__.values():` `if value in {entry.a,entry.b}:返回条目`。 (3认同)