سؤال

أنا أساسا C# المطور, ولكن أنا أعمل حاليا على مشروع في بيثون.

كيف يمكنني تمثل ما يعادل التعداد في الثعبان ؟

هل كانت مفيدة؟

المحلول

Enums تم إضافة بايثون 3.4 كما هو موضح في بيب 435.كما تم backported إلى 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, و 2.4 على pypi.

لمزيد من التعداد تقنيات محاولة aenum المكتبة (2.7 و3. 3+ نفس البلاغ enum34.المدونة ليست متوافقة تماما بين py2 و py3 مثلاسوف تحتاج __order__ في بيثون 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'

نصائح أخرى

قبل بيب 435 ، بيثون لم يكن لديك ما يعادلها ولكن هل يمكن تنفيذ الخاص بك.

نفسي أحب الحفاظ على أنها بسيطة (لقد رأيت بعض فظيعة مجمع أمثلة على الشبكة), شيء من هذا القبيل ...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

في بايثون 3.4 (بيب 435) ، يمكنك أن تجعل التعداد الفئة الأساسية.هذا يحصل لك قليلا من وظائف إضافية ، هو موضح في الحماسي.على سبيل المثال ، enum أعضاء متميزة من الأعداد الصحيحة ، وهي تتألف من name و value.

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

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

print(Animal.DOG.value)
# 1

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

إذا كنت لا تريد أن اكتب القيم التالية الاختصار:

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

Enum تطبيقات يمكن تحويلها إلى قوائم هي iterable.ترتيب أعضائها هو إعلان النظام و لا علاقة له مع قيمها.على سبيل المثال:

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

هنا هو تطبيق واحد:

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

هنا هو الاستخدام:

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

print(Animals.DOG)

إذا كنت في حاجة إلى قيم رقمية ، وهنا أسرع طريقة:

dog, cat, rabbit = range(3)

في بيثون 3.× يمكنك أيضا إضافة تألق نائبا في نهاية المطاف ، والتي سوف تمتص كل ما تبقى من قيم النطاق في حال كنت لا تمانع في إضاعة الذاكرة لا يمكن الاعتماد:

dog, cat, rabbit, horse, *_ = range(100)

الحل الأفضل بالنسبة لك يعتمد على ما تحتاج من وهمية enum.

بسيطة التعداد:

إذا كنت في حاجة إلى enum فقط قائمة أسماء تحديد مختلف البنود, الحل من قبل مارك هاريسون (أعلاه) عظيم:

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

باستخدام range كما يسمح لك لتحديد أي ابتداء من قيمة:

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

بالإضافة إلى ما سبق ، إذا كنت تحتاج أيضا إلى أن عناصر تنتمي إلى حاوية من نوع ما ، ثم تضمينها في فئة:

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

استخدام التعداد البند, أنت الآن بحاجة إلى استخدام الحاويات اسم و اسم العنصر:

stype = Stationery.Pen

مجمع التعداد:

على قوائم طويلة من التعداد أو أكثر تعقيدا يستخدم من التعداد, هذه الحلول لا تكفي.هل يمكن أن ننظر إلى وصفة من سوف وير ل محاكاة التعدادات في بايثون نشرت في بيثون طبخ.النسخة الإلكترونية من ما هو متاح هنا.

مزيد من المعلومات:

بيب 354:والتعدادات في بايثون وقد تفاصيل مثيرة للاهتمام من اقتراح التعداد في بيثون و لماذا تم رفضها.

على typesafe التعداد النمط الذي كان يستخدم في جاوة قبل JDK 5 لديه عدد من المزايا.مثل الكثير في ألكساندرو الجواب إنشاء فئة وفئة مستوى الحقول التعداد القيم ؛ ومع ذلك ، فإن التعداد القيم حالات الطبقة بدلا من الأعداد الصحيحة.هذا وقد ميزة أن التعداد القيم لا عن غير قصد مقارنة متساوية الصغيرة الاعداد الصحيحه ، يمكنك التحكم في كيفية انهم المطبوعة ، إضافة التعسفي طرق إذا كان هذا هو المفيد وجعل تأكيدات باستخدام 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

مؤخرا موضوع على الثعبان-dev وأشار إلى أن هناك زوجين من التعداد المكتبات في البرية ، بما في ذلك:

وهو التعداد فئة يمكن أن يكون بطانة واحدة.

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

الثعبان ليس لديها المدمج في تعادل enum, وغيرها من الإجابات لديهم أفكار لتنفيذ الخاصة بك (قد تكون مهتما أيضا في على النسخة الأولى في بيثون الطبخ).

ولكن في الحالات التي يكون فيها أحد enum سيكون دعت C, وعادة ما ينتهي فقط باستخدام السلاسل بسيطة:بسبب الطريقة الكائنات/سمات تنفيذ (ج)بيثون هو الأمثل للعمل سريع جدا مع سلاسل قصيرة على أي حال ، لذلك هناك لن يكون أي أداء فائدة باستخدام الأعداد الصحيحة.الاحتراس من الأخطاء المطبعية / صالح القيم يمكنك إدراج الشيكات في أماكن مختارة.

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

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

(عيب واحد مقارنة باستخدام فئة هو أن تخسر لصالح الإكمال التلقائي)

لذلك أنا أتفق.دعونا لا فرض نوع السلامة في بيثون ، ولكن أود أن أحمي نفسي من أخطاء سخيفة.فما رأيكم في هذا ؟

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]

على 2013-05-10 ، غيدو وافقت على قبول بيب 435 في بايثون 3.4 مكتبة القياسية.وهذا يعني أن الثعبان أخيرا مدمج دعم والتعدادات!

هناك backport المتاحة الثعبان 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

للحصول على مزيد من المعلومات ، راجع الاقتراح.الوثائق الرسمية من المحتمل قريبا.

أنا أفضل أن تحدد enums في بايثون مثل ذلك:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

ومن أكثر الأخطاء واقية من استخدام الأعداد الصحيحة منذ كنت لا داعي للقلق حول ضمان الاعداد الصحيحه هي فريدة من نوعها (مثلا ، إذا قال لك الكلب = 1 و Cat = 1 سوف يكون مشدود).

ومن أكثر الأخطاء واقية من استخدام سلاسل منذ كنت لا داعي للقلق حول الأخطاء المطبعية (مثلا ، x == "catt" فشل بصمت ، ولكن س == الحيوانية.Catt هي وقت استثناء).

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)

هممم...أعتقد أن أقرب شيء إلى التعداد سيكون القاموس ، تعريفه مثل هذا:

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

أو

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

ثم يمكنك استخدام اسم رمزي عن الثوابت مثل هذا:

mymonth = months['January']

هناك خيارات أخرى ، مثل قائمة الصفوف ، أو tuple من الصفوف ، ولكن القاموس هو الوحيد الذي يوفر لك مع "رمزي" (سلسلة ثابتة) وسيلة للوصول إلى القيمة.

تحرير:أنا أحب ألكساندرو الجواب أيضا!

آخر بسيط جدا ، تنفيذ التعداد في بيثون ، باستخدام 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

أن تتصرف كما هو متوقع إذا كنت تستخدم الإصدار الذي يملأ متتابعة عدد القيم.

ما يمكنني استخدام:

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

لذلك هذا يتيح لك الثوابت الصحيحة مثل الدولة.نشرت في الصفوف استخدام الخيارات في جانغو النماذج.

من بايثون 3.4 سيكون هناك دعم رسمي enums.يمكنك العثور على وثائق وأمثلة هنا في بايثون 3.4 الوثائق الصفحة.

والتعدادات يتم إنشاؤها باستخدام فئة الجملة ، مما يجعلها سهلة القراءة والكتابة.بديل إنشاء الأسلوب هو موضح في وظيفية API.لتحديد تعداد فرعية التعداد على النحو التالي:

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

davidg توصي باستخدام dicts.كنت أذهب خطوة واحدة أبعد من ذلك استخدام مجموعات:

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

الآن يمكنك اختبار ما إذا كانت قيمة المباريات واحدة من القيم في تعيين مثل هذا:

if m in months:

مثل dF, على الرغم من أنني عادة استخدام ثوابت السلسلة في مكان enums.

هذا هو أفضل واحد لقد رأيت:"من الدرجة الأولى Enums في بايثون"

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

يعطيك فئة و فئة يحتوي على جميع enums.على enums يمكن مقارنة بعضها البعض ، ولكن لا تملك أية قيمة ؛ لا يمكنك استخدامها بوصفها قيمة عدد صحيح.(قاومت هذا في البداية لأنني اعتدت على ج enums ، والتي هي القيم الصحيحة.ولكن إذا لم تتمكن من استخدام هذا صحيحا, لا يمكنك استخدامه بمثابة صحيح عن طريق الخطأ لذلك عموما أنا أعتقد أنه هو الفوز....) كل التعداد هو قيمة فريدة من نوعها.يمكنك طباعة enums ، يمكنك تكرار عليهم, يمكنك اختبار هذا التعداد القيمة "في" enum.انها جميلة كاملة والبقعة.

تحرير (cfi):الرابط أعلاه لا بيثون 3 متوافق.هنا هو بلدي ميناء enum.py إلى بيثون 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)

يبقيه بسيط:

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

وسنحت لي الفرصة من التعداد الصف لغرض فك تنسيق ملف ثنائي.الميزات حدث أني كنت تريد موجزة التعداد التعريف القدرة على بحرية إنشاء مثيلات من التعداد من قبل أي قيمة عدد صحيح أو سلسلة و مفيدة 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 ، قيمة عدد صحيح و الثعبان تعبير يقيم إلى التعداد.
  • تعداد القيم التي يتم إرجاعها من قبل منشئ محدودة بدقة القيم المعرفة مسبقا, لا عرضي التعداد القيم.
  • تعداد القيم ووحدانية;أنها يمكن أن تكون بدقة مقارنة مع is

أنا حقا أحب أليك توماس الحل (http://stackoverflow.com/a/1695250):

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

انها أنيقة و نظيفة المظهر ، ولكن انها مجرد وظيفة أن يخلق الطبقة المحددة الصفات.

مع القليل من التعديل على وظيفة نستطيع أن تعمل أكثر من ذلك بقليل 'enumy':

ملاحظة:أنا خلقت الأمثلة التالية قبل محاولة إعادة إنشاء سلوك pygtk هو نمط جديد 'enums' (مثل Gtk.MessageType.تحذير)

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

هذا يخلق التعداد القائم قبالة نوع محدد.بالإضافة إلى إعطاء سمة الدخول مثل الدالة السابقة ، فإنه يتصرف كما كنت تتوقع إجراء التعداد يتعلق أنواع.كما يرث الفئة الأساسية.

على سبيل المثال, صحيح 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'
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

ياه!

المعيار الجديد في بيثون هو بيب 435, ، لذلك التعداد الدرجة سوف تكون متاحة في الإصدارات المستقبلية من الثعبان:

>>> from enum import Enum

ومع ذلك البدء في استخدامه الآن يمكنك تثبيت مكتبة الأصلي أن الدافع الحماسي:

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

التعداد حزمة من PyPI يوفر تطبيق قوية من enums.رد سابق ذكرت بيب 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'

ألكساندرو اقتراح استخدام فئة الثوابت بالنسبة enums يعمل بشكل جيد جدا.

وأود أيضا أن أضيف قاموس لكل مجموعة من الثوابت إلى بحث الإنسان للقراءة تمثيل السلسلة.

وهذا يخدم غرضين:أ) يوفر طريقة بسيطة جدا-طباعة enum و ب) القاموس منطقيا المجموعات الثوابت بحيث يمكنك اختبار العضوية.

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

هنا نهج مع بعض خصائص مختلفة تجد القيمة:

  • يسمح > ، < المقارنة على أساس النظام في التعداد لا المعجمية النظام
  • يمكن معالجة البند اسم المنشأة أو مؤشر:x.a, 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

هنا هو البديل على أليك توماس الحل:

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

هذا الحل هو وسيلة بسيطة للحصول على الدرجة على التعداد بأنها قائمة (لا أكثر مزعج صحيح المهام):

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

في حين الأصلي التعداد الاقتراح ، بيب 354, كان رفض قبل سنوات يبقي يعود.نوع من التعداد كان المقصود أن تضاف إلى 3.2 ، ولكن تم تأجيله إلى 3.3 ثم نسي.والآن هناك بيب 435 المقصود لإدراجها في بايثون 3.4.الإشارة تنفيذ بيب 435 flufl.enum.

اعتبارا من نيسان / أبريل 2013 ، يبدو أن هناك إجماع عام على أن شيء ينبغي أن يضاف إلى المكتبة القياسية في 3.4—طالما أن الناس يمكن أن نتفق على أن "شيئا ما" ينبغي أن يكون.هذا هو الجزء الصعب.راجع المواضيع ابتداء من هنا و هنا, و نصف دزينة من المواضيع الأخرى في الأشهر الأولى من عام 2013.

وفي الوقت نفسه, كل هذا يأتي عدد كبير من التصاميم الجديدة و تطبيقات تظهر على PyPI, ActiveState ، وما إلى ذلك ، لذلك إذا كنت لا تحب FLUFL تصميم ، في محاولة PyPI البحث.

البديل (مع الدعم للحصول على قيمة تعداد اسم) إلى أليك توماس أنيق الإجابة:

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']
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top