मैं पायथन में एक 'एनम' का प्रतिनिधित्व कैसे कर सकता हूं?


1143

मैं मुख्य रूप से C # डेवलपर हूं, लेकिन मैं फिलहाल पायथन में एक प्रोजेक्ट पर काम कर रहा हूं।

मैं पायथन में एक एनम के बराबर का प्रतिनिधित्व कैसे कर सकता हूं?

जवाबों:


2686

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'

1
मुझे समझ में नहीं आ रहा था, उन्होंने विधि एनुम (* अनुक्रमिक, ** नाम) में kwargs (** नाम) पास क्यों किया? कृपया समझाएं। बिना kwargs के भी यह काम करेगा। मैंने इसे जाँचा था।
सीनू एस

पायथन 2 फ़ंक्शन को अद्यतन करने के लिए अच्छा होगा कि पायथन 3 के Enum (नाम, मान) के कार्यात्मक एपीआई के साथ संगत हो
bscan

**namedपुराने संस्करणों के लिए enum फ़ंक्शन में var kwargs ( ) कस्टम मानों का समर्थन करने के लिए है:enum("blue", "red", "green", black=0)
Araric Araujo

822

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

51
नहीं, यह एक वर्ग चर है।
जॉर्ज शॉली

246
पायथन डिफ़ॉल्ट रूप से गतिशील है। पाइथन जैसी भाषा में संकलन-समय सुरक्षा को लागू करने का कोई वैध कारण नहीं है, खासकर जब कोई नहीं है। और एक और बात ... एक अच्छा पैटर्न केवल उस संदर्भ में अच्छा है जिसमें इसे बनाया गया था। आपके द्वारा उपयोग किए जा रहे उपकरणों के आधार पर एक अच्छा पैटर्न भी अलंकृत या पूरी तरह से बेकार हो सकता है।
अलेक्जेंड्रू नेडेल्कू

20
@Longpoke यदि आपके पास 100 मान हैं, तो आप निश्चित रूप से कुछ गलत कर रहे हैं;) मुझे अपने एनम से जुड़े नंबर पसंद हैं ... वे लिखना आसान है (बनाम तार), आसानी से एक डेटाबेस में बनाए रखा जा सकता है, और इसके साथ संगत हैं सी / सी ++ एनुम, जो आसान मार्शिंग के लिए बनाता है।
अलेक्जेंड्रू नेडेल्स्कु

50
मैं इसका उपयोग करता हूं, इसके स्थान पर संख्याओं के साथ object()
तोबू

9
मूल PEP354 अब केवल अस्वीकार नहीं किया गया है, लेकिन अब इसे चिह्नित किया गया है। PEP435 पायथन 3.4 के लिए एक मानक Enum जोड़ता है। देखें python.org/dev/peps/pep-0435
पीटर हैनसेन

321

यहाँ एक कार्यान्वयन है:

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

यहाँ इसका उपयोग है:

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

print(Animals.DOG)

51
अति उत्कृष्ट। ओवरराइड करके इसे और बेहतर बनाया जा सकता है __setattr__(self, name, value)और शायद __delattr__(self, name)इसलिए कि अगर आप गलती से लिखेंगे Animals.DOG = CATतो यह चुपचाप सफल नहीं होगा।
जून १२’११ को

15
@ शहजापान: दिलचस्प, लेकिन अपेक्षाकृत धीमी गति से: प्रत्येक पहुंच के लिए एक परीक्षण किया जाता है जैसे Animals.DOG; इसके अलावा, कॉन्स्टैट्स के मूल्य तार हैं, ताकि इन स्थिरांक के साथ तुलना धीमी हो अगर, मान लें, पूर्णांक को मान के रूप में अनुमति दी गई थी।
एरिक ओ लेबिगॉट

3
@ शहजापान: मेरा तर्क है कि यह समाधान उदाहरण के लिए अलेक्जेंड्रू या मार्क के छोटे समाधानों के समान सुपाठ्य नहीं है। यह एक दिलचस्प समाधान है, हालांकि। :)
एरिक ओ लेबिगॉट

मैंने setattr()कार्यप्रणाली को अधिक __init__()करने के बजाय विधि के अंदर फ़ंक्शन का उपयोग करने का प्रयास किया __getattr__()। मुझे लगता है कि यह उसी तरह काम करने वाला माना जाता है: वर्ग Enum (ऑब्जेक्ट): __init __ (self, enum_string_list): if type (enum_string_list) == सूची: enum_string_list में enum_ring के लिए: setattr (आत्म, enum_string, enum_string) विशेषता
हर्षित JV

8
@ AndréTerra: आप किसी try-exceptब्लॉक में सेट सदस्यता के लिए कैसे जाँच करते हैं ?
11

209

यदि आपको संख्यात्मक मानों की आवश्यकता है, तो यहां सबसे तेज़ तरीका है:

dog, cat, rabbit = range(3)

Python 3.x में आप अंत में एक तारांकित प्लेसहोल्डर भी जोड़ सकते हैं, जो उस श्रेणी के सभी शेष मानों को भिगो देगा, जब आप स्मृति को बर्बाद नहीं करते और न गिन सकते हैं:

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

1
लेकिन यह अधिक स्मृति ले सकता है!
एमजे

मुझे दिए गए तारांकित प्लेसहोल्डर की बात नहीं दिखती है कि पायथन अनपैक करने के लिए मूल्यों की संख्या की जांच करेगा (इसलिए यह आपके लिए गणना करेगा)।
गेब्रियल डेविलर्स

@ गैब्रिएलडेविलर्स, मुझे लगता है कि अगर टुपल में तत्वों की संख्या पर एक बेमेल है तो पायथन अपवाद छोड़ देगा।
मार्क हैरिसन

1
वास्तव में, यह मेरे परीक्षण में होता है (Python2,3) लेकिन इसका मतलब है कि प्रोग्रामर से किसी भी गिनती की गलती को पहले परीक्षण (सही गिनती देने वाले संदेश के साथ) पर पकड़ा जाएगा।
गैब्रियल डेविलर्स

1
मैं गिन नहीं सकता। क्या तारांकित प्लेसहोल्डर मेरे वित्त को भी ठीक कर सकता है?
जावदबा ३१'१

130

आपके लिए सबसे अच्छा समाधान इस बात पर निर्भर करेगा कि आपको अपने नकली से क्या चाहिए 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: पायथन में एन्यूमरेशन में पायथन में एनम के लिए एक प्रस्ताव का दिलचस्प विवरण है और इसे क्यों खारिज कर दिया गया था।


7
आपके साथ rangeपहला तर्क छोड़ सकते हैं यदि यह 0 है
ToonAlfrink

एक और नकली एनम जो कुछ उद्देश्यों के लिए उपयुक्त है 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)]
majkelx

यह सबसे अच्छा जवाब है
यूरी पॉज़्निएक

78

जावा पूर्व-जेडडीके 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

अजगर देव पर हाल ही में एक सूत्र ने बताया कि जंगली में कुछ पुस्तकालय हैं, जिनमें शामिल हैं:


16
मुझे लगता है कि यह बहुत बुरा तरीका है। Animal.DOG = पशु ( "कुत्ता") Animal.DOG2 = पशु ( "कुत्ता") ज़ोर Animal.DOG == Animal.DOG2 में विफल रहता है ...
भ्रम

11
@ कॉन्फ्यूजन उपयोगकर्ता को कंस्ट्रक्टर को कॉल करने के लिए नहीं माना जाता है, यह तथ्य कि एक कंस्ट्रक्टर भी एक कार्यान्वयन विवरण है और आपको यह बताना होगा कि कौन आपके कोड का उपयोग कर रहा है जो नए एन्यूमरेशन मान बनाने से कोई मतलब नहीं है और यह कोड से बाहर नहीं निकलेगा "सही चीज़ करना"। बेशक जो आपको Animal.from_name ("कुत्ता") को लागू करने से नहीं रोकता है -> Animal.DOG।
हारून मेनापा

13
"आपके एनम मूल्यों का लाभ अनजाने में छोटे पूर्णांकों के बराबर नहीं होता है" इसमें क्या फायदा है? अपने एनम की पूर्णांकों से तुलना करने में क्या गलत है? विशेष रूप से यदि आप डेटाबेस में एनम को स्टोर करते हैं, तो आप आमतौर पर इसे पूर्णांक के रूप में संग्रहीत करना चाहते हैं, इसलिए आपको इसकी तुलना किसी बिंदु पर पूर्णांक से करनी होगी।
zबज

3
@ आरोन मेन्पा। सही बात। यह अभी भी एक टूटा हुआ है और इसे करने के लिए जटिल तरीका है।
अपरोनस्टरलिंग

4
@AaronMcSmooth जो वास्तव में इस बात पर निर्भर करता है कि आप "एनुम्स सिर्फ एक जोड़े के लिए नाम हैं" या अधिक ऑब्जेक्ट ओरिएंटेड दृष्टिकोण जहां एनम वैल्यू वास्तविक ऑब्जेक्ट हैं और जिनके तरीके (जावा में कैसे एनम हैं) 1.5 हैं, और जो प्रकार सुरक्षित ईनम पैटर्न के लिए जा रहा था)। व्यक्तिगत रूप से, मुझे स्विच स्टेटमेंट पसंद नहीं हैं इसलिए मैं उन एनम वैल्यू की ओर झुक जाता हूं जो वास्तविक ऑब्जेक्ट हैं।
एरोन मेनेपा

61

एनम वर्ग एक-लाइनर हो सकता है।

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

मुझे लगता है कि यह सबसे सरल अंत सबसे सुरुचिपूर्ण समाधान है। अजगर 2.4 में (हां, पुरानी विरासत सर्वर) ट्यूपल्स इंडेक्स नहीं है। मैंने सूची के साथ प्रतिस्थापित करने का हल किया।
मासिमो

मैंने एक ज्यूपिटर नोटबुक में यह कोशिश की और पता चला कि यह एक-लाइन परिभाषा के रूप में काम नहीं करेगा, लेकिन यह कि गेटएटर की परिभाषा को दूसरी (इंडेंटेड) लाइन पर रखना स्वीकार किया जाएगा।
user5920660

यह समाधान आइए मैं उन inसदस्यों के लिए खोज करने के लिए कीवर्ड का उपयोग करता हूं जो साफ-सुथरे हैं। उदाहरण उपयोग:'Claimed' in Enum(['Unclaimed', 'Claimed'])
फराजाद अब्दोल्होसिनी

51

तो, मैं सहमत हूं। आइए पायथन में प्रकार की सुरक्षा को लागू न करें, लेकिन मैं खुद को मूर्खतापूर्ण गलतियों से बचाना चाहूंगा। तो हम इस बारे में क्या सोचते हैं?

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]

मुझे यह पसंद है, लेकिन एक दक्षता के साथ दक्षता के लिए आप मानों को लॉक कर सकते हैं? मैं इसके साथ चारों ओर खेला और एक संस्करण के साथ आया है कि में आर्ग से सेट self.values init । घोषित करने में सक्षम होना अच्छा है Animal = Enum('horse', 'dog', 'cat')। मैं भी self.values में एक लापता आइटम की स्थिति में getattr में ValueError को पकड़ता हूं - इसके बजाय आपूर्ति किए गए नाम स्ट्रिंग के साथ एक AttributeError को उठाना बेहतर लगता है। मैं उस क्षेत्र में अपने सीमित ज्ञान के आधार पर पायथन 2.7 में काम करने के लिए मेटाक्लस नहीं प्राप्त कर सका, लेकिन मेरा कस्टम एनम वर्ग सीधे उदाहरण के तरीकों से ठीक काम करता है।
trojjer

49

पायथन में एक बिल्ट-इन के बराबर नहीं है enum, और अन्य उत्तरों में आपके स्वयं के कार्यान्वयन के लिए विचार हैं (आप पायथन कुकबुक में शीर्ष संस्करण में भी रुचि ले सकते हैं )।

हालाँकि, ऐसी परिस्थितियों में जहाँ enumC के लिए कॉल किया जाता है, मैं आमतौर पर सिंपल स्ट्रिंग्स का उपयोग करके समाप्त होता हूँ : जिस तरह से ऑब्जेक्ट्स / विशेषताओं को लागू किया जाता है, (C) वैसे भी शॉर्ट स्ट्रिंग्स के साथ पायथन को बहुत तेज़ी से काम करने के लिए अनुकूलित किया जाता है, इसलिए पूर्णांक का उपयोग करने के लिए वास्तव में कोई प्रदर्शन लाभ नहीं होगा। टाइपो / अमान्य मानों से बचाव के लिए आप चयनित स्थानों में चेक डाल सकते हैं।

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

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

(एक वर्ग का उपयोग करने की तुलना में एक नुकसान यह है कि आप स्वत: पूर्ण का लाभ खो देते हैं)


2
मैं इस समाधान को पसंद करता हूं। मुझे जहाँ संभव हो बिल्ट-इन प्रकारों का उपयोग करना पसंद है।
Seun Osewa

वह संस्करण वास्तव में शीर्ष पर नहीं है। यह सिर्फ आपूर्ति परीक्षण कोड
Casebash

1
दरअसल, "सही" संस्करण टिप्पणियों में है और बहुत अधिक जटिल है - मुख्य संस्करण में एक मामूली बग है।
केसबश

38

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

अधिक जानकारी के लिए , प्रस्ताव देखें । आधिकारिक प्रलेखन शायद जल्द ही पालन करेंगे।


33

मैं इस तरह से अजगर में शत्रुओं को परिभाषित करना पसंद करता हूं:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

पूर्णांक का उपयोग करने की तुलना में यह अधिक बग-प्रूफ है क्योंकि आपको यह सुनिश्चित करने के बारे में चिंता करने की आवश्यकता नहीं है कि पूर्णांक अद्वितीय हैं (जैसे यदि आपने कहा कि कुत्ता = 1 और बिल्ली = 1 आप खराब हो जाएंगे)।

यह स्ट्रिंग्स का उपयोग करने की तुलना में अधिक बग-प्रूफ है क्योंकि आपको टाइपोस के बारे में चिंता करने की ज़रूरत नहीं है (जैसे x == "catt" चुपचाप विफल रहता है, लेकिन x == Animal.Catt एक रनटाइम अपवाद है)।


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

11
IMHO यह क्लीनर होगा यदि आप बदल enum(names)गए enum(*names)- तो आप इसे कॉल करते समय अतिरिक्त कोष्ठक छोड़ सकते हैं।
क्रिस लुट्ज़

मुझे यह तरीका पसंद है। मैंने वास्तव में नाम के समान स्ट्रिंग के लिए विशेषता मान सेट करने के लिए इसे बदल दिया, जिसमें अच्छी संपत्ति है जो Animal.DOG == 'DOG' है, इसलिए वे अपने आप को आपके लिए स्वचालित रूप से स्ट्रिंग करते हैं। (डिबग आउटपुट को प्रिंट करने के लिए बहुत मदद करता है।)
टेड माइलकरेक

22

हममम ... मुझे लगता है कि एक एनुम के लिए निकटतम बात एक शब्दकोश होगी, इस तरह से परिभाषित:

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

या

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

फिर, आप इस तरह से स्थिरांक के लिए प्रतीकात्मक नाम का उपयोग कर सकते हैं:

mymonth = months['January']

अन्य विकल्प हैं, जैसे टुपल्स की सूची, या टुपल्स का एक टपल, लेकिन शब्दकोश एकमात्र ऐसा है जो आपको मूल्य तक पहुंचने के लिए "प्रतीकात्मक" (निरंतर स्ट्रिंग) तरीका प्रदान करता है।

संपादित करें: मुझे अलेक्जेंड्रू का जवाब भी पसंद है!


और अगर आप कॉम्बो बॉक्स आइटम के रूप में प्रदर्शित करने के लिए इसके स्ट्रिंग मूल्यों की आवश्यकता है, तो आप सबसे आसानी से एक शब्दकोश पर पुनरावृति कर सकते हैं। तो इसके बजाय गणना के लिए एक प्रतिस्थापन के रूप में एक शब्दकोश का उपयोग करें।
लेम्यूएल एडाने

22

एक और, बहुत ही सरल, पायथन में एक एनम का कार्यान्वयन, का उपयोग करते हुए 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

जैसा कि अपेक्षित है यदि आप उस संस्करण का उपयोग करते हैं जो क्रमिक संख्या मानों में भरता है।


22

पायथन 3.4 से, एनम के लिए आधिकारिक समर्थन मिलेगा। आप Python 3.4 प्रलेखन पृष्ठ पर प्रलेखन और उदाहरण पा सकते हैं ।

Enumerations को क्लास सिंटैक्स का उपयोग करके बनाया जाता है, जिससे उन्हें पढ़ना और लिखना आसान हो जाता है। एक वैकल्पिक निर्माण विधि कार्यात्मक एपीआई में वर्णित है। एन्यूमरेशन को परिभाषित करने के लिए, एनक्लेम को निम्न प्रकार से लिखें:

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

बैक पोर्टिंग अब भी समर्थित है। जाने का यह रास्ता है।
Srock

20

मैं क्या उपयोग करता हूं:

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 मॉडल में विकल्प के रूप में उपयोग करने के लिए।


17

davidg dicts का उपयोग करने की सलाह देता है। मैं एक कदम आगे और सेट का उपयोग करूँगा:

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

अब आप परीक्षण कर सकते हैं कि क्या मूल्य इस तरह से सेट में मौजूद मूल्यों में से एक से मेल खाता है:

if m in months:

हालांकि, डीएफ की तरह, मैं आमतौर पर केवल एनम के स्थान पर स्ट्रिंग स्थिरांक का उपयोग करता हूं।


हाँ !, बहुत अच्छा है अगर आप यू इनहेरिट सेट करते हैं और गेटैट विधि प्रदान करते हैं !
शजापान

16

यह मैंने देखा सबसे अच्छा है: "पायथन में प्रथम श्रेणी के एनम"

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)

इस नुस्खा का उपयोग पीईपी के लिए आधार के रूप में किया गया था, जिसे अस्वीकार कर दिया गया था। python.org/dev/peps/pep-0354 एक विस्तार जो मुझे पसंद है: enum मानों का एक सदस्य चर होना चाहिए जो आपको आंतरिक पूर्णांक मान प्राप्त करने देता है। गलती से एक एनम को पूर्णांक में डालना संभव नहीं होना चाहिए, इसलिए .__int__()विधि को एनम के लिए एक अपवाद उठाना चाहिए; लेकिन मूल्य को बाहर निकालने का एक तरीका होना चाहिए। और वर्ग परिभाषा समय पर विशिष्ट पूर्णांक मान सेट करना संभव होना चाहिए, ताकि आप statमॉड्यूल में स्थिरांक जैसी चीजों के लिए एक एनुम का उपयोग कर सकें ।
स्टीवेहा

16

इसे सरल रखें:

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

13

बाइनरी फ़ाइल फॉर्मेट को डिकोड करने के उद्देश्य से मुझे एनम वर्ग की आवश्यकता होती है। मुझे जो सुविधाएँ चाहिए 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

मुझे वास्तव में अपने स्वयं के मेटाक्लास के साथ एक सुपरक्लास का उपयोग करना पसंद है, जिससे कि एनम को परिभाषित करना आसान हो। यहाँ क्या याद आ रहा है एक __contains__ विधि है। मैं यह जांचने में सक्षम होना चाहता हूं कि एक दिया गया वैरिएबल एनम का हिस्सा है - ज्यादातर क्योंकि मैं एक फंक्शन पैरामीटर के स्वीकार्य मूल्यों के लिए एंम्स चाहता हूं।
xorsyst

यह वास्तव में मेरे द्वारा बनाए गए मूल रूप से थोड़ा छंटनी वाला संस्करण है (जिसे आप यहां पा सकते हैं: enum_strict.py ) v जो एक __instancecheck__विधि को परिभाषित करता है । कक्षाएं उदाहरणों का संग्रह नहीं हैं, इसलिए 1 in Fruitबेतुका है। हालांकि, लिंक किए गए संस्करण का समर्थन करता है isinstance(1, Fruit)जो वर्गों और उदाहरणों की धारणा के संदर्भ में अधिक सही होगा।
एकलकरण २१

लेकिन कक्षाओं और विसंगतियों के संदर्भ में सोचना भूल जाते हैं, तो यह उनके लिए एक संग्रह के रूप में सोचने के लिए समझ में आता है। उदाहरण के लिए, मेरे पास फ़ाइल खोलने के तरीके (MODE.OPEN, MODE.WRITE, आदि) हो सकता है। मैं अपने फ़ंक्शन के मापदंडों को सत्यापित करना चाहता हूं: अगर मोड में मोड: आइंटेंस (मोड, मोड) की
xorsyst

मैंने बहुत कुछ समान रखा है, जो सिर्फ ints से अधिक समर्थन करता है, और GitHub पर प्रलेखित और परीक्षण किया गया है: github.com/hmeine/onym_constants
hans_meine

11

पायथन में नया मानक 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

10
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

ओह!


9

मुझे वास्तव में एलेक थॉमस का समाधान (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'

यह "आधार" प्रकार का विचार साफ
सुथरा है

हाँ, ध्यान दें कि आप नए पायथन 3.4 Enum के साथ भी ऐसा कर सकते हैं: python.org/dev/peps/pep-0435/#other-derived-enumerations
bj0

7

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'

5

एलांडस के लिए क्लास कॉन्स्टेंट का उपयोग करने का अलेक्जेंड्रू का सुझाव काफी अच्छा काम करता है।

मुझे मानव-पठनीय स्ट्रिंग प्रतिनिधित्व देखने के लिए स्थिरांक के प्रत्येक सेट के लिए एक शब्दकोश जोड़ना पसंद है।

यह दो उद्देश्यों को पूरा करता है: ए) यह आपके एनम को सुंदर रूप से प्रिंट करने का एक सरल तरीका प्रदान करता है और बी) शब्दकोश तार्किक रूप से स्थिरांक को समूह बनाता है ताकि आप सदस्यता के लिए परीक्षण कर सकें।

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

4

यहाँ कुछ अलग विशेषताओं के साथ एक दृष्टिकोण है जो मुझे मूल्यवान लगता है:

  • अनुमति देता है> और <enum में आदेश के आधार पर तुलना, शाब्दिक आदेश नहीं
  • आइटम को नाम, संपत्ति या सूचकांक से संबोधित कर सकते हैं: xa, x ['a'] या x [०]
  • [:] या [-1] जैसे स्लाइसिंग ऑपरेशन का समर्थन करता है

और सबसे महत्वपूर्ण बात यह है कि विभिन्न प्रकार के एनमों के बीच तुलना को रोकता है !

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


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

2
यह कक्षाएं बनाने का एक बहुत पुराना तरीका है। type(class_name, (object,), dict(...))इसके बजाय बस का उपयोग क्यों नहीं ?
टर्मिनस

3

जबकि मूल एनम प्रस्ताव, पीईपी 354 , वर्षों पहले खारिज कर दिया गया था, यह वापस आ रहा है। किसी तरह की एनम को 3.2 में जोड़ने का इरादा था, लेकिन यह 3.3 पर वापस धकेल दिया गया और फिर भूल गया। और अब Python 3.4 में शामिल करने के उद्देश्य से PEP 435 है । PEP 435 का संदर्भ कार्यान्वयन हैflufl.enum

अप्रैल 2013 तक, एक आम सहमति प्रतीत होती है कि 3.4 में मानक पुस्तकालय में कुछ जोड़ा जाना चाहिए - जब तक लोग इस बात पर सहमत हो सकते हैं कि "कुछ" क्या होना चाहिए। वह कठिन हिस्सा है। यहां और यहां से शुरू होने वाले धागे देखें , और 2013 के शुरुआती महीनों में आधा दर्जन अन्य धागे।

इस बीच, हर बार यह सामने आता है, PyPI, ActiveState, इत्यादि पर नए डिज़ाइनों और कार्यान्वयनों की एक झलक दिखाई देती है, इसलिए यदि आप FLUFL डिज़ाइन पसंद नहीं करते हैं, तो PyPI खोज आज़माएँ


3

निम्न का उपयोग करें।

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 लग रहा है। यह वास्तव में एक एनम नहीं है, लेकिन यह काम करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.