2014-11-01 94 views

回答

25

虽然你不能使用命名参数你枚举描述的方式,你可以得到一个namedtuple混入类似的效果:

from collections import namedtuple 
from enum import Enum 

Body = namedtuple("Body", ["mass", "radius"]) 

class Planet(Body, Enum): 

    MERCURY = Body(mass=3.303e+23, radius=2.4397e6) 
    VENUS = Body(mass=4.869e+24, radius=6.0518e6) 
    EARTH = Body(mass=5.976e+24, radius=3.3972e6) 
    # ... etc. 

...这在我看来是清洁的,因为你不不必写一个__init__方法。

使用例:

>>> Planet.MERCURY 
<Planet.MERCURY: Body(mass=3.303e+23, radius=2439700.0)> 
>>> Planet.EARTH.mass 
5.976e+24 
>>> Planet.VENUS.radius 
6051800.0 

需要注意的是,按照the docs,“混合式类型必须Enum之前本身的碱基序列中出现”。

+0

非常酷。我从来没有考虑过用mixin解决问题。 – kevinarpe 2014-11-05 02:54:51

+2

巧妙。有一个投票。 :) – 2016-03-10 00:49:40

+0

@ZeroPiraeus:我添加了一个答案,但不是为了赏金 - 只是希望得到一些赞成票(我的[python-3.x]金徽章还有很长的路要走!)。 – 2017-03-17 07:13:12

9

@ zero-piraeus接受的答案可以稍微扩展以允许默认参数。当你有一个大的enum,大多数条目具有相同的元素值时,这非常方便。

class Body(namedtuple('Body', "mass radius moons")): 
    def __new__(cls, mass, radius, moons=0): 
     return super().__new__(cls, mass, radius, moons) 
    def __getnewargs__(self): 
     return (self.mass, self.radius, self.moons) 

class Planet(Body, Enum): 

    MERCURY = Body(mass=3.303e+23, radius=2.4397e6) 
    VENUS = Body(mass=4.869e+24, radius=6.0518e6) 
    EARTH = Body(5.976e+24, 3.3972e6, moons=1) 

当心酸洗没有__getnewargs__将无法​​正常工作。

class Foo: 
    def __init__(self): 
     self.planet = Planet.EARTH # pickle error in deepcopy 

from copy import deepcopy 

f1 = Foo() 
f2 = deepcopy(f1) # pickle error here 
+0

这是对原始想法的一个很好的调整,谢谢! – 2017-03-16 03:58:11

+1

好的延伸!有一个投票。 :) – 2017-03-17 06:34:25

+0

@ zero-piraeus谢谢先生! – 2017-03-23 15:01:45

2

如果超越namedtuple混合,在检查出的aenum库(由写的STDLIB Enumenum34反向移植相同的家伙写的)。除了Enum还有一些额外的铃声和哨声,它还支持NamedConstant和基于元类的NamedTuple

使用aenum.Enum上面的代码可能看起来像:

from aenum import Enum, enum, _reduce_ex_by_name 

class Planet(Enum, init='mass radius'): 
    MERCURY = enum(mass=3.303e+23, radius=2.4397e6) 
    VENUS = enum(mass=4.869e+24, radius=6.0518e6) 
    EARTH = enum(mass=5.976e+24, radius=3.3972e6) 
    # replace __reduce_ex__ so pickling works 
    __reduce_ex__ = _reduce_ex_by_name 

,并在使用中:

--> for p in Planet: 
...  print(repr(p)) 
<Planet.MERCURY: enum(radius=2439700.0, mass=3.3030000000000001e+23)> 
<Planet.EARTH: enum(radius=3397200.0, mass=5.9760000000000004e+24)> 
<Planet.VENUS: enum(radius=6051800.0, mass=4.8690000000000001e+24)> 

--> print(Planet.VENUS.mass) 
4.869e+24 
相关问题