命名参数可以与Python枚举一起使用吗?

kev*_*rpe 19 python enums named-parameters python-3.x

例:

class Planet(Enum):

    MERCURY = (mass: 3.303e+23, radius: 2.4397e6)

    def __init__(self, mass, radius):
        self.mass = mass       # in kilograms
        self.radius = radius   # in meters
Run Code Online (Sandbox Code Playgroud)

参考:https://docs.python.org/3/library/enum.html#planet

我为什么要这样做?如果构造函数列表中有一些原始类型(int,bool),那么使用命名参数会很好.

Zer*_*eus 25

虽然您不能像使用枚举一样使用命名参数,但您可以使用namedtuplemixin 获得类似的效果:

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

...在我看来更干净,因为你不必写一个__init__方法.

使用示例:

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

请注意,根据文档,"混合类型必须Enum在基础序列之前出现".

  • 巧妙.进行投票.:) (2认同)

小智 12

对于Python 3.6.1+,可以使用typing.NamedTuple,它还允许设置默认值,从而生成更漂亮的代码。@shao.lo 的示例如下所示:

from enum import Enum
from typing import NamedTuple


class Body(NamedTuple):
    mass: float
    radius: float
    moons: int=0


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

这也支持酸洗。如果您不想指定类型,可以使用typing.Any。

感谢@monk-time,他的回答启发这个解决方案。


sha*_*.lo 10

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

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

如果没有,那么小心酸洗是行不通的__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
Run Code Online (Sandbox Code Playgroud)


Eth*_*man 6

如果超出namedtuple混合范围,请查看aenum1。除了有一些额外的花哨之外,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
Run Code Online (Sandbox Code Playgroud)

并在使用中:

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

1声明:我是Python stdlibEnumenum34backportAdvanced Enumeration ( aenum)库的作者 。