2014-11-01 8 views

Odpowiedz

25

Chociaż nie można używać nazwanymi argumentami sposób opisać teksty stałe, można uzyskać podobny efekt z namedtuple wstawek:

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. 

... co moim zdaniem jest czystsze, ponieważ don "Trzeba napisać metodę __init__.

przykład zastosowanie:

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

Należy zauważyć, że zgodnie z the docs „musi znajdować się mieszankę w rodzaju wcześniej Enum się w sekwencji zasad”.

+0

bardzo fajne. Nigdy nie zastanawiałem się nad rozwiązaniem problemu z mixinem. – kevinarpe

+2

Pomysłowy. Masz up-vote. :) –

+0

@ZeroPiraeus: Dodałem odpowiedź, ale nie dla nagrody - po prostu mając nadzieję na kilka głosów w górę (długa droga do zdobycia złotej odznaki [python-3.x];). –

9

Przyjęta odpowiedź przez @ zero-piraeus może zostać nieznacznie rozszerzona, aby umożliwić również domyślne argumenty. Jest to bardzo przydatne, gdy masz duże wyliczenie z większością wpisów o tej samej wartości dla elementu.

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) 

Uwaga: wytrawianie nie zadziała bez __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

To niezła modyfikacja oryginalnego pomysłu, dzięki! –

+1

Dobre przedłużenie! Masz up-vote. :) –

+0

@ zero-piraeus Dziękuję, proszę pana! –

2

Jeśli wykraczające poza namedtuple mix-in sprawdzeniu aenum bibliotekę (napisany przez tego samego faceta, który napisał stdlib Enum i enum34 backportu). Oprócz kilku dodatkowych dzwonków i gwizdków dla Enum obsługuje także NamedConstant i opartą na metaklinie NamedTuple.

Korzystanie aenum.Enum powyższy kod mógłby wyglądać następująco:

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 

i użytkowania:

--> 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 
Powiązane problemy