如何在没有.value(并且不使用位置参数元组)的情况下访问枚举成员属性



使用枚举时,我更喜欢不必在任何地方使用.value来访问成员属性。

所以,我这样创建它们:

from dataclasses import dataclass
from enum import Enum
@dataclass
class Item:
foo: int
bar: int
class Collection(Item, Enum):
A = 1, 2
# Now I can use Collection.A.foo

但是,我的Item类有几个参数,为了可读性(和IDE支持(,我更喜欢直接在Enum上实例化Items。类似这样的东西(这不起作用,因为Enum想要一个位置参数的元组,而不是Item的实例(:

class Collection(Item, Enum):
A = Item(1, 2)

同时仍然享受Collection.A.foo属性访问(而不是Collection.A.value.foo,如果我有Collection(Enum),我会得到它(。

或者至少能够指定用于实例化Item:的关键字

class Collection(Item, Enum):
A = dict(1, 2)

有没有办法实现这两种解决方案?也许是Item.__new__的黑客攻击?

编辑:我尽量不在枚举中使用元组。(在撰写本文时,两个答案仍然使用元组来定义Items的参数。(

从Python的Enum文档中-您可以尝试重写枚举类的__init____new__,并获得所需的输出。

请注意文件中关于何时覆盖哪一个的以下部分:

何时使用__new__((与__init__((

每当您想要自定义枚举成员的实际值时,都必须使用new((。任何其他修改都可以在__new__((或__init__((中进行,首选__init__(。

例如,如果您想将几个项传递给构造函数,但只希望其中一个为值(请参阅__new__重写(

看看这两个例子:

覆盖__new__:

>>> class Coordinate(bytes, Enum):
...     """
...     Coordinate with binary codes that can be indexed by the int code.
...     """
...     def __new__(cls, value, label, unit):
...         obj = bytes.__new__(cls, [value])
...         obj._value_ = value
...         obj.label = label
...         obj.unit = unit
...         return obj
...     PX = (0, 'P.X', 'km')
...     PY = (1, 'P.Y', 'km')
...     VX = (2, 'V.X', 'km/s')
...     VY = (3, 'V.Y', 'km/s')
...
>>> print(Coordinate['PY'])
Coordinate.PY
>>> print(Coordinate(3))
Coordinate.VY

覆盖__init__:

>>> class Planet(Enum):
...     MERCURY = (3.303e+23, 2.4397e6)
...     VENUS   = (4.869e+24, 6.0518e6)
...     EARTH   = (5.976e+24, 6.37814e6)
...     MARS    = (6.421e+23, 3.3972e6)
...     JUPITER = (1.9e+27,   7.1492e7)
...     SATURN  = (5.688e+26, 6.0268e7)
...     URANUS  = (8.686e+25, 2.5559e7)
...     NEPTUNE = (1.024e+26, 2.4746e7)
...     def __init__(self, mass, radius):
...         self.mass = mass       # in kilograms
...         self.radius = radius   # in meters
...     @property
...     def surface_gravity(self):
...         # universal gravitational constant  (m3 kg-1 s-2)
...         G = 6.67300E-11
...         return G * self.mass / (self.radius * self.radius)
...
>>> Planet.EARTH.value
(5.976e+24, 6378140.0)
>>> Planet.EARTH.surface_gravity
9.802652743337129

通过使用其中一种方法,您可以创建自己的、更可定制的Enum类。即使您还需要Item类作为一个独立于枚举的类,您也可以覆盖这两个函数中的一个并使其工作(尽管如果Item只是为了枚举而创建的,您可能应该在内部合并它(。

我认为您可以尝试__init__方法中的传统设置方式,该方法不需要额外的类。详细的解释可以在这里找到。

from enum import Enum

class Collection(Enum):
A = 1, 2
B = 3, 4
C = 5, 6
D = 7, 8
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar

试运行

for item in Collection:
print(item.foo, item.bar, sep=', ')

结果

1, 2
3, 4
5, 6
7, 8

最新更新