Hvordan kan jeg representere en 'Enum' i Python?

stemmer
1k

Jeg er først og fremst en C # utvikler, men jeg jobber for tiden med et prosjekt i Python.

Hvordan kan jeg representerer tilsvarende en Enum i Python?

Publisert på 31/08/2008 klokken 15:55
kilden bruker
På andre språk...                            


43 svar

stemmer
2k

Enums har blitt lagt til Python 3.4 som er beskrevet i PEP 435 . Det har også blitt backported til 3,3, 3,2, 3,1, 2,7, 2,6, 2,5, og 2,4 på PyPI.

For mer avanserte enum teknikker prøve aenum bibliotek (2.7, 3.3 eller nøyere, samme forfatter som enum34. Kode er ikke forenelig mellom Py2 og pY3, f.eks du trenger __order__i python 2 ).

  • Å bruke enum34, gjør$ pip install enum34
  • Å bruke aenum, gjør$ pip install aenum

Installere enum(ingen tall) vil installere en helt annen og inkompatibel versjon.


from enum import Enum     # for enum34, or the stdlib version
# from aenum import Enum  # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')

Animal.ant  # returns <Animal.ant: 1>
Animal['ant']  # returns <Animal.ant: 1> (string lookup)
Animal.ant.name  # returns 'ant' (inverse lookup)

eller ekvivalent:

class Animal(Enum):
    ant = 1
    bee = 2
    cat = 3
    dog = 4

I tidligere versjoner, en måte å oppnå enums er:

def enum(**enums):
    return type('Enum', (), enums)

som anvendes som så:

>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'

Du kan også enkelt støtte for automatisk telling med noe sånt som dette:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)

og brukes slik:

>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1

Støtte for å konvertere verdiene tilbake til navn kan legges til på denne måten:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    reverse = dict((value, key) for key, value in enums.iteritems())
    enums['reverse_mapping'] = reverse
    return type('Enum', (), enums)

Dette overskriver noe med det navnet, men det er nyttig for å gjengi dine enums i produksjonen. Det vil kaste KeyError hvis det motsatte kartleggingen ikke eksisterer. Med det første eksempelet:

>>> Numbers.reverse_mapping['three']
'THREE'
Svarte 08/11/2009 kl. 03:15
kilden bruker

stemmer
723

Før PEP 435, hadde Python ikke har en tilsvarende, men du kan implementere din egen.

Meg selv, jeg liker å holde det enkelt (jeg har sett noen forferdelig komplekse eksempler på nettet), noe som dette ...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

I Python 3.4 ( PEP 435 ), kan du gjøre Enum base klassen. Dette får du litt ekstra funksjonalitet, som er beskrevet i PEP. For eksempel, enum medlemmer er forskjellig fra heltall, og de er sammensatt av en nameog en value.

class Animal(Enum):
    DOG = 1
    CAT = 2

print(Animal.DOG)
# <Animal.DOG: 1>

print(Animal.DOG.value)
# 1

print(Animal.DOG.name)
# "DOG"

Hvis du ikke ønsker å skrive verdiene, kan du bruke følgende snarvei:

class Animal(Enum):
    DOG, CAT = range(2)

Enumimplementeringer kan konverteres til lister og er iterable . Rekkefølgen av dets medlemmer er erklæringen orden og har ingenting å gjøre med deres verdier. For eksempel:

class Animal(Enum):
    DOG = 1
    CAT = 2
    COW = 0

list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]

[animal.value for animal in Animal]
# [1, 2, 0]

Animal.CAT in Animal
# True
Svarte 31/08/2008 kl. 16:06
kilden bruker

stemmer
298

Her er en implementering:

class Enum(set):
    def __getattr__(self, name):
        if name in self:
            return name
        raise AttributeError

Her er dens bruk:

Animals = Enum(["DOG", "CAT", "HORSE"])

print(Animals.DOG)
Svarte 02/02/2010 kl. 07:21
kilden bruker

stemmer
184

Hvis du trenger de numeriske verdiene, her er den raskeste måten:

dog, cat, rabbit = range(3)

I Python 3.x kan du også legge til et hovedrollen plassholder på slutten, som vil suge opp alle de gjenværende verdiene av området i tilfelle du ikke har noe imot å kaste bort minne og kan ikke telle:

dog, cat, rabbit, horse, *_ = range(100)
Svarte 31/08/2008 kl. 20:31
kilden bruker

stemmer
119

Den beste løsningen for deg vil avhenge av hva du ønsker fra din falske enum .

Enkelt enum:

Hvis du trenger enumsom bare en liste over navn som identifiserer ulike elementer , løsningen av Mark Harrison (over) er stor:

Pen, Pencil, Eraser = range(0, 3)

Ved hjelp av en rangekan du også sette noen startverdi :

Pen, Pencil, Eraser = range(9, 12)

I tillegg til ovennevnte, hvis du også kreve at elementene tilhører en beholder av noe slag, deretter legge dem i en klasse:

class Stationery:
    Pen, Pencil, Eraser = range(0, 3)

For å bruke enum element, ville du nå må bruke container navn og elementet navn:

stype = Stationery.Pen

Complex enum:

For lange lister med enum eller mer kompliserte bruk av enum, vil disse løsningene ikke nok. Du kan se til oppskriften av Will Ware for Simulerer Oppramsinger i Python publisert i Python Cookbook . En elektronisk versjon av som er tilgjengelig her .

Mer informasjon:

PEP 354: Oppramsinger i Python har interessante detaljer om et forslag til enum i Python og hvorfor den ble avvist.

Svarte 07/10/2009 kl. 02:47
kilden bruker

stemmer
76

Den typesafe enum mønster som ble brukt i pre-Java JDK 5 har en rekke fordeler. Mye som i Alexandru svar, oppretter du en klasse og klassenivå felt er enum verdier; imidlertid enum verdier er forekomster av klassen i stedet for små heltall. Dette har den fordelen at enum verdier ikke utilsiktet sammenligne lik små heltall, kan du kontrollere hvordan de er skrevet ut, legger vilkårlige metoder hvis det er nyttig og gjøre påstander bruke isinstance:

class Animal:
   def __init__(self, name):
       self.name = name

   def __str__(self):
       return self.name

   def __repr__(self):
       return "<Animal: %s>" % self

Animal.DOG = Animal("dog")
Animal.CAT = Animal("cat")

>>> x = Animal.DOG
>>> x
<Animal: dog>
>>> x == 1
False

En fersk tråd på python-dev påpekt er det et par av enum bibliotekene i naturen, inkludert:

Svarte 01/09/2008 kl. 16:05
kilden bruker

stemmer
56

En Nummer klasse kan være en ett-liner.

class Enum(tuple): __getattr__ = tuple.index

Hvordan bruke det (forover og bakover oppslag, nøkler, verdier, elementer, etc.)

>>> State = Enum(['Unclaimed', 'Claimed'])
>>> State.Claimed
1
>>> State[1]
'Claimed'
>>> State
('Unclaimed', 'Claimed')
>>> range(len(State))
[0, 1]
>>> [(k, State[k]) for k in range(len(State))]
[(0, 'Unclaimed'), (1, 'Claimed')]
>>> [(k, getattr(State, k)) for k in State]
[('Unclaimed', 0), ('Claimed', 1)]
Svarte 08/02/2012 kl. 20:59
kilden bruker

stemmer
45

Så, jeg er enig. La oss ikke håndheve typen sikkerhet i Python, men jeg ønsker å beskytte meg mot dumme feil. Så hva tror vi om dette?

class Animal(object):
    values = ['Horse','Dog','Cat']

    class __metaclass__(type):
        def __getattr__(self, name):
            return self.values.index(name)

Det holder meg fra verdi kollisjon i å definere mine enums.

>>> Animal.Cat
2

Det er en annen praktisk fordel: veldig fort reverse oppslag:

def name_of(self, i):
    return self.values[i]
Svarte 03/11/2010 kl. 23:02
kilden bruker

stemmer
44

Python har ikke en innebygd tilsvarer enum, og andre svar har ideer for å implementere din egen (du kan også være interessert i over toppen versjonen i Python kokebok).

Men i situasjoner der en enumville bli kalt for i C, jeg pleier å ende opp med bare å bruke enkle strenger : på grunn av måten objekter / attributter er implementert, (C) Python er optimalisert for å fungere veldig raskt med korte strenger uansett, så det wouldn 't virkelig være noen ytelse fordel å bruke heltall. For å beskytte mot skrivefeil / ugyldige verdier kan du sette inn kontroller i utvalgte steder.

ANIMALS = ['cat', 'dog', 'python']

def take_for_a_walk(animal):
    assert animal in ANIMALS
    ...

(En ulempe sammenlignet med en klasse er at du mister fordelen av autofullfør)

Svarte 31/08/2008 kl. 18:10
kilden bruker

stemmer
31

På 2013-05-10, Guido enige om å godta PEP 435 i Python 3.4 standard bibliotek. Dette betyr at Python har endelig innebygd støtte for enumerations!

Det er en Backport tilgjengelig for Python 3,3, 3,2, 3,1, 2,7, 2,6, 2,5, og 2,4. Det er på PyPI som enum34 .

Erklæring:

>>> from enum import Enum
>>> class Color(Enum):
...     red = 1
...     green = 2
...     blue = 3

Representasjon:

>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>

iterasjon:

>>> for color in Color:
...   print(color)
...
Color.red
Color.green
Color.blue

Programmatisk tilgang:

>>> Color(1)
Color.red
>>> Color['blue']
Color.blue

For mer informasjon, se forslaget . Offisiell dokumentasjon vil trolig følge snart.

Svarte 10/05/2013 kl. 16:09
kilden bruker

stemmer
29

Jeg foretrekker å definere enums i Python som så:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

Det er mer bug-bevis enn å bruke heltall siden du ikke trenger å bekymre deg for at heltallene er unike (for eksempel hvis du sa Dog = 1 og Cat = en du vil bli skrudd).

Det er mer bug-bevis enn å bruke strenger siden du ikke trenger å bekymre deg for skrivefeil (f.eks x == "fo" mislykkes uten, men x == Animal.Catt er en runtime unntak).

Svarte 29/11/2010 kl. 02:05
kilden bruker

stemmer
29
def M_add_class_attribs(attribs):
    def foo(name, bases, dict_):
        for v, k in attribs:
            dict_[k] = v
        return type(name, bases, dict_)
    return foo

def enum(*names):
    class Foo(object):
        __metaclass__ = M_add_class_attribs(enumerate(names))
        def __setattr__(self, name, value):  # this makes it read-only
            raise NotImplementedError
    return Foo()

Bruk det slik:

Animal = enum('DOG', 'CAT')
Animal.DOG # returns 0
Animal.CAT # returns 1
Animal.DOG = 2 # raises NotImplementedError

Hvis du bare vil ha unike symboler og ikke bryr seg om verdier, erstatte denne linjen:

__metaclass__ = M_add_class_attribs(enumerate(names))

med dette:

__metaclass__ = M_add_class_attribs((object(), name) for name in names)
Svarte 20/09/2008 kl. 11:49
kilden bruker

stemmer
21

En annen, svært enkel, gjennomføring av en enum i Python, ved hjelp av namedtuple:

from collections import namedtuple

def enum(*keys):
    return namedtuple('Enum', keys)(*keys)

MyEnum = enum('FOO', 'BAR', 'BAZ')

eller alternativt

# With sequential number values
def enum(*keys):
    return namedtuple('Enum', keys)(*range(len(keys)))

# From a dict / keyword args
def enum(**kwargs):
    return namedtuple('Enum', kwargs.keys())(*kwargs.values())

I likhet med metoden ovenfor som underklasser set, gjør dette:

'FOO' in MyEnum
other = MyEnum.FOO
assert other == MyEnum.FOO

Men har mer fleksibilitet som det kan ha forskjellige nøkler og verdier. Dette tillater

MyEnum.FOO < MyEnum.BAR

å fungere som forventes hvis du bruker den versjonen som fyller i sekvensielle tallverdier.

Svarte 07/08/2011 kl. 05:51
kilden bruker

stemmer
19

Hmmm ... Jeg antar at det nærmeste du kommer en enum ville være en ordbok, definert enten som dette:

months = {
    'January': 1,
    'February': 2,
    ...
}

eller

months = dict(
    January=1,
    February=2,
    ...
)

Deretter kan du bruke symbolsk navn for konstanter som dette:

mymonth = months['January']

Det finnes andre alternativer, som en liste med tupler, eller en tuppel av tupler, men ordboken er den eneste som gir deg en "symbolsk" (konstant streng) måte å få tilgang til verdien.

Edit: Jeg liker Alexandru svar også!

Svarte 31/08/2008 kl. 16:09
kilden bruker

stemmer
17

Det jeg bruker:

class Enum(object):
    def __init__(self, names, separator=None):
        self.names = names.split(separator)
        for value, name in enumerate(self.names):
            setattr(self, name.upper(), value)
    def tuples(self):
        return tuple(enumerate(self.names))

Hvordan å bruke:

>>> state = Enum('draft published retracted')
>>> state.DRAFT
0
>>> state.RETRACTED
2
>>> state.FOO
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
AttributeError: 'Enum' object has no attribute 'FOO'
>>> state.tuples()
((0, 'draft'), (1, 'published'), (2, 'retracted'))

Så dette gir deg heltall konstanter som state.PUBLISHED og de to tupler å bruke som valg i Django modeller.

Svarte 02/02/2009 kl. 23:39
kilden bruker

stemmer
15

Fra Python 3.4 vil det være offisiell støtte for enums. Du kan finne dokumentasjon og eksempler her på Python 3.4 dokumentasjonssiden .

Enumerations er opprettet ved hjelp av klassen syntaks, noe som gjør dem enkle å lese og skrive. En alternativ dannelsesmåten er beskrevet i Funksjonell API. For å definere en oppregning, underklasse Enum som følger:

from enum import Enum
class Color(Enum):
     red = 1
     green = 2
     blue = 3
Svarte 11/12/2013 kl. 13:49
kilden bruker

stemmer
15

davidg anbefaler å bruke dicts. Jeg vil gå et skritt videre og bruke sett:

months = set('January', 'February', ..., 'December')

Nå kan du teste om en verdi samsvarer med ett av verdiene i settet slik:

if m in months:

som DF, selv om jeg vanligvis bare bruke string konstanter i stedet for enums.

Svarte 02/09/2008 kl. 03:20
kilden bruker

stemmer
14

Dette er den beste jeg har sett: "First Class enums i Python"

http://code.activestate.com/recipes/413486/

Det gir deg en klasse, og klassen inneholder alle enums. De enums kan sammenlignes med hverandre, men ikke har noen særlig verdi; du kan ikke bruke dem som et heltall. (Jeg imot dette i begynnelsen, fordi jeg er vant til C enums, som er heltall. Men hvis du ikke kan bruke den som et heltall, kan du ikke bruke den som et heltall ved en feil så samlet tror jeg det er en seier .) Hver enum er en unik verdi. Du kan skrive ut enums, kan du iterere over dem, du kan teste at en enum verdien er "i" enum. Det er ganske komplett og glatt.

Edit (CFI): Den ovennevnte kobling er ikke Python 3-kompatibel. Her er min port av enum.py til Python 3:

def cmp(a,b):
   if a < b: return -1
   if b < a: return 1
   return 0


def Enum(*names):
   ##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!

   class EnumClass(object):
      __slots__ = names
      def __iter__(self):        return iter(constants)
      def __len__(self):         return len(constants)
      def __getitem__(self, i):  return constants[i]
      def __repr__(self):        return 'Enum' + str(names)
      def __str__(self):         return 'enum ' + str(constants)

   class EnumValue(object):
      __slots__ = ('__value')
      def __init__(self, value): self.__value = value
      Value = property(lambda self: self.__value)
      EnumType = property(lambda self: EnumType)
      def __hash__(self):        return hash(self.__value)
      def __cmp__(self, other):
         # C fans might want to remove the following assertion
         # to make all enums comparable by ordinal value {;))
         assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
         return cmp(self.__value, other.__value)
      def __lt__(self, other):   return self.__cmp__(other) < 0
      def __eq__(self, other):   return self.__cmp__(other) == 0
      def __invert__(self):      return constants[maximum - self.__value]
      def __nonzero__(self):     return bool(self.__value)
      def __repr__(self):        return str(names[self.__value])

   maximum = len(names) - 1
   constants = [None] * len(names)
   for i, each in enumerate(names):
      val = EnumValue(i)
      setattr(EnumClass, each, val)
      constants[i] = val
   constants = tuple(constants)
   EnumType = EnumClass()
   return EnumType


if __name__ == '__main__':
   print( '\n*** Enum Demo ***')
   print( '--- Days of week ---')
   Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
   print( Days)
   print( Days.Mo)
   print( Days.Fr)
   print( Days.Mo < Days.Fr)
   print( list(Days))
   for each in Days:
      print( 'Day:', each)
   print( '--- Yes/No ---')
   Confirmation = Enum('No', 'Yes')
   answer = Confirmation.No
   print( 'Your answer is not', ~answer)
Svarte 18/11/2009 kl. 02:51
kilden bruker

stemmer
11

Hold det enkelt:

class Enum(object): 
    def __init__(self, tupleList):
            self.tupleList = tupleList

    def __getattr__(self, name):
            return self.tupleList.index(name)

Deretter:

DIRECTION = Enum(('UP', 'DOWN', 'LEFT', 'RIGHT'))
DIRECTION.DOWN
1
Svarte 28/03/2014 kl. 21:44
kilden bruker

stemmer
11

Jeg har hatt anledning til å trenge en Enum klasse, med det formål å dekode et binært filformat. Funksjonene jeg skjedd å ønske er kortfattet enum definisjon, muligheten til fritt å skape forekomster av enum ved enten heltallsverdi eller streng, og en nyttig representation. Her er hva jeg endte opp med:

>>> class Enum(int):
...     def __new__(cls, value):
...         if isinstance(value, str):
...             return getattr(cls, value)
...         elif isinstance(value, int):
...             return cls.__index[value]
...     def __str__(self): return self.__name
...     def __repr__(self): return "%s.%s" % (type(self).__name__, self.__name)
...     class __metaclass__(type):
...         def __new__(mcls, name, bases, attrs):
...             attrs['__slots__'] = ['_Enum__name']
...             cls = type.__new__(mcls, name, bases, attrs)
...             cls._Enum__index = _index = {}
...             for base in reversed(bases):
...                 if hasattr(base, '_Enum__index'):
...                     _index.update(base._Enum__index)
...             # create all of the instances of the new class
...             for attr in attrs.keys():
...                 value = attrs[attr]
...                 if isinstance(value, int):
...                     evalue = int.__new__(cls, value)
...                     evalue._Enum__name = attr
...                     _index[value] = evalue
...                     setattr(cls, attr, evalue)
...             return cls
... 

En lunefull eksempel på bruk av det:

>>> class Citrus(Enum):
...     Lemon = 1
...     Lime = 2
... 
>>> Citrus.Lemon
Citrus.Lemon
>>> 
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __new__
KeyError: 5
>>> class Fruit(Citrus):
...     Apple = 3
...     Banana = 4
... 
>>> Fruit.Apple
Fruit.Apple
>>> Fruit.Lemon
Citrus.Lemon
>>> Fruit(1)
Citrus.Lemon
>>> Fruit(3)
Fruit.Apple
>>> "%d %s %r" % ((Fruit.Apple,)*3)
'3 Apple Fruit.Apple'
>>> Fruit(1) is Citrus.Lemon
True

Nøkkelegenskaper:

  • str(), int()Og repr()alle produserer den mest anvendelige utgangs mulig, henholdsvis navnet på enumartion, dens heltall, og en Python uttrykk som evalueres tilbake til nummereringen.
  • Oppregnet verdier som returneres av konstruktøren er begrenset strengt til de forhåndsdefinerte verdier, ingen utilsiktede enum verdier.
  • Oppregnet verdier er enkelts; de kan være strengt sammenlignet medis
Svarte 22/12/2011 kl. 02:16
kilden bruker

stemmer
9

Jeg liker Alec Thomas' løsning (http://stackoverflow.com/a/1695250):

def enum(**enums):
    '''simple constant "enums"'''
    return type('Enum', (object,), enums)

Det er elegant og rent utseende, men det er bare en funksjon som skaper en klasse med de angitte attributter.

Med litt modifisering til funksjonen, kan vi få det til å handle litt mer 'enumy':

MERK: Jeg opprettet følgende eksempler ved å prøve å gjenskape problemet for pygtk nye stil 'enums' (som Gtk.MessageType.WARNING)

def enum_base(t, **enums):
    '''enums with a base class'''
    T = type('Enum', (t,), {})
    for key,val in enums.items():
        setattr(T, key, T(val))

    return T

Dette skaper en enum basert av en bestemt type. I tillegg til å gi attributt tilgang som forrige funksjon, oppfører det som du ville forvente en Enum til med hensyn til typer. Det arver også base klassen.

For eksempel, heltallige enums:

>>> Numbers = enum_base(int, ONE=1, TWO=2, THREE=3)
>>> Numbers.ONE
1
>>> x = Numbers.TWO
>>> 10 + x
12
>>> type(Numbers)
<type 'type'>
>>> type(Numbers.ONE)
<class 'Enum'>
>>> isinstance(x, Numbers)
True

En annen interessant ting som kan gjøres med denne metoden er å tilpasse bestemt atferd ved å overstyre innebygde metoder:

def enum_repr(t, **enums):
    '''enums with a base class and repr() output'''
    class Enum(t):
        def __repr__(self):
            return '<enum {0} of type Enum({1})>'.format(self._name, t.__name__)

    for key,val in enums.items():
        i = Enum(val)
        i._name = key
        setattr(Enum, key, i)

    return Enum



>>> Numbers = enum_repr(int, ONE=1, TWO=2, THREE=3)
>>> repr(Numbers.ONE)
'<enum ONE of type Enum(int)>'
>>> str(Numbers.ONE)
'1'
Svarte 18/01/2012 kl. 06:09
kilden bruker

stemmer
8
def enum(*sequential, **named):
    enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
    return type('Enum', (), enums)

Hvis du kaller det, er ditt problem, men hvis ikke lage objekter i stedet for verdier kan du gjøre dette:

>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False

Ved bruk av andre implementeringer lokalisert her (også ved bruk av navngitte forekomster i mitt eksempel) må du være sikker på at du aldri prøve å sammenligne gjenstander fra ulike enums. For her er en mulig fallgruve:

>>> DOG = enum('BARK'=1, 'WALK'=2, 'SIT'=3)
>>> CAT = enum('WALK'=1, 'SIT'=2)
>>> pet1_state = DOG.BARK
>>> pet2_state = CAT.WALK
>>> pet1_state == pet2_state
True

Yikes!

Svarte 11/11/2014 kl. 09:26
kilden bruker

stemmer
8

Den nye standarden i Python er PEP 435 , så en Enum klassen vil være tilgjengelig i fremtidige versjoner av Python:

>>> from enum import Enum

Men å begynne å bruke det nå kan du installere den opprinnelige biblioteket som motiverte den PEP:

#sudo pip install flufl.enum   //or #sudo easy_install flufl.enum

Så du kan bruke den som per sin online guide :

>>> from flufl.enum import Enum
>>> class Colors(Enum):
...     red = 1
...     green = 2
...     blue = 3
>>> for color in Colors: print color
Colors.red
Colors.green
Colors.blue
Svarte 10/05/2013 kl. 16:22
kilden bruker

stemmer
7

Enum pakken fra PyPI gir en robust implementering av enums. En tidligere svar nevnte PEP 354; Dette ble avvist, men forslaget ble gjennomført http://pypi.python.org/pypi/enum .

Bruken er enkel og elegant:

>>> from enum import Enum
>>> Colors = Enum('red', 'blue', 'green')
>>> shirt_color = Colors.green
>>> shirt_color = Colors[2]
>>> shirt_color > Colors.red
True
>>> shirt_color.index
2
>>> str(shirt_color)
'green'
Svarte 16/03/2010 kl. 22:36
kilden bruker

stemmer
6

Alexandru forslag om å bruke klasse konstanter for enums fungerer ganske bra.

Jeg ønsker også å legge til en ordbok for hvert sett med konstanter for å slå opp en lesbar strengrepresentasjon.

Dette tjener to formål: a) det er en enkel måte å skrive ut pen din enum og b) ordlisten logisk grupper konstantene slik at du kan teste for medlemskap.

class Animal:    
  TYPE_DOG = 1
  TYPE_CAT = 2

  type2str = {
    TYPE_DOG: "dog",
    TYPE_CAT: "cat"
  }

  def __init__(self, type_):
    assert type_ in self.type2str.keys()
    self._type = type_

  def __repr__(self):
    return "<%s type=%s>" % (
        self.__class__.__name__, self.type2str[self._type].upper())
Svarte 19/09/2008 kl. 03:37
kilden bruker

stemmer
4

Her er en tilnærming med noen forskjellige egenskaper finner jeg verdifull:

  • lar> og <sammenligning basert på rekkefølgen enum, ikke leksikalske orden
  • kan henvende element ved navn, eiendom eller Indeks: XA, x [ 'en'] eller x [0]
  • støtter kutting operasjoner som [:] eller [-1]

og viktigst hindrer sammenligninger mellom enums av forskjellige typer !

Basert tett på http://code.activestate.com/recipes/413486-first-class-enums-in-python .

Mange doctests inkludert her for å illustrere hva som er annerledes med denne tilnærmingen.

def enum(*names):
    """
SYNOPSIS
    Well-behaved enumerated type, easier than creating custom classes

DESCRIPTION
    Create a custom type that implements an enumeration.  Similar in concept
    to a C enum but with some additional capabilities and protections.  See
    http://code.activestate.com/recipes/413486-first-class-enums-in-python/.

PARAMETERS
    names       Ordered list of names.  The order in which names are given
                will be the sort order in the enum type.  Duplicate names
                are not allowed.  Unicode names are mapped to ASCII.

RETURNS
    Object of type enum, with the input names and the enumerated values.

EXAMPLES
    >>> letters = enum('a','e','i','o','u','b','c','y','z')
    >>> letters.a < letters.e
    True

    ## index by property
    >>> letters.a
    a

    ## index by position
    >>> letters[0]
    a

    ## index by name, helpful for bridging string inputs to enum
    >>> letters['a']
    a

    ## sorting by order in the enum() create, not character value
    >>> letters.u < letters.b
    True

    ## normal slicing operations available
    >>> letters[-1]
    z

    ## error since there are not 100 items in enum
    >>> letters[99]
    Traceback (most recent call last):
        ...
    IndexError: tuple index out of range

    ## error since name does not exist in enum
    >>> letters['ggg']
    Traceback (most recent call last):
        ...
    ValueError: tuple.index(x): x not in tuple

    ## enums must be named using valid Python identifiers
    >>> numbers = enum(1,2,3,4)
    Traceback (most recent call last):
        ...
    AssertionError: Enum values must be string or unicode

    >>> a = enum('-a','-b')
    Traceback (most recent call last):
        ...
    TypeError: Error when calling the metaclass bases
        __slots__ must be identifiers

    ## create another enum
    >>> tags = enum('a','b','c')
    >>> tags.a
    a
    >>> letters.a
    a

    ## can't compare values from different enums
    >>> letters.a == tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    >>> letters.a < tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    ## can't update enum after create
    >>> letters.a = 'x'
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'a' is read-only

    ## can't update enum after create
    >>> del letters.u
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'u' is read-only

    ## can't have non-unique enum values
    >>> x = enum('a','b','c','a')
    Traceback (most recent call last):
        ...
    AssertionError: Enums must not repeat values

    ## can't have zero enum values
    >>> x = enum()
    Traceback (most recent call last):
        ...
    AssertionError: Empty enums are not supported

    ## can't have enum values that look like special function names
    ## since these could collide and lead to non-obvious errors
    >>> x = enum('a','b','c','__cmp__')
    Traceback (most recent call last):
        ...
    AssertionError: Enum values beginning with __ are not supported

LIMITATIONS
    Enum values of unicode type are not preserved, mapped to ASCII instead.

    """
    ## must have at least one enum value
    assert names, 'Empty enums are not supported'
    ## enum values must be strings
    assert len([i for i in names if not isinstance(i, types.StringTypes) and not \
        isinstance(i, unicode)]) == 0, 'Enum values must be string or unicode'
    ## enum values must not collide with special function names
    assert len([i for i in names if i.startswith("__")]) == 0,\
        'Enum values beginning with __ are not supported'
    ## each enum value must be unique from all others
    assert names == uniquify(names), 'Enums must not repeat values'

    class EnumClass(object):
        """ See parent function for explanation """

        __slots__ = names

        def __iter__(self):
            return iter(constants)

        def __len__(self):
            return len(constants)

        def __getitem__(self, i):
            ## this makes xx['name'] possible
            if isinstance(i, types.StringTypes):
                i = names.index(i)
            ## handles the more normal xx[0]
            return constants[i]

        def __repr__(self):
            return 'enum' + str(names)

        def __str__(self):
            return 'enum ' + str(constants)

        def index(self, i):
            return names.index(i)

    class EnumValue(object):
        """ See parent function for explanation """

        __slots__ = ('__value')

        def __init__(self, value):
            self.__value = value

        value = property(lambda self: self.__value)

        enumtype = property(lambda self: enumtype)

        def __hash__(self):
            return hash(self.__value)

        def __cmp__(self, other):
            assert self.enumtype is other.enumtype, 'Only values from the same enum are comparable'
            return cmp(self.value, other.value)

        def __invert__(self):
            return constants[maximum - self.value]

        def __nonzero__(self):
            ## return bool(self.value)
            ## Original code led to bool(x[0])==False, not correct
            return True

        def __repr__(self):
            return str(names[self.value])

    maximum = len(names) - 1
    constants = [None] * len(names)
    for i, each in enumerate(names):
        val = EnumValue(i)
        setattr(EnumClass, each, val)
        constants[i] = val
    constants = tuple(constants)
    enumtype = EnumClass()
    return enumtype
Svarte 19/06/2013 kl. 21:30
kilden bruker

stemmer
4

Mens den opprinnelige enum forslaget, PEP 354 , ble avvist år siden, holder det å komme opp igjen. En slags enum var ment å bli lagt til 3,2, men det ble skjøvet tilbake til 3,3 og deretter glemt. Og nå er det en PEP 435 ment for inkludering i Python 3.4. Referanse gjennomføring av PEP 435 er flufl.enum.

Per april 2013 synes det å være en generell enighet om at noe bør legges til standardbiblioteket i 3,4-så lenge folk kan bli enige om hva som "noe" skal være. Det er den harde delen. Se trådene starter her og her , og et halvt dusin andre tråder i de første månedene av 2013.

I mellomtiden, hver gang dette kommer opp, massevis av nye design og implementeringer vises på PyPI, Active, etc., så hvis du ikke liker FLUFL design, prøv en PyPI søk .

Svarte 19/04/2013 kl. 01:16
kilden bruker

stemmer
4

Denne løsningen er en enkel måte å få en klasse for telling definert som en liste (ikke mer irriterende heltall oppdrag):

enumeration.py:

import new

def create(class_name, names):
    return new.classobj(
        class_name, (object,), dict((y, x) for x, y in enumerate(names))
    )

example.py:

import enumeration

Colors = enumeration.create('Colors', (
    'red',
    'orange',
    'yellow',
    'green',
    'blue',
    'violet',
))
Svarte 18/09/2011 kl. 01:26
kilden bruker

stemmer
4

Her er en variant på Alec Thomas løsning :

def enum(*args, **kwargs):
    return type('Enum', (), dict((y, x) for x, y in enumerate(args), **kwargs)) 

x = enum('POOH', 'TIGGER', 'EEYORE', 'ROO', 'PIGLET', 'RABBIT', 'OWL')
assert x.POOH == 0
assert x.TIGGER == 1
Svarte 14/06/2011 kl. 17:29
kilden bruker

stemmer
2

Her er en fin Python oppskrift som jeg fant her: http://code.activestate.com/recipes/577024-yet-another-enum-for-python/

def enum(typename, field_names):
    "Create a new enumeration type"

    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    d = dict((reversed(nv) for nv in enumerate(field_names)), __slots__ = ())
    return type(typename, (object,), d)()

Eksempel på bruk:

STATE = enum('STATE', 'GET_QUIZ, GET_VERSE, TEACH')

Flere detaljer finner du på oppskriften siden.

Svarte 17/03/2014 kl. 17:34
kilden bruker

stemmer
2

Fikk ikke se dette i listen over svarene, her er den jeg pisket opp. Det tillater bruk av 'in' søkeord og len () -metoden:

class EnumTypeError(TypeError):
    pass

class Enum(object):
    """
    Minics enum type from different languages
    Usage:
    Letters = Enum(list('abc'))
    a = Letters.a
    print(a in Letters) # True
    print(54 in Letters) # False
    """
    def __init__(self, enums):
        if isinstance(enums, dict):
            self.__dict__.update(enums)
        elif isinstance(enums, list) or isinstance(enums, tuple):
            self.__dict__.update(**dict((v,k) for k,v in enumerate(enums)))
        else:
            raise EnumTypeError

    def __contains__(self, key):
        return key in self.__dict__.values()

    def __len__(self):
        return len(self.__dict__.values())


if __name__ == '__main__':
    print('Using a dictionary to create Enum:')
    Letters = Enum(dict((v,k) for k,v in enumerate(list('abcde'))))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    print('\nUsing a list to create Enum:')
    Letters = Enum(list('abcde'))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    try:
        # make sure we raise an exception if we pass an invalid arg
        Failure = Enum('This is a Failure')
        print('Failure')
    except EnumTypeError:
        print('Success!')

Produksjon:

Using a dictionary to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5

Using a list to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5
Success!
Svarte 05/09/2013 kl. 04:12
kilden bruker

stemmer
2

Løsningen som Jeg bruker vanligvis er denne enkel funksjon for å få en forekomst av en dynamisk skapte klasse.

def enum(names):
    "Create a simple enumeration having similarities to C."
    return type('enum', (), dict(map(reversed, enumerate(
        names.replace(',', ' ').split())), __slots__=()))()

Bruke det er så enkelt som å kalle funksjonen med en streng med de navnene som du vil referere til.

grade = enum('A B C D F')
state = enum('awake, sleeping, dead')

Verdiene er bare tall, slik at du kan dra nytte av det hvis ønskelig (akkurat som i C-språk).

>>> grade.A
0
>>> grade.B
1
>>> grade.F == 4
True
>>> state.dead == 2
True
Svarte 31/01/2013 kl. 14:27
kilden bruker

stemmer
2

En variant (med støtte for å få en enum verdi navn) til Alec Thomas ryddig svar :

class EnumBase(type):
    def __init__(self, name, base, fields):
        super(EnumBase, self).__init__(name, base, fields)
        self.__mapping = dict((v, k) for k, v in fields.iteritems())
    def __getitem__(self, val):
        return self.__mapping[val]

def enum(*seq, **named):
    enums = dict(zip(seq, range(len(seq))), **named)
    return EnumBase('Enum', (), enums)

Numbers = enum(ONE=1, TWO=2, THREE='three')
print Numbers.TWO
print Numbers[Numbers.ONE]
print Numbers[2]
print Numbers['three']
Svarte 21/06/2012 kl. 22:43
kilden bruker

stemmer
2

Hvorfor må enumerations være ints? Dessverre kan jeg ikke komme på noen gode jakt konstruere å produsere dette uten å endre Python språket, så jeg skal bruke strenger:

class Enumerator(object):
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        if self.name == other:
            return True
        return self is other

    def __ne__(self, other):
        if self.name != other:
            return False
        return self is other

    def __repr__(self):
        return 'Enumerator({0})'.format(self.name)

    def __str__(self):
        return self.name

class Enum(object):
    def __init__(self, *enumerators):
        for e in enumerators:
            setattr(self, e, Enumerator(e))
    def __getitem__(self, key):
        return getattr(self, key)

Så igjen kanskje det er enda bedre nå som vi naturlig kan teste mot strengene, av hensyn til konfigurasjonsfiler eller annen ekstern inngang.

Eksempel:

class Cow(object):
    State = Enum(
        'standing',
        'walking',
        'eating',
        'mooing',
        'sleeping',
        'dead',
        'dying'
    )
    state = State.standing

In [1]: from enum import Enum

In [2]: c = Cow()

In [3]: c2 = Cow()

In [4]: c.state, c2.state
Out[4]: (Enumerator(standing), Enumerator(standing))

In [5]: c.state == c2.state
Out[5]: True

In [6]: c.State.mooing
Out[6]: Enumerator(mooing)

In [7]: c.State['mooing']
Out[7]: Enumerator(mooing)

In [8]: c.state = Cow.State.dead

In [9]: c.state == c2.state
Out[9]: False

In [10]: c.state == Cow.State.dead
Out[10]: True

In [11]: c.state == 'dead'
Out[11]: True

In [12]: c.state == Cow.State['dead']
Out[11]: True
Svarte 07/05/2010 kl. 02:05
kilden bruker

stemmer
2

Jeg hadde behov for noen symbolske konstanter i pyparsing å representere venstre og høyre assosiativitet av binære operatorer. Jeg brukte klasse konstanter som dette:

# an internal class, not intended to be seen by client code
class _Constants(object):
    pass


# an enumeration of constants for operator associativity
opAssoc = _Constants()
opAssoc.LEFT = object()
opAssoc.RIGHT = object()

Nå når klientkoden ønsker å bruke disse konstanter, kan de importere hele enum ved hjelp av:

import opAssoc from pyparsing

De enumerations er unike, de kan bli testet med 'er' i stedet for '==', tar de ikke opp en stor plass i min kode for en mindre konsept, og de er lett importeres til klientkoden. De støtter ikke noen fancy str () oppførsel, men så langt som er i YAGNI kategorien.

Svarte 17/11/2009 kl. 20:54
kilden bruker

stemmer
2

Det er morsomt, jeg bare hadde et behov for dette den andre dagen, og jeg kunne ikke finne en implementering verdt å bruke ... så jeg skrev min egen:

import functools

class EnumValue(object):
    def __init__(self,name,value,type):
        self.__value=value
        self.__name=name
        self.Type=type
    def __str__(self):
        return self.__name
    def __repr__(self):#2.6 only... so change to what ever you need...
        return '{cls}({0!r},{1!r},{2})'.format(self.__name,self.__value,self.Type.__name__,cls=type(self).__name__)

    def __hash__(self):
        return hash(self.__value)
    def __nonzero__(self):
        return bool(self.__value)
    def __cmp__(self,other):
        if isinstance(other,EnumValue):
            return cmp(self.__value,other.__value)
        else:
            return cmp(self.__value,other)#hopefully their the same type... but who cares?
    def __or__(self,other):
        if other is None:
            return self
        elif type(self) is not type(other):
            raise TypeError()
        return EnumValue('{0.Name} | {1.Name}'.format(self,other),self.Value|other.Value,self.Type)
    def __and__(self,other):
        if other is None:
            return self
        elif type(self) is not type(other):
            raise TypeError()
        return EnumValue('{0.Name} & {1.Name}'.format(self,other),self.Value&other.Value,self.Type)
    def __contains__(self,other):
        if self.Value==other.Value:
            return True
        return bool(self&other)
    def __invert__(self):
        enumerables=self.Type.__enumerables__
        return functools.reduce(EnumValue.__or__,(enum for enum in enumerables.itervalues() if enum not in self))

    @property
    def Name(self):
        return self.__name

    @property
    def Value(self):
        return self.__value

class EnumMeta(type):
    @staticmethod
    def __addToReverseLookup(rev,value,newKeys,nextIter,force=True):
        if value in rev:
            forced,items=rev.get(value,(force,()) )
            if forced and force: #value was forced, so just append
                rev[value]=(True,items+newKeys)
            elif not forced:#move it to a new spot
                next=nextIter.next()
                EnumMeta.__addToReverseLookup(rev,next,items,nextIter,False)
                rev[value]=(force,newKeys)
            else: #not forcing this value
                next = nextIter.next()
                EnumMeta.__addToReverseLookup(rev,next,newKeys,nextIter,False)
                rev[value]=(force,newKeys)
        else:#set it and forget it
            rev[value]=(force,newKeys)
        return value

    def __init__(cls,name,bases,atts):
        classVars=vars(cls)
        enums = classVars.get('__enumerables__',None)
        nextIter = getattr(cls,'__nextitr__',itertools.count)()
        reverseLookup={}
        values={}

        if enums is not None:
            #build reverse lookup
            for item in enums:
                if isinstance(item,(tuple,list)):
                    items=list(item)
                    value=items.pop()
                    EnumMeta.__addToReverseLookup(reverseLookup,value,tuple(map(str,items)),nextIter)
                else:
                    value=nextIter.next()
                    value=EnumMeta.__addToReverseLookup(reverseLookup,value,(str(item),),nextIter,False)#add it to the reverse lookup, but don't force it to that value

            #build values and clean up reverse lookup
            for value,fkeys in reverseLookup.iteritems():
                f,keys=fkeys
                for key in keys:
                    enum=EnumValue(key,value,cls)
                    setattr(cls,key,enum)
                    values[key]=enum
                reverseLookup[value]=tuple(val for val in values.itervalues() if val.Value == value)
        setattr(cls,'__reverseLookup__',reverseLookup)
        setattr(cls,'__enumerables__',values)
        setattr(cls,'_Max',max([key for key in reverseLookup] or [0]))
        return super(EnumMeta,cls).__init__(name,bases,atts)

    def __iter__(cls):
        for enum in cls.__enumerables__.itervalues():
            yield enum
    def GetEnumByName(cls,name):
        return cls.__enumerables__.get(name,None)
    def GetEnumByValue(cls,value):
        return cls.__reverseLookup__.get(value,(None,))[0]

class Enum(object):
    __metaclass__=EnumMeta
    __enumerables__=None

class FlagEnum(Enum):
    @staticmethod
    def __nextitr__():
        yield 0
        for val in itertools.count():
            yield 2**val

def enum(name,*args):
    return EnumMeta(name,(Enum,),dict(__enumerables__=args))

Ta det eller la det, det gjorde det jeg trengte å gjøre :)

Bruk den slik ut:

class Air(FlagEnum):
    __enumerables__=('None','Oxygen','Nitrogen','Hydrogen')

class Mammals(Enum):
    __enumerables__=('Bat','Whale',('Dog','Puppy',1),'Cat')
Bool = enum('Bool','Yes',('No',0))
Svarte 21/10/2008 kl. 02:08
kilden bruker

stemmer
1

Python 2.7 og find_name ()

Her er en lett-å-lese gjennomføring av den valgte ideen med noen helper metoder, som kanskje er mer Pytonske og renere å bruke enn "reverse_mapping". Krever Python> = 2,7.

For å løse noen kommentarer nedenfor, enums er ganske nyttig for å hindre stavefeil i koden, for eksempel for tilstandsmaskiner, feilklassifiseringsenheter etc.

def Enum(*sequential, **named):
  """Generate a new enum type. Usage example:

  ErrorClass = Enum('STOP','GO')
  print ErrorClass.find_name(ErrorClass.STOP)
    = "STOP"
  print ErrorClass.find_val("STOP")
    = 0
  ErrorClass.FOO     # Raises AttributeError
  """
  enums = { v:k for k,v in enumerate(sequential) } if not named else named

  @classmethod
  def find_name(cls, val):
    result = [ k for k,v in cls.__dict__.iteritems() if v == val ]
    if not len(result):
        raise ValueError("Value %s not found in Enum" % val)
    return result[0]

  @classmethod
  def find_val(cls, n):
    return getattr(cls, n)

  enums['find_val'] = find_val
  enums['find_name'] = find_name
  return type('Enum', (), enums)
Svarte 08/04/2013 kl. 18:58
kilden bruker

stemmer
1

Jeg liker å bruke lister eller sett som enumerations. For eksempel:

>>> packet_types = ['INIT', 'FINI', 'RECV', 'SEND']
>>> packet_types.index('INIT')
0
>>> packet_types.index('FINI')
1
>>>
Svarte 20/11/2012 kl. 13:18
kilden bruker

stemmer
1

Jeg bruker en metaclass å implementere en oppregning (i min tanke, er det en const). Her er koden:

class ConstMeta(type):
    '''
    Metaclass for some class that store constants
    '''
    def __init__(cls, name, bases, dct):
        '''
        init class instance
        '''
        def static_attrs():
            '''
            @rtype: (static_attrs, static_val_set)
            @return: Static attributes in dict format and static value set
            '''
            import types
            attrs = {}
            val_set = set()
            #Maybe more
            filter_names = set(['__doc__', '__init__', '__metaclass__', '__module__', '__main__'])
            for key, value in dct.iteritems():
                if type(value) != types.FunctionType and key not in filter_names:
                    if len(value) != 2:
                        raise NotImplementedError('not support for values that is not 2 elements!')
                    #Check value[0] duplication.
                    if value[0] not in val_set:
                        val_set.add(value[0])
                    else:
                        raise KeyError("%s 's key: %s is duplicated!" % (dict([(key, value)]), value[0]))
                    attrs[key] = value
            return attrs, val_set

        attrs, val_set = static_attrs()
        #Set STATIC_ATTRS to class instance so that can reuse
        setattr(cls, 'STATIC_ATTRS', attrs)
        setattr(cls, 'static_val_set', val_set)
        super(ConstMeta, cls).__init__(name, bases, dct)

    def __getattribute__(cls, name):
        '''
        Rewrite the special function so as to get correct attribute value
        '''
        static_attrs = object.__getattribute__(cls, 'STATIC_ATTRS')
        if name in static_attrs:
            return static_attrs[name][0]
        return object.__getattribute__(cls, name)

    def static_values(cls):
        '''
        Put values in static attribute into a list, use the function to validate value.
        @return: Set of values
        '''
        return cls.static_val_set

    def __getitem__(cls, key):
        '''
        Rewrite to make syntax SomeConstClass[key] works, and return desc string of related static value.
        @return: Desc string of related static value
        '''
        for k, v in cls.STATIC_ATTRS.iteritems():
            if v[0] == key:
                return v[1]
        raise KeyError('Key: %s does not exists in %s !' % (str(key), repr(cls)))


class Const(object):
    '''
    Base class for constant class.

    @usage:

    Definition: (must inherit from Const class!
        >>> class SomeConst(Const):
        >>>   STATUS_NAME_1 = (1, 'desc for the status1')
        >>>   STATUS_NAME_2 = (2, 'desc for the status2')

    Invoke(base upper SomeConst class):
    1) SomeConst.STATUS_NAME_1 returns 1
    2) SomeConst[1] returns 'desc for the status1'
    3) SomeConst.STATIC_ATTRS returns {'STATUS_NAME_1': (1, 'desc for the status1'), 'STATUS_NAME_2': (2, 'desc for the status2')}
    4) SomeConst.static_values() returns set([1, 2])

    Attention:
    SomeCosnt's value 1, 2 can not be duplicated!
    If WrongConst is like this, it will raise KeyError:
    class WrongConst(Const):
        STATUS_NAME_1 = (1, 'desc for the status1')
        STATUS_NAME_2 = (1, 'desc for the status2')
    '''
    __metaclass__ = ConstMeta
##################################################################
#Const Base Class ends
##################################################################


def main():
    class STATUS(Const):
        ERROR = (-3, '??')
        OK = (0, '??')

    print STATUS.ERROR
    print STATUS.static_values()
    print STATUS.STATIC_ATTRS

    #Usage sample:
    user_input = 1
    #Validate input:
    print user_input in STATUS.static_values()
    #Template render like:
    print '<select>'
    for key, value in STATUS.STATIC_ATTRS.items():
        print '<option value="%s">%s</option>' % (value[0], value[1])
    print '</select>'


if __name__ == '__main__':
    main()
Svarte 04/04/2012 kl. 02:43
kilden bruker

stemmer
1

Jeg liker Java enum, det er hvordan jeg gjør det i Python:

def enum(clsdef):
    class Enum(object):
        __slots__=tuple([var for var in clsdef.__dict__ if isinstance((getattr(clsdef, var)), tuple) and not var.startswith('__')])

        def __new__(cls, *args, **kwargs):
            if not '_the_instance' in cls.__dict__:
                cls._the_instance = object.__new__(cls, *args, **kwargs)
            return cls._the_instance

        def __init__(self):
            clsdef.values=lambda cls, e=Enum: e.values()
            clsdef.valueOf=lambda cls, n, e=self: e.valueOf(n)
            for ordinal, key in enumerate(self.__class__.__slots__):
                args=getattr(clsdef, key)
                instance=clsdef(*args)
                instance._name=key
                instance._ordinal=ordinal
                setattr(self, key, instance)

        @classmethod
        def values(cls):
            if not hasattr(cls, '_values'):
                cls._values=[getattr(cls, name) for name in cls.__slots__]
            return cls._values

        def valueOf(self, name):
            return getattr(self, name)

        def __repr__(self):
            return ''.join(['<class Enum (', clsdef.__name__, ') at ', str(hex(id(self))), '>'])

    return Enum()

Prøve bruk:

i=2
@enum
class Test(object):
    A=("a",1)
    B=("b",)
    C=("c",2)
    D=tuple()
    E=("e",3)

    while True:
        try:
            F, G, H, I, J, K, L, M, N, O=[tuple() for _ in range(i)]
            break;
        except ValueError:
            i+=1

    def __init__(self, name="default", aparam=0):
        self.name=name
        self.avalue=aparam

Alle klassevariabler er definert som en tuppel, akkurat som konstruktøren. Så langt, kan du ikke bruke navngitte argumenter.

Svarte 04/06/2010 kl. 16:33
kilden bruker

stemmer
1
def enum( *names ):

    '''
    Makes enum.
    Usage:
        E = enum( 'YOUR', 'KEYS', 'HERE' )
        print( E.HERE )
    '''

    class Enum():
        pass
    for index, name in enumerate( names ):
        setattr( Enum, name, index )
    return Enum
Svarte 26/05/2010 kl. 13:14
kilden bruker

stemmer
1

Etter Java som enum implementering foreslått av Aaron Mäenpää, jeg kom ut med følgende. Ideen var å gjøre det generiske og parseable.

class Enum:
    #'''
    #Java like implementation for enums.
    #
    #Usage:
    #class Tool(Enum): name = 'Tool'
    #Tool.DRILL = Tool.register('drill')
    #Tool.HAMMER = Tool.register('hammer')
    #Tool.WRENCH = Tool.register('wrench')
    #'''

    name = 'Enum'    # Enum name
    _reg = dict([])   # Enum registered values

    @classmethod
    def register(cls, value):
        #'''
        #Registers a new value in this enum.
        #
        #@param value: New enum value.
        #
        #@return: New value wrapper instance.
        #'''
        inst = cls(value)
        cls._reg[value] = inst
        return inst

    @classmethod
    def parse(cls, value):
        #'''
        #Parses a value, returning the enum instance.
        #
        #@param value: Enum value.
        #
        #@return: Value corresp instance.        
        #'''
        return cls._reg.get(value)    

    def __init__(self, value):
        #'''
        #Constructor (only for internal use).
        #'''
        self.value = value

    def __str__(self):
        #'''
        #str() overload.
        #'''
        return self.value

    def __repr__(self):
        #'''
        #repr() overload.
        #'''
        return "<" + self.name + ": " + self.value + ">"
Svarte 05/03/2010 kl. 20:24
kilden bruker

stemmer
1

Bruk følgende.

TYPE = {'EAN13':   u'EAN-13',
        'CODE39':  u'Code 39',
        'CODE128': u'Code 128',
        'i25':     u'Interleaved 2 of 5',}

>>> TYPE.items()
[('EAN13', u'EAN-13'), ('i25', u'Interleaved 2 of 5'), ('CODE39', u'Code 39'), ('CODE128', u'Code 128')]
>>> TYPE.keys()
['EAN13', 'i25', 'CODE39', 'CODE128']
>>> TYPE.values()
[u'EAN-13', u'Interleaved 2 of 5', u'Code 39', u'Code 128']

Jeg brukte det for Django modell valg, og det ser veldig Pytonske. Det er egentlig ikke en Enum, men det gjør jobben.

Svarte 19/10/2009 kl. 10:21
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more