Можно ли использовать именованные аргументы с перечислениями Python?
пример:
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
Ref:https://docs.python.org/3/library/enum.html#planet
почему я хочу это сделать? Если в списке конструкторов есть несколько примитивных типов (int, bool), было бы неплохо использовать именованные аргументы.
4 ответов
хотя вы не можете использовать именованные аргументы так, как описываете перечисления, вы можете получить аналогичный эффект с 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
обратите внимание, что в соответствии с документы, " типы mix-in должны появиться перед Enum
сам в последовательности баз".
принятый ответ @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)
остерегайтесь маринования не будет работать без __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
если выход за пределы namedtuple
mix-in проверьте aenum
библиотека1. Кроме того, есть несколько дополнительных колоколов и свистков для 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
1 раскрытие: я автор Python stdlib Enum
, в enum34
backport и Дополнительные Перечисления (aenum
) библиотека.
для Python 3.6.1+печатать.NamedTuple может использоваться, что также позволяет устанавливать значения по умолчанию, что приводит к более красивому коду. Пример @shao.Ло тогда выглядит так:
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)
Это также поддерживает мариновать. Ввод.Любой может использоваться, если вы не хотите указывать тип.
кредит @monk-time, кто ответ здесь вдохновленный этим решением.