2014-11-01 10 views

Antwort

25

Sie können zwar keine benannten Argumente, die Art und Weise verwenden Sie mit Aufzählungen beschreiben, können Sie einen ähnlichen Effekt mit einem namedtuple mixin erhalten:

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. 

..., die meiner Meinung nach sauberer, da Sie don Ich muss eine __init__ Methode schreiben.

Beispiel Verwendung:

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

sei bemerkt, dass gemäß the docs "mix-Typen vor Enum sich in der Sequenz der Basen erscheinen muß".

+0

Sehr cool. Ich habe nie darüber nachgedacht, das Problem mit einem Mixin zu lösen. – kevinarpe

+2

Genial. Habe eine Abstimmung. :) –

+0

@ZeroPiraeus: Ich habe eine Antwort hinzugefügt, aber nicht für die Bounty - nur auf einige Up-Stimmen gehofft (langer Weg bis zu meinem [Python-3.x] Gold-Abzeichen!;). –

9

Die akzeptierte Antwort von @ zero-piraeus kann leicht erweitert werden, um auch Standardargumente zuzulassen. Dies ist sehr praktisch, wenn Sie eine große Aufzählung mit den meisten Einträgen haben, die denselben Wert für ein Element haben.

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) 

Vorsicht Beizen wird ohne die __getnewargs__ nicht funktionieren.

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

Das ist eine nette Änderung an der ursprünglichen Idee, danke! –

+1

Gute Erweiterung! Habe eine Abstimmung. :) –

+0

@ Zero-Piräus Danke, mein Herr! –

2

über die namedtuple Mix-in Check-out die aenum Bibliothek (geschrieben von dem gleichen Kerl, der den stdlib Enum und den enum34 Backport geschrieben) Wenn gehen. Abgesehen von ein paar zusätzlichen Schnickschnack für Enum unterstützt es auch NamedConstant und eine Metaklasse-basierte NamedTuple.

Mit aenum.Enum der obigen Code könnte wie folgt aussehen:

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 

und im Einsatz:

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