जवाबों:
PEP 435 में वर्णित के रूप में पायथन 3.4 में एनम जोड़े गए हैं । यह भी pypi पर 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 और 2.4 को बैकपोर्ट किया गया है।
अधिक उन्नत Enum तकनीकों के लिए aenum लाइब्रेरी (2.7, 3.3+, एक ही लेखक के रूप में प्रयास करें enum34
। कोड py2 और p33 के बीच पूरी तरह से संगत नहीं है, उदाहरण के लिए आपको __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
पुराने संस्करणों में, एनमों को पूरा करने का एक तरीका है:
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)
यह उस नाम के साथ कुछ भी अधिलेखित करता है, लेकिन यह आउटपुट में आपके एनम को प्रस्तुत करने के लिए उपयोगी है। यदि रिवर्स मैपिंग मौजूद नहीं है, तो यह KeyError को फेंक देगा। पहले उदाहरण के साथ:
>>> Numbers.reverse_mapping['three']
'THREE'
**named
पुराने संस्करणों के लिए enum फ़ंक्शन में var kwargs ( ) कस्टम मानों का समर्थन करने के लिए है:enum("blue", "red", "green", black=0)
PEP 435 से पहले, Python के पास एक समतुल्य नहीं था, लेकिन आप अपने स्वयं के कार्यान्वयन कर सकते थे।
खुद को, मैं इसे सरल रखना पसंद करता हूं (मैंने नेट पर कुछ भयानक जटिल उदाहरण देखे हैं), कुछ इस तरह ...
class Animal:
DOG = 1
CAT = 2
x = Animal.DOG
पायथन 3.4 ( PEP 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
कार्यान्वयन सूचियों में परिवर्तित किए जा सकते हैं और पुनरावृत्त होते हैं । इसके सदस्यों का आदेश घोषणा आदेश है और इसका उनके मूल्यों से कोई लेना-देना नहीं है। उदाहरण के लिए:
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
object()
।
यहाँ एक कार्यान्वयन है:
class Enum(set):
def __getattr__(self, name):
if name in self:
return name
raise AttributeError
यहाँ इसका उपयोग है:
Animals = Enum(["DOG", "CAT", "HORSE"])
print(Animals.DOG)
__setattr__(self, name, value)
और शायद __delattr__(self, name)
इसलिए कि अगर आप गलती से लिखेंगे Animals.DOG = CAT
तो यह चुपचाप सफल नहीं होगा।
Animals.DOG
; इसके अलावा, कॉन्स्टैट्स के मूल्य तार हैं, ताकि इन स्थिरांक के साथ तुलना धीमी हो अगर, मान लें, पूर्णांक को मान के रूप में अनुमति दी गई थी।
setattr()
कार्यप्रणाली को अधिक __init__()
करने के बजाय विधि के अंदर फ़ंक्शन का उपयोग करने का प्रयास किया __getattr__()
। मुझे लगता है कि यह उसी तरह काम करने वाला माना जाता है: वर्ग Enum (ऑब्जेक्ट): __init __ (self, enum_string_list): if type (enum_string_list) == सूची: enum_string_list में enum_ring के लिए: setattr (आत्म, enum_string, enum_string) विशेषता
try-except
ब्लॉक में सेट सदस्यता के लिए कैसे जाँच करते हैं ?
यदि आपको संख्यात्मक मानों की आवश्यकता है, तो यहां सबसे तेज़ तरीका है:
dog, cat, rabbit = range(3)
Python 3.x में आप अंत में एक तारांकित प्लेसहोल्डर भी जोड़ सकते हैं, जो उस श्रेणी के सभी शेष मानों को भिगो देगा, जब आप स्मृति को बर्बाद नहीं करते और न गिन सकते हैं:
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
जटिल enum:
एनम की लंबी सूची या एनुम के अधिक जटिल उपयोगों के लिए, ये समाधान पर्याप्त नहीं होंगे। आप पायथन कुकबुक में प्रकाशित पायथन में विल वेयर के लिए विल वेयर द्वारा नुस्खा के लिए देख सकते हैं । इसका एक ऑनलाइन संस्करण यहां उपलब्ध है ।
और जानकारी:
PEP 354: पायथन में एन्यूमरेशन में पायथन में एनम के लिए एक प्रस्ताव का दिलचस्प विवरण है और इसे क्यों खारिज कर दिया गया था।
range
पहला तर्क छोड़ सकते हैं यदि यह 0 है
my_enum = dict(map(reversed, enumerate(str.split('Item0 Item1 Item2'))))
। फिर my_enum
लुक-अप में उपयोग किया जा सकता है, उदाहरण के लिए, my_enum['Item0']
अनुक्रम में एक अनुक्रम हो सकता है। आप किसी str.split
ऐसे फ़ंक्शन के परिणाम को लपेटना चाहते हैं जो किसी भी डुप्लिकेट होने पर अपवाद को फेंकता है।
Flag1, Flag2, Flag3 = [2**i for i in range(3)]
जावा पूर्व-जेडडीके 5 में उपयोग किए जाने वाले टाइपफॉम एनम पैटर्न के कई फायदे हैं। अलेक्जेंड्रू के जवाब में बहुत पसंद है, आप एक क्लास बनाते हैं और क्लास लेवल फील्ड एनम वैल्यूज हैं; हालाँकि, एनम मान छोटे पूर्णांकों के बजाय कक्षा के उदाहरण हैं। इससे यह फायदा होता है कि आपके एनम वैल्यू अनजाने में छोटे पूर्णांकों के बराबर तुलना नहीं करते हैं, आप नियंत्रित कर सकते हैं कि वे कैसे मुद्रित होते हैं, मनमाने तरीके जोड़ते हैं यदि यह उपयोगी है और आइंस्टीन का उपयोग करके अभिकथन करें:
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
अजगर देव पर हाल ही में एक सूत्र ने बताया कि जंगली में कुछ पुस्तकालय हैं, जिनमें शामिल हैं:
एनम वर्ग एक-लाइनर हो सकता है।
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)]
in
सदस्यों के लिए खोज करने के लिए कीवर्ड का उपयोग करता हूं जो साफ-सुथरे हैं। उदाहरण उपयोग:'Claimed' in Enum(['Unclaimed', 'Claimed'])
तो, मैं सहमत हूं। आइए पायथन में प्रकार की सुरक्षा को लागू न करें, लेकिन मैं खुद को मूर्खतापूर्ण गलतियों से बचाना चाहूंगा। तो हम इस बारे में क्या सोचते हैं?
class Animal(object):
values = ['Horse','Dog','Cat']
class __metaclass__(type):
def __getattr__(self, name):
return self.values.index(name)
यह मुझे अपनी दुश्मनी को परिभाषित करने में मूल्य-टकराव से बचाता है।
>>> Animal.Cat
2
एक और आसान लाभ है: वास्तव में तेजी से रिवर्स लुकअप:
def name_of(self, i):
return self.values[i]
Animal = Enum('horse', 'dog', 'cat')
। मैं भी self.values में एक लापता आइटम की स्थिति में getattr में ValueError को पकड़ता हूं - इसके बजाय आपूर्ति किए गए नाम स्ट्रिंग के साथ एक AttributeError को उठाना बेहतर लगता है। मैं उस क्षेत्र में अपने सीमित ज्ञान के आधार पर पायथन 2.7 में काम करने के लिए मेटाक्लस नहीं प्राप्त कर सका, लेकिन मेरा कस्टम एनम वर्ग सीधे उदाहरण के तरीकों से ठीक काम करता है।
पायथन में एक बिल्ट-इन के बराबर नहीं है enum
, और अन्य उत्तरों में आपके स्वयं के कार्यान्वयन के लिए विचार हैं (आप पायथन कुकबुक में शीर्ष संस्करण में भी रुचि ले सकते हैं )।
हालाँकि, ऐसी परिस्थितियों में जहाँ enum
C के लिए कॉल किया जाता है, मैं आमतौर पर सिंपल स्ट्रिंग्स का उपयोग करके समाप्त होता हूँ : जिस तरह से ऑब्जेक्ट्स / विशेषताओं को लागू किया जाता है, (C) वैसे भी शॉर्ट स्ट्रिंग्स के साथ पायथन को बहुत तेज़ी से काम करने के लिए अनुकूलित किया जाता है, इसलिए पूर्णांक का उपयोग करने के लिए वास्तव में कोई प्रदर्शन लाभ नहीं होगा। टाइपो / अमान्य मानों से बचाव के लिए आप चयनित स्थानों में चेक डाल सकते हैं।
ANIMALS = ['cat', 'dog', 'python']
def take_for_a_walk(animal):
assert animal in ANIMALS
...
(एक वर्ग का उपयोग करने की तुलना में एक नुकसान यह है कि आप स्वत: पूर्ण का लाभ खो देते हैं)
2013-05-10 को, गुइडो ने PEP 435 को पायथन 3.4 मानक पुस्तकालय में स्वीकार करने पर सहमति व्यक्त की । इसका मतलब यह है कि पायथन ने अंत में गणना के लिए अंतर्निहित समर्थन किया है!
पायथन 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 और 2.4 के लिए एक बैकपोर्ट उपलब्ध है। यह enum34 के रूप में Pypi पर है ।
घोषणा:
>>> 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
अधिक जानकारी के लिए , प्रस्ताव देखें । आधिकारिक प्रलेखन शायद जल्द ही पालन करेंगे।
मैं इस तरह से अजगर में शत्रुओं को परिभाषित करना पसंद करता हूं:
class Animal:
class Dog: pass
class Cat: pass
x = Animal.Dog
पूर्णांक का उपयोग करने की तुलना में यह अधिक बग-प्रूफ है क्योंकि आपको यह सुनिश्चित करने के बारे में चिंता करने की आवश्यकता नहीं है कि पूर्णांक अद्वितीय हैं (जैसे यदि आपने कहा कि कुत्ता = 1 और बिल्ली = 1 आप खराब हो जाएंगे)।
यह स्ट्रिंग्स का उपयोग करने की तुलना में अधिक बग-प्रूफ है क्योंकि आपको टाइपोस के बारे में चिंता करने की ज़रूरत नहीं है (जैसे x == "catt" चुपचाप विफल रहता है, लेकिन x == Animal.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)
enum(names)
गए enum(*names)
- तो आप इसे कॉल करते समय अतिरिक्त कोष्ठक छोड़ सकते हैं।
हममम ... मुझे लगता है कि एक एनुम के लिए निकटतम बात एक शब्दकोश होगी, इस तरह से परिभाषित:
months = {
'January': 1,
'February': 2,
...
}
या
months = dict(
January=1,
February=2,
...
)
फिर, आप इस तरह से स्थिरांक के लिए प्रतीकात्मक नाम का उपयोग कर सकते हैं:
mymonth = months['January']
अन्य विकल्प हैं, जैसे टुपल्स की सूची, या टुपल्स का एक टपल, लेकिन शब्दकोश एकमात्र ऐसा है जो आपको मूल्य तक पहुंचने के लिए "प्रतीकात्मक" (निरंतर स्ट्रिंग) तरीका प्रदान करता है।
संपादित करें: मुझे अलेक्जेंड्रू का जवाब भी पसंद है!
एक और, बहुत ही सरल, पायथन में एक एनम का कार्यान्वयन, का उपयोग करते हुए 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
जैसा कि अपेक्षित है यदि आप उस संस्करण का उपयोग करते हैं जो क्रमिक संख्या मानों में भरता है।
पायथन 3.4 से, एनम के लिए आधिकारिक समर्थन मिलेगा। आप Python 3.4 प्रलेखन पृष्ठ पर प्रलेखन और उदाहरण पा सकते हैं ।
Enumerations को क्लास सिंटैक्स का उपयोग करके बनाया जाता है, जिससे उन्हें पढ़ना और लिखना आसान हो जाता है। एक वैकल्पिक निर्माण विधि कार्यात्मक एपीआई में वर्णित है। एन्यूमरेशन को परिभाषित करने के लिए, एनक्लेम को निम्न प्रकार से लिखें:
from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
मैं क्या उपयोग करता हूं:
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'))
तो यह आपको राज्य की तरह पूर्णांक स्थिरांक प्रदान करता है। प्रकाशित और दो-टुपल्स को Django मॉडल में विकल्प के रूप में उपयोग करने के लिए।
davidg dicts का उपयोग करने की सलाह देता है। मैं एक कदम आगे और सेट का उपयोग करूँगा:
months = set('January', 'February', ..., 'December')
अब आप परीक्षण कर सकते हैं कि क्या मूल्य इस तरह से सेट में मौजूद मूल्यों में से एक से मेल खाता है:
if m in months:
हालांकि, डीएफ की तरह, मैं आमतौर पर केवल एनम के स्थान पर स्ट्रिंग स्थिरांक का उपयोग करता हूं।
यह मैंने देखा सबसे अच्छा है: "पायथन में प्रथम श्रेणी के एनम"
http://code.activestate.com/recipes/413486/
यह आपको एक क्लास देता है, और क्लास में सभी एनम होते हैं। एनमों की एक दूसरे से तुलना की जा सकती है, लेकिन इसका कोई विशेष मूल्य नहीं है; आप उन्हें पूर्णांक मान के रूप में उपयोग नहीं कर सकते। (मैंने इसका सबसे पहले विरोध किया क्योंकि मैं सी एनम के लिए उपयोग किया जाता हूं, जो पूर्णांक मान हैं। लेकिन यदि आप इसे पूर्णांक के रूप में उपयोग नहीं कर सकते हैं, तो आप इसे गलती से पूर्णांक के रूप में उपयोग नहीं कर सकते हैं, कुल मिलाकर मुझे लगता है कि यह एक जीत है। ।) प्रत्येक एनुम एक अद्वितीय मूल्य है। आप enums प्रिंट कर सकते हैं, आप उन पर पुनरावृति कर सकते हैं, आप परीक्षण कर सकते हैं कि एक enum मान "inum" है। यह बहुत पूरा है और चालाक है।
संपादित करें (cfi): उपरोक्त लिंक पायथन 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)
.__int__()
विधि को एनम के लिए एक अपवाद उठाना चाहिए; लेकिन मूल्य को बाहर निकालने का एक तरीका होना चाहिए। और वर्ग परिभाषा समय पर विशिष्ट पूर्णांक मान सेट करना संभव होना चाहिए, ताकि आप stat
मॉड्यूल में स्थिरांक जैसी चीजों के लिए एक एनुम का उपयोग कर सकें ।
बाइनरी फ़ाइल फॉर्मेट को डिकोड करने के उद्देश्य से मुझे एनम वर्ग की आवश्यकता होती है। मुझे जो सुविधाएँ चाहिए repr
थीं , वे हैं संक्षिप्त परिभाषा, स्वतंत्र रूप से या तो पूर्णांक मान या स्ट्रिंग, और एक उपयोगी वृद्धि द्वारा Enum के उदाहरण बनाने की क्षमता । यहाँ मैंने क्या किया:
>>> 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()
सभी संभवतया सबसे उपयोगी आउटपुट का उत्पादन करते हैं, क्रमशः एनुमार्टन, इसके पूर्णांक मान और पायथन अभिव्यक्ति का नाम जो एन्यूमरेशन का मूल्यांकन करता है।is
__instancecheck__
विधि को परिभाषित करता है । कक्षाएं उदाहरणों का संग्रह नहीं हैं, इसलिए 1 in Fruit
बेतुका है। हालांकि, लिंक किए गए संस्करण का समर्थन करता है isinstance(1, Fruit)
जो वर्गों और उदाहरणों की धारणा के संदर्भ में अधिक सही होगा।
पायथन में नया मानक PEP 435 है , इसलिए एक Enum क्लास Python के भविष्य के संस्करणों में उपलब्ध होगी:
>>> from enum import Enum
हालाँकि इसका उपयोग शुरू करने के लिए अब आप मूल लाइब्रेरी को स्थापित कर सकते हैं जिसने PEP को प्रेरित किया:
$ 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
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
जब यहां लागू अन्य कार्यान्वयन का उपयोग किया जाता है (मेरे उदाहरण में नामित उदाहरणों का उपयोग करते समय भी) तो आपको यह सुनिश्चित करना चाहिए कि आप कभी भी विभिन्न मल से वस्तुओं की तुलना करने की कोशिश नहीं करते हैं। यहाँ एक संभावित नुकसान के लिए:
>>> 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
ओह!
मुझे वास्तव में एलेक थॉमस का समाधान (http://stackoverflow.com/a/1695250) पसंद है:
def enum(**enums):
'''simple constant "enums"'''
return type('Enum', (object,), enums)
यह सुरुचिपूर्ण और साफ दिख रहा है, लेकिन यह केवल एक फ़ंक्शन है जो निर्दिष्ट विशेषताओं के साथ एक वर्ग बनाता है।
फ़ंक्शन के लिए थोड़ा संशोधन के साथ, हम इसे थोड़ा और अधिक 'एनुमी ’कार्य करने के लिए प्राप्त कर सकते हैं:
नोट: मैंने pygtk की नई शैली 'enums' (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 से प्रकारों के संबंध में अपेक्षा करेंगे। यह बेस क्लास को भी विरासत में मिला है।
उदाहरण के लिए, पूर्णांक एनम:
>>> 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'
PyPI से एनम पैकेज, एनमों का एक मजबूत कार्यान्वयन प्रदान करता है। पहले का उल्लेख पीईपी 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'
एलांडस के लिए क्लास कॉन्स्टेंट का उपयोग करने का अलेक्जेंड्रू का सुझाव काफी अच्छा काम करता है।
मुझे मानव-पठनीय स्ट्रिंग प्रतिनिधित्व देखने के लिए स्थिरांक के प्रत्येक सेट के लिए एक शब्दकोश जोड़ना पसंद है।
यह दो उद्देश्यों को पूरा करता है: ए) यह आपके एनम को सुंदर रूप से प्रिंट करने का एक सरल तरीका प्रदान करता है और बी) शब्दकोश तार्किक रूप से स्थिरांक को समूह बनाता है ताकि आप सदस्यता के लिए परीक्षण कर सकें।
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())
यहाँ कुछ अलग विशेषताओं के साथ एक दृष्टिकोण है जो मुझे मूल्यवान लगता है:
और सबसे महत्वपूर्ण बात यह है कि विभिन्न प्रकार के एनमों के बीच तुलना को रोकता है !
Http://code.activestate.com/recipes/413486-first-class-enums-in-python पर बारीकी से आधारित है ।
इस दृष्टिकोण के बारे में अलग-अलग व्याख्या करने के लिए कई सिद्धांतों को यहाँ शामिल किया गया है।
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',
))
type(class_name, (object,), dict(...))
इसके बजाय बस का उपयोग क्यों नहीं ?
जबकि मूल एनम प्रस्ताव, पीईपी 354 , वर्षों पहले खारिज कर दिया गया था, यह वापस आ रहा है। किसी तरह की एनम को 3.2 में जोड़ने का इरादा था, लेकिन यह 3.3 पर वापस धकेल दिया गया और फिर भूल गया। और अब Python 3.4 में शामिल करने के उद्देश्य से PEP 435 है । PEP 435 का संदर्भ कार्यान्वयन हैflufl.enum
।
अप्रैल 2013 तक, एक आम सहमति प्रतीत होती है कि 3.4 में मानक पुस्तकालय में कुछ जोड़ा जाना चाहिए - जब तक लोग इस बात पर सहमत हो सकते हैं कि "कुछ" क्या होना चाहिए। वह कठिन हिस्सा है। यहां और यहां से शुरू होने वाले धागे देखें , और 2013 के शुरुआती महीनों में आधा दर्जन अन्य धागे।
इस बीच, हर बार यह सामने आता है, PyPI, ActiveState, इत्यादि पर नए डिज़ाइनों और कार्यान्वयनों की एक झलक दिखाई देती है, इसलिए यदि आप FLUFL डिज़ाइन पसंद नहीं करते हैं, तो PyPI खोज आज़माएँ ।
निम्न का उपयोग करें।
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 लग रहा है। यह वास्तव में एक एनम नहीं है, लेकिन यह काम करता है।