Πώς μπορώ να αντιπροσωπεύει μια «Enum» στην Python;

ψήφοι
1k

Είμαι κυρίως C # developer, αλλά είμαι σήμερα εργάζονται για ένα έργο στην Python.

Πώς μπορώ να αντιπροσωπεύουν το ισοδύναμο ενός Enum στην Python;

Δημοσιεύθηκε 31/08/2008 στις 16:55
πηγή χρήστη
Σε άλλες γλώσσες...                            


43 απαντήσεις

ψήφοι
711

Πριν PEP 435, Python δεν έχουν ισοδύναμο, αλλά θα μπορούσατε να εφαρμόσετε τις δικές σας.

Εαυτός μου, μου αρέσει κρατώντας το απλό (έχω δει κάποια φοβερά πολύπλοκα παραδείγματα στο διαδίκτυο), κάτι σαν αυτό ...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

Στην Python 3.4 ( PEP 435 ), μπορείτε να κάνετε Enum η βασική κλάση. Αυτό σας παίρνει λίγο επιπλέον λειτουργικότητα, που περιγράφεται στο ΠΕΠ. Για παράδειγμα, οι τιμές enum είναι διακριτές από ακέραιοι.

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

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

Εάν δεν θέλετε να πληκτρολογήσετε τις τιμές, χρησιμοποιήστε την παρακάτω συντόμευση:

class Animal(Enum):
    DOG, CAT = range(2)
Απαντήθηκε 31/08/2008 στις 17:06
πηγή χρήστη

ψήφοι
18

Χμμμ ... Υποθέτω ότι το πιο κοντινό πράγμα σε μια απαρίθμησης θα ήταν ένα λεξικό, που ορίζεται είτε ως εξής:

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

ή

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

Στη συνέχεια, μπορείτε να χρησιμοποιήσετε το συμβολικό όνομα για τις σταθερές όπως αυτό:

mymonth = months['January']

Υπάρχουν και άλλες επιλογές, όπως μια λίστα των πλειάδων, ή μια πλειάδα από πλειάδες, αλλά το λεξικό είναι η μόνη που σας παρέχει μια «συμβολική» (σταθερή σειρά) τρόπος για να αποκτήσετε πρόσβαση στην αξία.

Επεξεργασία: Μου αρέσει απάντηση Alexandru πάρα πολύ!

Απαντήθηκε 31/08/2008 στις 17:09
πηγή χρήστη

ψήφοι
43

Python δεν έχει ενσωματωμένο ισοδυναμεί με enum, και άλλες απαντήσεις έχουν ιδέες για την εφαρμογή της δικής σας (μπορείτε επίσης να ενδιαφέρεται για το πάνω από την κορυφαία έκδοση στο βιβλίο μαγειρικής Python).

Ωστόσο, σε περιπτώσεις όπου ένας enumθα κληθούν σε C, συνήθως καταλήγουν μόνο με απλές χορδές : λόγω του τρόπου εφαρμογής τους αντικείμενα / χαρακτηριστικά, (C) Python έχει βελτιστοποιηθεί ώστε να λειτουργεί πολύ γρήγορα με σύντομες σειρές ούτως ή άλλως, έτσι wouldn εκεί «t πραγματικά να είναι οποιοδήποτε όφελος των επιδόσεων από τη χρήση ακεραίων. Για την προστασία από λάθη / μη έγκυρες τιμές μπορείτε να εισάγετε ελέγχους σε επιλεγμένα σημεία.

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

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

(Ένα μειονέκτημα σε σύγκριση με τη χρήση μιας κατηγορίας είναι ότι χάνετε το πλεονέκτημα της αυτόματης συμπλήρωσης)

Απαντήθηκε 31/08/2008 στις 19:10
πηγή χρήστη

ψήφοι
180

Εάν χρειάζεστε τις αριθμητικές τιμές, εδώ είναι ο πιο γρήγορος τρόπος:

dog, cat, rabbit = range(3)

Στην Python 3.x μπορείτε επίσης να προσθέσετε ένα αστέρι σύμβολο κράτησης θέσης στο τέλος, το οποίο θα απολαύσετε όλες τις υπόλοιπες τιμές της σειράς σε περίπτωση που δεν πειράζει σπατάλη μνήμης και δεν μπορεί να υπολογίζει:

dog, cat, rabbit, horse, *_ = range(100)
Απαντήθηκε 31/08/2008 στις 21:31
πηγή χρήστη

ψήφοι
75

Το μοτίβο typesafe enum το οποίο χρησιμοποιήθηκε σε Java προ-JDK 5 έχει έναν αριθμό πλεονεκτημάτων. Μοιάζει πολύ με την απάντηση Alexandru, μπορείτε να δημιουργήσετε ένα επίπεδο της τάξης και της τάξης πεδία είναι οι τιμές απαρίθμησης? Ωστόσο, οι τιμές enum είναι περιπτώσεις της κατηγορίας και όχι μικρά ακέραιοι. Αυτό έχει το πλεονέκτημα ότι οι τιμές απαρίθμησης σας δεν ακούσια συγκρίνετε ίσο με μικρές ακέραιους αριθμούς, μπορείτε να ελέγξετε τον τρόπο όπου και αν εκτυπωθούν, να προσθέσετε αυθαίρετες μεθόδους, αν αυτό είναι χρήσιμο και να κάνει ισχυρισμούς χρησιμοποιώντας 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

Μια πρόσφατη νήμα για python-dev επεσήμανε ότι υπάρχουν μερικές βιβλιοθήκες απαρίθμησης στην άγρια φύση, συμπεριλαμβανομένων:

Απαντήθηκε 01/09/2008 στις 17:05
πηγή χρήστη

ψήφοι
14

davidg συνιστά τη χρήση DICTS. Είχα πάει ένα βήμα παραπέρα και να χρησιμοποιούν σύνολα:

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

Τώρα μπορείτε να ελέγξετε αν μια τιμή δεν ταιριάζει με μια από τις τιμές στο σύνολο σαν αυτό:

if m in months:

όπως dF, όμως, εγώ συνήθως απλά χρησιμοποιήστε σταθερές συμβολοσειράς στη θέση του enums.

Απαντήθηκε 02/09/2008 στις 04:20
πηγή χρήστη

ψήφοι
5

πρόταση Alexandru για τη χρήση σταθερών τάξης για enums λειτουργεί αρκετά καλά.

Θα ήθελα επίσης να προσθέσω ένα λεξικό για κάθε σύνολο σταθερών σε αναζήτηση μιας παράστασης συμβολοσειράς αναγνώσιμη από τον άνθρωπο.

Αυτό εξυπηρετεί δύο σκοπούς: α) παρέχει έναν απλό τρόπο για πολύ-εκτύπωση απαρίθμησης και β) το λεξικό λογικά ομάδες οι σταθερές, έτσι ώστε να μπορείτε να ελέγξετε για ένταξη.

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())
Απαντήθηκε 19/09/2008 στις 04:37
πηγή χρήστη

ψήφοι
28
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()

Χρησιμοποιήστε το σαν αυτό:

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

αν θέλετε απλά μοναδικά σύμβολα και δεν ενδιαφέρονται για τις τιμές, την αντικατάσταση αυτή τη γραμμή:

__metaclass__ = M_add_class_attribs(enumerate(names))

με αυτό:

__metaclass__ = M_add_class_attribs((object(), name) for name in names)
Απαντήθηκε 20/09/2008 στις 12:49
πηγή χρήστη

ψήφοι
2

Είναι αστείο, είχα μόνο μια ανάγκη για αυτό την άλλη μέρα και θα μπορούσα να βρείτε μια εφαρμογή που αξίζει τη χρήση ... έτσι έγραψα το δικό μου:

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

Πάρτε το ή αφήστε το, έκανε ό, τι έπρεπε να κάνει :)

Χρησιμοποιήστε το όπως:

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

class Mammals(Enum):
    __enumerables__=('Bat','Whale',('Dog','Puppy',1),'Cat')
Bool = enum('Bool','Yes',('No',0))
Απαντήθηκε 21/10/2008 στις 03:08
πηγή χρήστη

ψήφοι
16

Αυτό που μπορώ να χρησιμοποιήσω:

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

Πώς να χρησιμοποιήσετε:

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

Έτσι, αυτό σας δίνει ακέραιο σταθερές, όπως state.PUBLISHED και τα δύο πλειάδες που θα χρησιμοποιηθεί ως επιλογές στα μοντέλα Django.

Απαντήθηκε 03/02/2009 στις 00:39
πηγή χρήστη

ψήφοι
118

Η καλύτερη λύση για σας θα εξαρτηθεί από το τι χρειάζεστε από το ψεύτικο enum .

Απλή enum:

Εάν χρειάζεστε την enumως μόνο μια λίστα με τα ονόματα τον προσδιορισμό των διαφόρων ειδών , η λύση από τον Mark Harrison (παραπάνω) είναι μεγάλη:

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

Χρησιμοποιώντας ένα rangeσας επιτρέπει επίσης να ορίσετε οποιαδήποτε τιμή εκκίνησης :

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

Εκτός από τα παραπάνω, εάν απαιτείται, επίσης, ότι τα στοιχεία που ανήκουν σε ένα εμπορευματοκιβώτιο κάποιου είδους, τότε να τους ενσωματώσετε σε μια τάξη:

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

Για να χρησιμοποιήσετε το στοιχείο απαρίθμησης, θα πρέπει τώρα να χρησιμοποιήσει το όνομα του δοχείου και το όνομα του στοιχείου:

stype = Stationery.Pen

Συγκρότημα enum:

Για μεγάλες λίστες της απαρίθμησης ή πιο περίπλοκη χρήσεις της απαρίθμησης, αυτές οι λύσεις δεν θα είναι αρκετή. Θα μπορούσατε να δείτε την συνταγή του Will Υγιεινής για την προσομοίωση των συνόλων Python δημοσιευθεί στην Python Cookbook . Η ηλεκτρονική έκδοση της που είναι διαθέσιμη εδώ .

Περισσότερες πληροφορίες:

PEP 354: συνόλων Python έχει τις ενδιαφέρουσες λεπτομέρειες της πρότασης για απαρίθμησης σε Python και γι 'αυτό απορρίφθηκε.

Απαντήθηκε 07/10/2009 στις 03:47
πηγή χρήστη

ψήφοι
1

Χρησιμοποιήστε τα ακόλουθα.

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

Θα χρησιμοποιηθεί αυτό για Django επιλογές μοντέλο, και φαίνεται πολύ pythonic. Δεν είναι πραγματικά ένα Enum, αλλά κάνει τη δουλειά του.

Απαντήθηκε 19/10/2009 στις 11:21
πηγή χρήστη

ψήφοι
2k

Έχουν Enums προστεθεί στο Python 3.4 όπως περιγράφεται στο PEP 435 . Έχει επίσης backported έως 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, και 2.4 σε pypi.

Για περισσότερες προηγμένες τεχνικές Enum δοκιμάστε την βιβλιοθήκη aenum (2.7, 3,3+, ίδιο συγγραφέα ως enum34. Κώδικας δεν είναι απόλυτα συμβατές μεταξύ py2 και py3, π.χ. θα πρέπει __order__σε python 2 ).

  • Για να χρησιμοποιήσετε enum34, κάντε$ pip install enum34
  • Για να χρησιμοποιήσετε aenum, κάντε$ pip install aenum

Εγκατάσταση enum(χωρίς αριθμούς) θα εγκαταστήσει μια εντελώς διαφορετική και μη συμβατή έκδοση.


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)

ή ισοδύναμα:

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

Σε παλαιότερες εκδόσεις, ένας τρόπος για την επίτευξη enums είναι:

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

το οποίο χρησιμοποιείται όπως έτσι:

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

Μπορείτε επίσης να υποστηρίξει εύκολα αυτόματη αρίθμηση με κάτι σαν αυτό:

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

και χρησιμοποιούνται σαν αυτό:

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

Υποστήριξη για τη μετατροπή των τιμών πίσω σε ονόματα μπορεί να προστεθεί με αυτόν τον τρόπο:

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)

Αυτό αντικαθιστά τίποτα με αυτό το όνομα, αλλά είναι χρήσιμο για την απόδοση enums σας στην έξοδο. Θα ρίξει KeyError αν δεν υπάρχει η αντίστροφη χαρτογράφηση. Με το πρώτο παράδειγμα:

>>> Numbers.reverse_mapping['three']
'THREE'
Απαντήθηκε 08/11/2009 στις 04:15
πηγή χρήστη

ψήφοι
2

Είχα ανάγκη από κάποιες συμβολικές σταθερές στο pyparsing να εκπροσωπεί τα αριστερά και δεξιά συσχέτισης των δυαδικών φορέων. Θα χρησιμοποιηθεί για σταθερές κατηγορίας, όπως αυτό:

# 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()

Τώρα, όταν ο κώδικας πελάτης θέλει να χρησιμοποιεί τις σταθερές αυτές, μπορούν να εισάγουν το σύνολο της απαρίθμησης χρησιμοποιώντας:

import opAssoc from pyparsing

Οι απαριθμήσεις είναι μοναδικά, μπορούν να ελεγχθούν με το «είναι» αντί του «==», που δεν καταλαμβάνουν ένα μεγάλο αποτύπωμα στον κώδικά μου για μια μικρή ιδέα, και εισάγονται εύκολα στον κώδικα του πελάτη. Δεν υποστηρίζουν οποιαδήποτε συμπεριφορά φανταχτερό str (), αλλά μέχρι στιγμής αυτό είναι το YAGNI κατηγορία.

Απαντήθηκε 17/11/2009 στις 21:54
πηγή χρήστη

ψήφοι
13

Αυτό είναι το καλύτερο που έχω δει: «First Class Enums στην Python»

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

Σας δίνει μια τάξη και η τάξη περιλαμβάνει όλα τα enums. Οι enums μπορούν να συγκριθούν μεταξύ τους, αλλά δεν έχουν ιδιαίτερη αξία? δεν μπορείτε να τα χρησιμοποιήσετε ως μια ακέραια τιμή. (Αντιστάθηκα αυτή την πρώτη, επειδή έχω συνηθίσει να C enums, οι οποίες είναι ακέραιες τιμές. Αλλά αν δεν μπορείτε να το χρησιμοποιήσετε ως ένα ακέραιο, δεν μπορείτε να το χρησιμοποιήσετε ως ένα ακέραιο κατά λάθος και έτσι συνολικά νομίζω ότι είναι μια νίκη .) Κάθε απαρίθμησης είναι μια μοναδική τιμή. Μπορείτε να εκτυπώσετε enums, μπορείτε να μετακινηθείτε πάνω τους, μπορείτε να ελέγξετε ότι η τιμή απαρίθμησης είναι «σε» την απαρίθμησης. Είναι αρκετά πλήρης και λείο.

Επεξεργασία (CFI): Η παραπάνω σύνδεσμος δεν είναι Python 3 συμβατή. Εδώ είναι το λιμάνι μου enum.py σε 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)
Απαντήθηκε 18/11/2009 στις 03:51
πηγή χρήστη

ψήφοι
296

Εδώ είναι μια εφαρμογή:

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

Εδώ είναι η χρήση του:

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

print(Animals.DOG)
Απαντήθηκε 02/02/2010 στις 08:21
πηγή χρήστη

ψήφοι
1

Μετά την εφαρμογή Java, όπως απαρίθμησης προτείνει Aaron Mäenpää, βγήκα με τα ακόλουθα. Η ιδέα ήταν να γίνει γενική και 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 + ">"
Απαντήθηκε 05/03/2010 στις 21:24
πηγή χρήστη

ψήφοι
5

Το πακέτο enum από PyPI παρέχει μια ισχυρή εφαρμογή των enums. Μια προηγούμενη απάντηση αναφέρεται PEP 354? αυτό απορρίφθηκε, αλλά η πρόταση τέθηκε σε εφαρμογή http://pypi.python.org/pypi/enum .

Χρήση είναι εύκολη και κομψή:

>>> 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'
Απαντήθηκε 16/03/2010 στις 23:36
πηγή χρήστη

ψήφοι
2

Γιατί πρέπει να απαριθμήσεις να ints; Δυστυχώς, δεν μπορώ να σκεφτώ κάποιο καλό που αναζητούν την κατασκευή για να παράγουν αυτό χωρίς να αλλάξετε τη γλώσσα Python, γι 'αυτό θα χρησιμοποιήσει χορδές:

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)

Στη συνέχεια και πάλι ίσως είναι ακόμα καλύτερα τώρα που μπορούμε να ελέγξουμε φυσικά εναντίον χορδές, για χάρη των αρχείων ρυθμίσεων ή άλλες απομακρυσμένες εισόδου.

Παράδειγμα:

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
Απαντήθηκε 07/05/2010 στις 03:05
πηγή χρήστη

ψήφοι
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
Απαντήθηκε 26/05/2010 στις 14:14
πηγή χρήστη

ψήφοι
1

Μου αρέσει η Java απαρίθμησης, αυτό είναι το πώς θα το κάνουμε σε 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()

Δείγμα χρήση:

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

Όλες οι μεταβλητές κλάσης ορίζεται ως μια πλειάδα, ακριβώς όπως τον κατασκευαστή. Μέχρι στιγμής, δεν μπορείτε να χρησιμοποιήσετε το όνομα επιχειρήματα.

Απαντήθηκε 04/06/2010 στις 17:33
πηγή χρήστη

ψήφοι
43

Έτσι, συμφωνώ. Ας μην επιβάλει ασφαλείας τύπου σε Python, αλλά θα ήθελα να προστατέψω τον εαυτό μου από ανόητα λάθη. Έτσι τι σκεφτόμαστε γι 'αυτό;

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

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

Αυτό με κρατάει από την αξία της σύγκρουσης στον καθορισμό enums μου.

>>> Animal.Cat
2

Υπάρχει ένα άλλο πρακτικό πλεονέκτημα: πολύ γρήγορα αντίστροφες αναζητήσεις:

def name_of(self, i):
    return self.values[i]
Απαντήθηκε 04/11/2010 στις 00:02
πηγή χρήστη

ψήφοι
28

Προτιμώ να καθορίσει enums στην Python, όπως αυτό:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

Είναι πιο bug-απόδειξη από τη χρήση ακεραίων δεδομένου ότι δεν έχετε να ανησυχείτε για τη διασφάλιση ότι οι ακέραιοι είναι μοναδικά (π.χ. αν είπατε Dog = 1 και Cat = 1 τότε θα πρέπει να βιδωθεί).

Είναι πιο bug-απόδειξη από τη χρήση χορδές αφού δεν έχετε να ανησυχείτε για τυπογραφικά λάθη (π.χ. x == «βοοει» αποτυγχάνει αθόρυβα, αλλά x == Animal.Catt είναι ένα runtime εξαίρεση).

Απαντήθηκε 29/11/2010 στις 03:05
πηγή χρήστη

ψήφοι
3

Εδώ είναι μια παραλλαγή της λύσης Alec Θωμά :

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
Απαντήθηκε 14/06/2011 στις 18:29
πηγή χρήστη

ψήφοι
20

Ένα άλλο, πολύ απλά, η εφαρμογή μιας απαρίθμησης σε Python, με τη χρήση namedtuple:

from collections import namedtuple

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

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

ή, εναλλακτικά,

# 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())

Όπως και η παραπάνω μέθοδος αυτή υποκατηγορίες set, αυτό επιτρέπει:

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

Αλλά έχει μεγαλύτερη ευελιξία καθώς μπορεί να έχουν διαφορετικά κλειδιά και αξίες. Αυτό επιτρέπει

MyEnum.FOO < MyEnum.BAR

να ενεργεί ως αναμένεται, αν χρησιμοποιείτε την έκδοση που συμπληρώνει διαδοχικές αριθμητικές τιμές.

Απαντήθηκε 07/08/2011 στις 06:51
πηγή χρήστη

ψήφοι
3

Αυτή η λύση είναι ένας απλός τρόπος για να πάρει ένα μάθημα για την καταμέτρηση ορίζεται ως λίστα (όχι περισσότερο ενοχλητικό αναθέσεις ακέραιος):

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',
))
Απαντήθηκε 18/09/2011 στις 02:26
πηγή χρήστη

ψήφοι
10

Είχα την ευκαιρία να χρειάζονται μια τάξη Enum, με σκοπό την αποκωδικοποίηση ενός δυαδική μορφή αρχείου. Τα χαρακτηριστικά που έτυχε να θέλω είναι συνοπτική περιγραφή απαρίθμησης, η δυνατότητα να δημιουργήσετε ελεύθερα παρουσίες της απαρίθμησης είτε ακέραια τιμή ή σπάγκο, και ένα χρήσιμο representation. Εδώ είναι αυτό που κατέληξα με:

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

Ένα παιχνιδιάρικη παράδειγμα από τη χρήση του:

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

Βασικά χαρακτηριστικά:

  • str(), int()Και repr()όλα παράγουν το δυνατόν πιο χρήσιμο εξόδου, αντίστοιχα το όνομα του enumartion, ακέραια τιμή του, και ένα έκφραση Python που αξιολογεί πίσω στο απαρίθμηση.
  • απαριθμούνται τιμές επέστρεψαν από τον κατασκευαστή περιορίζεται αυστηρά στις προκαθορισμένες τιμές, χωρίς τυχαία τιμές enum.
  • Απαριθμούνται τιμές είναι singletons? μπορούν απολύτως να συγκριθεί μεis
Απαντήθηκε 22/12/2011 στις 03:16
πηγή χρήστη

ψήφοι
8

Μου αρέσει λύση Alec Θωμά (http://stackoverflow.com/a/1695250):

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

Είναι κομψό και καθαρό ψάχνει, αλλά είναι απλά μια λειτουργία που δημιουργεί μια τάξη με τις συγκεκριμένες ιδιότητες.

Με μια μικρή τροποποίηση στη λειτουργία, μπορούμε να το πάρει για να δράσει λίγο πιο «enumy»:

ΣΗΜΕΙΩΣΗ: Δημιούργησα τα ακόλουθα παραδείγματα, προσπαθώντας να αναπαράγουν τη συμπεριφορά των «enums» PyGTK νέο στυλ (όπως το 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

Αυτό δημιουργεί ένα enum βάση από ένα συγκεκριμένο τύπο. Εκτός από την παροχή πρόσβασης χαρακτηριστικό όπως και η προηγούμενη λειτουργία, συμπεριφέρεται όπως θα περίμενε κανείς μια Enum σε σχέση με τους τύπους. Είναι κληρονομεί επίσης την κλάση βάσης.

Για παράδειγμα, ακέραιο 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

Ένα άλλο ενδιαφέρον πράγμα που μπορεί να γίνει με τη μέθοδο αυτή είναι προσαρμόσετε συγκεκριμένη συμπεριφορά από επιτακτικούς ενσωματωμένο μεθόδους:

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'
Απαντήθηκε 18/01/2012 στις 07:09
πηγή χρήστη

ψήφοι
54

Μια κατηγορία Enum μπορεί να είναι ένα one-επένδυση.

class Enum(tuple): __getattr__ = tuple.index

Πώς να το χρησιμοποιήσετε (προς τα εμπρός και αντίστροφη αναζήτηση, κλειδιά, τιμές, στοιχεία, κλπ)

>>> 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)]
Απαντήθηκε 08/02/2012 στις 21:59
πηγή χρήστη

ψήφοι
1

Χρησιμοποιώ ένα μετακλάση να εφαρμόσουν μια απαρίθμηση (στη σκέψη μου, είναι const). Εδώ είναι ο κώδικας:

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()
Απαντήθηκε 04/04/2012 στις 03:43
πηγή χρήστη

ψήφοι
2

Μια παραλλαγή (με την υποστήριξη για να πάρει το όνομα ενός αξία enum) για να τακτοποιημένο απάντηση Alec Θωμά :

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']
Απαντήθηκε 21/06/2012 στις 23:43
πηγή χρήστη

ψήφοι
1

Μου αρέσει να χρησιμοποιούν καταλόγους ή θέτει ως συνόλων. Για παράδειγμα:

>>> packet_types = ['INIT', 'FINI', 'RECV', 'SEND']
>>> packet_types.index('INIT')
0
>>> packet_types.index('FINI')
1
>>>
Απαντήθηκε 20/11/2012 στις 14:18
πηγή χρήστη

ψήφοι
2

Η λύση που εγώ συνήθως χρησιμοποιούν είναι αυτή η απλή λειτουργία για να πάρετε ένα στιγμιότυπο μιας κλάσης δημιουργούνται δυναμικά.

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

Η χρήση του είναι τόσο απλή όσο καλώντας τη συνάρτηση με μια σειρά που έχει τα ονόματα που θέλετε να αναφέρετε.

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

Οι τιμές είναι μόνο ακέραιοι, ώστε να μπορείτε να επωφεληθείτε από αυτό, αν θέλετε (όπως ακριβώς και στη γλώσσα C).

>>> grade.A
0
>>> grade.B
1
>>> grade.F == 4
True
>>> state.dead == 2
True
Απαντήθηκε 31/01/2013 στις 15:27
πηγή χρήστη

ψήφοι
1

Python 2.7 και find_name ()

Εδώ είναι ένα εύκολο στην ανάγνωση εφαρμογή της επιλεγείσας ιδέα με κάποιες μεθόδους βοηθός, που ίσως είναι πιο Pythonic και καθαρότερο στη χρήση από «reverse_mapping». Απαιτεί Python> = 2.7.

Για την αντιμετώπιση κάτω από κάποια σχόλια, Enums είναι αρκετά χρήσιμο για την πρόληψη ορθογραφικά λάθη στον κώδικα, π.χ. για τις κρατικές μηχανές, ταξινομητές λάθος, κ.λπ.

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)
Απαντήθηκε 08/04/2013 στις 19:58
πηγή χρήστη

ψήφοι
3

Ενώ η αρχική πρόταση της απαρίθμησης, PEP 354 , απορρίφθηκε χρόνια πριν, επανέρχεται επάνω. Κάποιο είδος απαρίθμησης επρόκειτο να προστεθεί στο 3.2, αλλά πήρε έσπρωξε πίσω στο 3.3 και στη συνέχεια να ξεχαστεί. Και τώρα υπάρχει μια PEP 435 που προορίζεται για ένταξη στην Python 3.4. Η εφαρμογή αναφοράς του PEP 435 είναι flufl.enum.

Από τον Απρίλιο του 2013, φαίνεται να υπάρχει μια γενική συναίνεση ότι υπάρχει κάτι που πρέπει να προστεθεί στο πρότυπο βιβλιοθήκης στην 3.4-εφ 'όσον οι άνθρωποι μπορούν να συμφωνήσουν σχετικά με το τι ότι «κάτι» θα πρέπει να είναι. Αυτό είναι το δύσκολο μέρος. Δείτε τα θέματα που αρχίζουν εδώ και εδώ και μισή ντουζίνα άλλα θέματα που κατά τους πρώτους μήνες του 2013.

Εν τω μεταξύ, κάθε φορά που αυτό έρχεται, μια απόκλιση από τα νέα σχέδια και οι εφαρμογές εμφανίζονται στο PyPI, ActiveState, κλπ, οπότε αν δεν σας αρέσει το σχεδιασμό FLUFL, δοκιμάστε μια αναζήτηση PyPI .

Απαντήθηκε 19/04/2013 στις 02:16
πηγή χρήστη

ψήφοι
29

Την 05.10.2013, Guido συμφώνησε να δεχθεί PEP 435 στην πρότυπη βιβλιοθήκη της Python 3.4. Αυτό σημαίνει ότι η Python έχει τελικά ενσωματωμένη υποστήριξη για απαριθμήσεις!

Υπάρχει ένα backport διαθέσιμες για Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, και 2.4. Είναι σε Pypi ως enum34 .

Δήλωση:

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

Αναπαράσταση:

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

Επανάληψη:

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

Προγραμματική πρόσβασης:

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

Για περισσότερες πληροφορίες, ανατρέξτε στην πρόταση . Επίσημη τεκμηρίωση κατά πάσα πιθανότητα θα ακολουθήσουν σύντομα.

Απαντήθηκε 10/05/2013 στις 17:09
πηγή χρήστη

ψήφοι
7

Το νέο πρότυπο στην Python είναι PEP 435 , οπότε μια κατηγορία Enum θα είναι διαθέσιμη σε μελλοντικές εκδόσεις της Python:

>>> from enum import Enum

Ωστόσο, για να αρχίσετε να χρησιμοποιείτε το τώρα μπορείτε να εγκαταστήσετε την αρχική βιβλιοθήκη που παρακίνησε το ΠΕΠ:

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

Στη συνέχεια, μπορείτε να το χρησιμοποιήσετε ως ανά ηλεκτρονικό οδηγό της :

>>> 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
Απαντήθηκε 10/05/2013 στις 17:22
πηγή χρήστη

ψήφοι
3

Εδώ είναι μια προσέγγιση με κάποια διαφορετικά χαρακτηριστικά θεωρώ πολύτιμη:

  • επιτρέπει> και <σύγκριση βασίζεται σε σειρά απαρίθμησης, δεν λεξιλογικές σειρά
  • μπορεί να αντιμετωπίσει το στοιχείο με βάση το όνομα, την περιουσία ή το δείκτη: xa, x [ 'a'] ή x [0]
  • υποστηρίζει τον τεμαχισμό λειτουργίες, όπως [:] ή [-1]

και το πιο σημαντικό εμποδίζει τις συγκρίσεις μεταξύ enums διαφορετικών τύπων !

Με βάση κοντά στο http://code.activestate.com/recipes/413486-first-class-enums-in-python .

Πολλοί doctests περιλαμβάνονται εδώ για να απεικονίσουν ό, τι είναι διαφορετικό για αυτήν την προσέγγιση.

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
Απαντήθηκε 19/06/2013 στις 22:30
πηγή χρήστη

ψήφοι
2

Δεν βλέπετε αυτό το ένα στη λίστα των απαντήσεων, εδώ είναι αυτή που υποκίνησε. Επιτρέπει τη χρήση του «in» λέξη-κλειδί και len () μέθοδος:

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!')

Παραγωγή:

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!
Απαντήθηκε 05/09/2013 στις 05:12
πηγή χρήστη

ψήφοι
14

Από την Python 3.4 θα υπάρχει επίσημη υποστήριξη για enums. Μπορείτε να βρείτε την τεκμηρίωση και παραδείγματα εδώ στην Python 3.4 σελίδα τεκμηρίωσης .

Οι απαριθμήσεις δημιουργούνται χρησιμοποιώντας τη σύνταξη κατηγορίας, γεγονός που τις καθιστά εύκολο να διαβάσει και να γράψει. Μια εναλλακτική μέθοδος δημιουργίας περιγράφεται στο Functional API. Για να ορίσετε μια απαρίθμηση, υποκατηγορία Enum ως εξής:

from enum import Enum
class Color(Enum):
     red = 1
     green = 2
     blue = 3
Απαντήθηκε 11/12/2013 στις 14:49
πηγή χρήστη

ψήφοι
2

Εδώ είναι μια ωραία συνταγή Python που βρήκα εδώ: 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)()

Παράδειγμα Χρήσης:

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

Περισσότερες λεπτομέρειες μπορείτε να βρείτε στη σελίδα συνταγή.

Απαντήθηκε 17/03/2014 στις 18:34
πηγή χρήστη

ψήφοι
10

Φροντίστε να είναι απλή:

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

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

Επειτα:

DIRECTION = Enum(('UP', 'DOWN', 'LEFT', 'RIGHT'))
DIRECTION.DOWN
1
Απαντήθηκε 28/03/2014 στις 22:44
πηγή χρήστη

ψήφοι
7
def enum(*sequential, **named):
    enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
    return type('Enum', (), enums)

Αν εσείς το όνομα, είναι το πρόβλημά σας, αλλά αν δεν τη δημιουργία αντικειμένων αντί των αξιών σας επιτρέπει να το κάνετε αυτό:

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

Όταν χρησιμοποιείτε άλλες εφαρμογές βρίσκονται εδώ (ακόμα και όταν χρησιμοποιείτε το όνομά περιπτώσεις στο παράδειγμά μου) θα πρέπει να είστε σίγουροι ότι ποτέ δεν προσπαθούν να συγκρίνουν αντικείμενα από διαφορετικές enums. Για εδώ είναι μια πιθανή παγίδα:

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

Απαντήθηκε 11/11/2014 στις 09:26
πηγή χρήστη

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