2012-02-29 13 views
28

संभव डुप्लिकेट:
What's the best way to implement an 'enum' in Python?बूलियन के दो संभावित मूल्य हैं। क्या ऐसे तीन प्रकार हैं जिनके पास तीन संभावित मूल्य हैं?

मैं एक समारोह है कि, आदर्श, मैं तीन राज्यों में से एक वापस आना चाहते हैं लिख रहा हूँ: "हाँ", "नहीं", और "पता नहीं"।

  1. क्या किसी भी प्रोग्रामिंग भाषा में एक प्रकार है जिसमें तीन और तीन राज्य हैं? एक बुलियन की तरह, लेकिन दो के बजाय तीन राज्यों के साथ?

  2. ऐसी भाषाओं में जिनके पास ऐसा कोई प्रकार नहीं है (जैसे पायथन), इसका प्रतिनिधित्व करने का सबसे अच्छा तरीका क्या है?

    वर्तमान में मुझे लगता है कि मैं एक पूर्णांक के साथ जाना होगा ("नहीं" के लिए 0, "पता नहीं है" के लिए 1 और "हाँ" के लिए 2), लेकिन शायद वहाँ एक बेहतर तरीका है? इंटीग्रर्स थोड़ा "जादू संख्या" लगते हैं।

    मैं True, False या None, लौट सकता है, लेकिन के रूप में None सबसे तुलना संदर्भों में False का मूल्यांकन होगा यह त्रुटियों के लिए थोड़ा परिपक्व लगता है।

+2

यह प्रासंगिक हो सकता है: http://stackoverflow.com/questions/36932/whats-the-best-way-to-implement-an-enum-in-python – Owen

+2

इस प्रश्न के समान, है ना? http://stackoverflow.com/questions/36932/whats-the-best-way-to-implement-an-enum-in-python –

+0

@ जोहान्सवेस: काफी संभवतः - मेरे पास सी पृष्ठभूमि नहीं है, और मैं ' मैं enums की अवधारणा से परिचित नहीं हूँ। अच्छा लगता है, चीयर्स। –

उत्तर

24

अजगर में मुझे क्या करना चाहते हैं कि एक आवरण उद्देश्य यह है कि उन तीन में से एक मान रखती है के साथ; मैं True, False, और None का उपयोग करता हूं। चूंकि तीन संभव मूल्यों के साथ एक बूलियन-जैसी वस्तु का अंतर्निहित सच्चाई मूल्य समस्याग्रस्त है, हम इसे से हल कर देंगे जो पूरी तरह से (__nonzero__() में अपवाद उठा रहा है, या पायथन 3, __bool__() में), इस प्रकार तुलना की आवश्यकता है कि तुलना हमेशा in, ==, या != का उपयोग करके स्पष्ट रूप से किया गया। हम समानता को पहचान के रूप में लागू करेंगे ताकि केवल विशिष्ट सिंगलटन मान True, False, और None मिलान किए जाएं।

class Tristate(object): 

    def __init__(self, value=None): 
     if any(value is v for v in (True, False, None)): 
      self.value = value 
     else: 
      raise ValueError("Tristate value must be True, False, or None") 

    def __eq__(self, other): 
     return (self.value is other.value if isinstance(other, Tristate) 
       else self.value is other) 

    def __ne__(self, other): 
     return not self == other 

    def __nonzero__(self): # Python 3: __bool__() 
     raise TypeError("Tristate object may not be used as a Boolean") 

    def __str__(self): 
     return str(self.value) 

    def __repr__(self): 
     return "Tristate(%s)" % self.value 

उपयोग:

t = Tristate(True) 
t == True   # True 
t != False   # True 
t in (True, False) # True 
bool(t)    # Exception! 
if t: print "woo" # Exception! 

Tristate वस्तुओं का उपयोग करते समय, आप स्पष्ट रूप से निर्दिष्ट करनी होगी, जो मैच के लिए महत्व देता है अर्थात foo == True or bar != None। आप कई मानों से मेल खाने के लिए foo in (False, None) भी कर सकते हैं (हालांकि निश्चित रूप से in दो मान एक ही मान के साथ != के विपरीत है)। यदि अन्य तर्क संचालन हैं जो आप इन वस्तुओं के साथ प्रदर्शन करने में सक्षम होना चाहते हैं, तो आप इन्हें विधियों के रूप में लागू कर सकते हैं, या संभवतः कुछ ऑपरेटरों को ओवरराइड करके (दुर्भाग्य से, तार्किक not, and, और or ओवरराइड करने योग्य नहीं हैं, हालांकि a proposal है उसमें जोड़ें)।

यह भी ध्यान रखें कि आप पाइथन में id() ओवरराइड नहीं कर सकते हैं, उदाहरण के लिए Tristate(None) is NoneFalse है; दो वस्तुओं वास्तव में अलग हैं। चूंकि सिंगल के खिलाफ तुलना करते समय अच्छी पायथन शैली is का उपयोग करना है, यह दुर्भाग्यपूर्ण है, लेकिन अपरिहार्य है।

संपादित करें 4/27/16: एक Tristate ऑब्जेक्ट की तुलना किसी अन्य पर तुलना करने के लिए समर्थन जोड़ा गया।

+0

@ PaulD.Waite मैं पूछने जा रहा था कि अस्वीकार्य क्यों है, लेकिन यह स्पष्ट है कि क्यों। – Marcin

+0

@ मार्सिन: निश्चित रूप से, क्षमा करें अगर मैंने कोई अपराध किया - यह उत्तर अनिवार्य रूप से आपके जैसा ही है (उदाहरण के लिए कोड और बूलियन तुलना की चर्चा के साथ। मैंने अतिरिक्त विवरण को स्वीकृति के लायक बना दिया। –

+0

@ PaulD.Waite नहीं, कोई अपराध नहीं लिया गया - यह उत्तर स्पष्ट रूप से बहुत अधिक है, और इस मुद्दे के पहलुओं को संबोधित करता है जिनके बारे में मैंने भी सोचा नहीं था। – Marcin

2

इसे आम तौर पर उस नाम के सी निर्माण के बाद 'enum' के रूप में जाना जाता है।

आप आसानी से अपनी खुद की कक्षा बना सकते हैं, जिनकी वस्तुओं को सेट से मूल्यों के साथ प्रारंभ किया जाना चाहिए, और आप तदनुसार उचित तुलना, समानता और सत्य कार्य बना सकते हैं।

+1

टर्नरी तर्क एक enum के समान नहीं है। –

+1

@EthanFurman: यह सच है, लेकिन नहीं, मुझे प्रासंगिक लगता है। – Marcin

0

ऐसे कोई भी अंतर्निहित प्रकार नहीं हैं। और enum भी एक प्रकार के रूप में समर्थित नहीं हैं। हालांकि, अगर आप उपयोग कर सकते हैं निरंतर रूप में:

class Option: 
    NO = 0 
    DONT_KNOW = 1 
    YES = 2 

reply = Option.YES 
+0

ध्यान दें कि यह एक enum के समान नहीं है। – Marcin

+0

कार्यान्वयन की तरह एक enum के लिए आप http://stackoverflow.com/a/1695250 –

+0

का उल्लेख कर सकते हैं यह आपके उदाहरण के समान ही सी enum के विपरीत है। – Marcin

0

मैं एक अजगर प्रोग्रामिंग की ज्यादा नहीं हूँ, लेकिन तुम वापस में कोई भी पता नहीं मामले सकता है। कॉलर को "हां", "नहीं" या कोई नहीं देखना होगा, लेकिन कम से कम वे जानते होंगे कि आप नहीं जानते हैं।

http://boodebr.org/main/python/tourist/none-empty-nothing

6

यह Ternary logic या थ्री-वैल्यूड लॉजिक कहा जाता है। अन्य उत्तर का सुझाव के रूप में, आप या तो एक वर्ग को लागू कर सकते हैं:

class Ternary: 
    FALSE = 0 
    TRUE = 1 
    UNKNOWN = 2 

मैं स्वयं, मैं शायद अपने समाधान के लिए जाना होगा (True, False, None), लेकिन मैं आपकी चिंता को समझते हैं।

0

मैंने कभी भी एक प्रकार का बूलियन जैसा नहीं देखा जिसमें दो से अधिक मूल्य थे। सभी "बूलियन" का अर्थ है कि फ़ंक्शन "बूलियन डोमेन" पर काम करता है, जिसके बदले में वास्तव में 2 मान होते हैं।

ने कहा, यह पूर्णांक, enums, या यहां तक ​​कि तारों का उपयोग करने के लिए बिल्कुल ठीक है। पायथन में आप एक मॉड्यूल बना सकते हैं जिसमें केवल वेरिएबल हैं, हाँ, मई, और वहां से अन्य सभी जगहों पर आयात करें।C#:

2
  1. कम से कम एक भाषा इस है int? num = null;, अब num वास्तव में Nullable<Int32> है (प्रश्न चिह्न एक "वाक्यात्मक चीनी" है) देखें: http://msdn.microsoft.com/en-us/library/1t3y8s4s%28v=vs.80%29.aspx और http://en.wikipedia.org/wiki/Nullable_type
  2. अजगर पता नहीं है, लेकिन यह आपकी पसंद पर निर्भर करता है: प्रयोज्य (enum या class) बनाम दक्षता (4 बिट क्षेत्रों)
5

कोई भी समस्या के समानांतर झूठी = 0, सच के साथ मौजूद है = 1, अज्ञात = 2 (अज्ञात है वास्तव में सच भी नहीं है, लेकिन यदि आप सावधान नहीं हैं तो सच साबित होंगे)।

मैं एक hackish तरीका कुछ कम से कम का अनुमान लगाती है कि आप क्या चाहते हैं, मुझे लगता है कि प्राप्त करने के लिए के साथ आया था। यह कम से कम आपको कुछ ऐसा मिलेगा जो एक ट्रिनरी फैशन में मूल्यांकन करेगा यदि/else और अन्य बूलियन eval उदाहरणों में।

class Yes(object): 
    def __nonzero__(self): 
     return True 

class No(object): 
    def __nonzero__(self): 
     return False 

class Unknown(object): 
    def __nonzero__(self): 
     raise ValueError('Unknown typed values do not evaluate to True/False. Try using Ternary.eval().') 

class Ternary(object): 
    def __init__(self, yes, no, unknown): 
     setattr(self, yes, Yes()) 
     setattr(self, no, No()) 
     setattr(self, unknown, Unknown()) 
    @staticmethod 
    def eval(value, unknown_eval): 
     if isinstance(value, Unknown): 
      return unknown_eval 
     return bool(value) 

उपयोग:

t = Ternary('yes', 'no', 'unknown') 
# Do stuff to assign ternary value to x 
if Ternary.eval(x, True): 
    print 'x is yes or unknown' 
if Ternary.eval(x, False): 
    print 'x is yes only' 

आप नहीं है, हाँ कर सकता है, और अज्ञात छद्म एकमात्र जो आप eval एक छोटा सा परिशोधित कर सकते हैं होगा। यदि आप जानते हैं कि आपका मान हाँ या नहीं होने पर जांचता है तो आप अभी भी सरल कर सकते हैं, लेकिन यदि आपने अज्ञात पर सीधे बूल() यानी x) करने का प्रयास किया है तो आपको टाइप एरर मिल जाएगा। यह आपके कोड अधिक स्पष्ट हो जाएगा हालांकि, हर बार जब आप trinary प्रकार के एक मूल्य की जाँच के रूप में, आप अपने कोड में परिभाषित करने के लिए कैसे आप अज्ञात है कि सशर्त के संदर्भ में इलाज किया जा करना चाहता था होगा, ताकि एक प्लस होगा ।

संपादित करें: मैं एक विकल्प है कि कम विशेष हैंडलिंग लेकिन कम सुविधाजनक की आवश्यकता होगी के बारे में सोचा। thusly ऊपर बदलें:

class Unknown(object): 
    def __init__(self, eval): 
     self._eval = eval 
    def __nonzero__(self): 
     return self._eval 

class Ternary(object): 
    def __init__(self, yes, no, unknown, unknown_eval): 
     setattr(self, yes, Yes()) 
     setattr(self, no, No()) 
     setattr(self, unknown, Unknown(unknown_eval)) 

उपयोग:

t1 = Ternary('yes', 'no', 'unknown', True) 
t2 = Ternary('yes', 'no', 'unknown', False) 
# Do stuff to assign ternary values to x1 and x2 
if x1: 
    print 'x is yes or unknown' 
if x2: 
    print 'x is yes only' 

यह अज्ञात में के लिए कल्पना के रूप में कॉल काम करने के लिए अनुमति देता है अशून्य को लाभ मिलता है, लेकिन यह पत्थर में अज्ञात सेट के लिए eval होने के नकारात्मक पक्ष यह है तत्काल से और अज्ञात को छद्म-सिंगलटन होने की अनुमति नहीं दे रहा है।

+0

'__nonzero__' को 'बूल' या' int 'वापस करना होगा - किसी को भी अनुमति नहीं है। –

+0

@ ईथन फर्मन, और इसलिए मैंने कई बार क्यों इंगित किया कि यह कल्पना को पूरा नहीं करता है। और मैंने नीचे दिए गए विकल्प को क्यों प्रदान किया। क्या आपके पास जोड़ने के लिए नई जानकारी है? –

+0

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

1

मैं अपने dbf module में एक 3-मान तार्किक वर्ग की है।

यह False/True/Unknown सिंगलटन मूल्यों Falsth/Truth/Unknown के रूप में लागू करता है। यह सब तुलना ऑपरेटरों को लागू करता है, और यह भी अजगर एकमात्र False/True/None (None अज्ञात मतलब करने के लिए लिया गया) के साथ तुलना की अनुमति देता है। Unknown में एक Unknown मूल्य परिणामों के साथ किसी भी तुलना, और परोक्ष एक if बयान (या अन्य bool संदर्भ) में एक Unknown मान का उपयोग करने की कोशिश एक TypeError बढ़ा देंगे, हालांकि Truth और Falsth बूलियन संदर्भों में इस्तेमाल किया जा सकता है, और Unknown तुलना की जा सकती सीधे के खिलाफ।

क्योंकि यह संभव and, or, और not व्यवहार प्रकार ओवरराइड करता है बिटवाइज़ ऑपरेटर्स &, |, और ~ ओवरराइड करने के लिए नहीं है।

यह __index__ को Unknown के साथ 2 के मान के साथ लागू करता है।

उदाहरण:

from dbf import Logical, Truth, Falsth, Unknown 

middle_name = raw_input("What is the middle name? ['?' if unknown] ").strip() 
if middle_name == '?': 
    middle_name = '' 
    middle_exists = Unknown 
elif middle_name: 
    middle_exists = Truth 
else: 
    middle_exists = Falsth 
. 
. 
. 
if middle_exists is Unknown: 
    print "The middle name is unknown." 
elif middle_exists: 
    print "The middle name is %s." % middle_name 
else: 
    print "This person does not have a middle name." 
संबंधित मुद्दे