2014-11-01 17 views

risposta

25

Mentre non è possibile utilizzare argomenti con nome il modo di descrivere con le enumerazioni, è possibile ottenere un effetto simile con un namedtuple mixin:

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. 

... che a mio parere è più pulita, dal momento che don Non è necessario scrivere un metodo __init__.

uso Esempio:

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

Si noti che, come da the docs, "deve apparire mix-in tipi prima di Enum stesso nella sequenza delle basi".

+0

molto cool. Non ho mai pensato di risolvere il problema con un mixin. – kevinarpe

+2

Geniale. Avere un voto positivo :) –

+0

@ZeroPiraeus: ho aggiunto una risposta, ma non per la taglia - sperando solo in alcuni voti positivi (una lunga strada da percorrere per il mio distintivo d'oro [python-3.x]!;). –

9

La risposta accettata da @ zero-pireo può essere leggermente estesa per consentire anche gli argomenti predefiniti. Questo è molto utile quando si ha una grande enumerazione con la maggior parte delle voci che hanno lo stesso valore per un elemento.

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) 

Attenzione decapaggio non funziona senza la __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

Questo è un bel tocco sull'idea originale, grazie! –

+1

Buona estensione! Avere un voto positivo :) –

+0

@ zero-pireo Grazie signore! –

2

Se andare al di là del mix-in namedtuple check out biblioteca aenum (scritto dallo stesso tizio che ha scritto lo stdlib Enum e la enum34 backport). Oltre ad avere alcuni campanelli e fischietti aggiuntivi per Enum, supporta anche NamedConstant e uno basato su metaclass.

Utilizzando aenum.Enum il codice di cui sopra potrebbe essere simile:

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 

e in uso:

--> 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