पायथन में स्विच स्टेटमेंट के लिए प्रतिस्थापन?


1718

मैं पायथन में एक फ़ंक्शन लिखना चाहता हूं जो एक इनपुट इंडेक्स के मूल्य के आधार पर विभिन्न निश्चित मान लौटाता है।

अन्य भाषाओं में मैं एक switchया caseकथन का उपयोग करूंगा , लेकिन पायथन का switchकथन नहीं है। इस परिदृश्य में अनुशंसित पायथन समाधान क्या हैं?


77
संबंधित PEP, स्वयं Guido द्वारा लिखित: PEP 3103
chb

28
@ पीबी उस पीईपी में, गुइडो का उल्लेख नहीं है कि अगर / एलिफ चेन भी त्रुटि का एक क्लासिक स्रोत हैं। यह बहुत ही नाजुक निर्माण है।
इसका कर्क

15
यहां सभी समाधानों से गायब डुप्लिकेट केस वैल्यू का पता लगा रहा है । असफल-तेज़ सिद्धांत के रूप में, यह प्रदर्शन या गिरावट की विशेषता से अधिक महत्वपूर्ण नुकसान हो सकता है।
बॉब स्टीन

6
switchवास्तव में अधिक "बहुमुखी" है जो इनपुट इंडेक्स के मूल्य के आधार पर विभिन्न निश्चित मानों को लौटाता है। यह कोड के विभिन्न टुकड़ों को निष्पादित करने की अनुमति देता है। यह वास्तव में एक मूल्य वापस करने की भी आवश्यकता नहीं है। मुझे आश्चर्य है कि यदि यहां कुछ उत्तर सामान्य switchकथन के लिए अच्छे प्रतिस्थापन हैं , या केवल कोड के सामान्य टुकड़ों को निष्पादित करने की कोई संभावना नहीं के साथ लौटने के मामले के लिए।
sancho.s ReinstateMonicaCellio

3
@ MalikA.Rumi फ्रैगाइल निर्माण, जैसे ही कुछ समय के लिए लूप एक नाजुक निर्माण होता है यदि आप इसका उपयोग करने की कोशिश करते हैं तो ... के लिए ... करता है। क्या आप लूप के उपयोग के लिए प्रोग्रामर को कमजोर कहने जा रहे हैं? जबकि छोरों वे सब वास्तव में जरूरत है। लेकिन लूप स्पष्ट इरादे दिखाते हैं, व्यर्थ बॉयलरप्लेट को बचाते हैं और शक्तिशाली सार बनाने का अवसर देते हैं।
6

जवाबों:


1486

आप एक शब्दकोश का उपयोग कर सकते हैं:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]

99
यदि x नहीं मिला तो क्या होगा?
निक

46
@nick: आप डिफाल्ट का उपयोग कर सकते हैं
एली

384
अगर प्रदर्शन एक मुद्दा है, तो मैं फ़ंक्शन के बाहर हुक लगाने की सलाह दूंगा, इसलिए यह हर फ़ंक्शन कॉल पर तानाशाही को फिर से नहीं बनाता है
क्लाउडी

56
@EliBendersky, getविधि का उपयोग करना शायद collections.defaultdictइस मामले में उपयोग करने की तुलना में अधिक सामान्य होगा ।
माइक ग्राहम

27
@ क्लिक करें, }.get(x, default)यदि कोई डिफ़ॉल्ट होना चाहिए, तो इसके बजाय एक अपवाद है । (नोट: यदि आप एक स्विच स्टेटमेंट से डिफॉल्ट को छोड़ देते हैं तो यह बहुत अच्छा होता है!)
माइक ग्राहम

1375

यदि आप डिफॉल्ट चाहते हैं तो आप डिक्शनरी get(key[, default])विधि का उपयोग कर सकते हैं :

def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 is default if x not found

11
क्या होगा अगर 'a' और 'b' मैच 1, और 'c' और 'd' मैच 2?
जॉन मी

13
@ जेएम: ठीक है, जाहिर है शब्दकोश लुक अप-थ्रू का समर्थन नहीं करते हैं। आप एक डबल डिक्शनरी लुकअप कर सकते हैं। Ie 'a' और 'b' उत्तर answer1 और 'c' और 'd' बिंदु से उत्तर 2 तक आते हैं, जो एक दूसरे शब्दकोश में समाहित हैं।
निक

3
यह डिफ़ॉल्ट मान पारित करने के लिए बेहतर है
HaTiMSuM

इस दृष्टिकोण के साथ एक समस्या है, पहली बार जब आप फोन करते हैं तो आप फिर से दूसरा बनाने जा रहे हैं यदि आपके पास अधिक जटिल मूल्य है तो आप एक अपवाद प्राप्त कर सकते हैं। यदि x एक टुपल है और हम इस x = ('a') डी f (x): रिटर्न {'a': x [0], 'b': x [1] .get] जैसे कुछ करना चाहते हैं। x [0], 9) यह IndexError
Idan Haim Shalom

2
@ इदान: सवाल स्विच को दोहराने का था। मुझे यकीन है कि मैं इस कोड को भी तोड़ सकता हूं अगर मैंने विषम मूल्यों में डालने की कोशिश की। हां, यह पुनः बनाएगा, लेकिन इसे ठीक करना सरल है।
निक

394

मैंने हमेशा इसे इस तरह से करना पसंद किया है

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}[value](x)

यहां से


16
महान विधि, डिफ़ॉल्ट को संभालने के लिए () के साथ संयुक्त मेरा सबसे अच्छा विकल्प भी है
drAlberT

27
शायद इस मामले में लैम्ब्डा का उपयोग करना एक अच्छा विचार नहीं है क्योंकि लैम्बडा को वास्तव में हर बार डिक्शनरी बनाने के लिए कहा जाता है।
अशर

13
अफसोस की बात है कि यह सबसे करीबी लोगों को मिलने वाला है। जो तरीके .get()(वर्तमान उच्चतम उत्तरों की तरह) उपयोग करते हैं उन्हें डिस्पैच करने से पहले सभी संभावनाओं का बेसब्री से मूल्यांकन करने की आवश्यकता होगी, और इसलिए न केवल (न केवल बहुत बल्कि) बेहद अक्षम हैं और इसके दुष्प्रभाव भी नहीं हो सकते हैं; यह उत्तर उस मुद्दे के आसपास मिलता है, लेकिन अधिक क्रिया है। मैं सिर्फ अगर / elif / और, और यहां तक ​​कि उन लोगों को 'केस' के रूप में लिखने के लिए उपयोग करूंगा।
नवजागेको

13
क्या यह सभी मामलों में हर समय सभी कार्यों / लंबो का मूल्यांकन नहीं करेगा, भले ही यह केवल परिणामों में से एक हो?
19

23
@ शेल्फ नहीं, जब नियंत्रण प्रवाह कोड के उस टुकड़े तक पहुंचता है, तो यह 3 फ़ंक्शन (3 लैम्ब्डा के उपयोग के माध्यम से) का निर्माण करेगा और फिर मानों के रूप में उन 3 कार्यों के साथ एक शब्दकोश का निर्माण करेगा, लेकिन वे बिना रुके रहते हैं ( मूल्यांकन थोड़ा अस्पष्ट है) वह प्रसंग) सबसे पहले। तब शब्दकोश को अनुक्रमित किया जाता है [value], जो 3 कार्यों में से केवल एक को वापस करेगा (यह मानते हुए valueकि 3 कुंजी में से एक है)। फ़ंक्शन को उस बिंदु पर नहीं बुलाया गया है, फिर भी। तब तर्क के रूप (x)में बस लौटे फ़ंक्शन को कॉल करें x(और परिणाम जाता है result)। अन्य 2 कार्यों को नहीं बुलाया जाएगा।
ब्लबरडाइब्लूब

353

शब्दकोश विधियों के अलावा (जो मुझे वास्तव में पसंद है, बीटीडब्लू), आप प्राप्त करने के लिए if- elif- elseका भी उपयोग कर सकते हैंswitch / case/ defaultकार्यक्षमता:

if x == 'a':
    # Do the thing
elif x == 'b':
    # Do the other thing
if x in 'bc':
    # Fall-through by not using elif, but now the default case includes case 'a'!
elif x in 'xyz':
    # Do yet another thing
else:
    # Do the default

यह पाठ्यक्रम स्विच / केस के समान नहीं है - आप breakकथन को छोड़ते हुए आसानी से गिर नहीं सकते , लेकिन आपके पास अधिक जटिल परीक्षण हो सकता है। इसके स्वरूपण नेस्टेड ifएस की एक श्रृंखला की तुलना में अच्छे हैं , भले ही कार्यात्मक रूप से यह करीब है।


51
मैं वास्तव में इसे पसंद करूंगा, यह एक standart भाषा के निर्माण का उपयोग करता है और यदि कोई मिलान वाला मामला नहीं मिलता है, तो KeyError को फेंक नहीं देता है
martyglaubitz

7
मैंने शब्दकोश / getरास्ते के बारे में सोचा , लेकिन मानक तरीका बस अधिक पठनीय है।
मार्टिन थोमा

2
@someuser लेकिन तथ्य यह है कि वे "ओवरलैप" कर सकते हैं एक विशेषता है। आप सिर्फ यह सुनिश्चित करें कि ऑर्डर प्राथमिकता है जिसमें मैच होने चाहिए। दोहराया x के लिए: बस एक x = the.other.thingसे पहले करते हैं। आमतौर पर, आपके पास एक एकल होगा, यदि कई एलिफ और एक एकल, जैसा कि समझना आसान है।
मैथ्यू Schinckel

7
हालांकि, "फॉल-थ्रू बाय एलिफ का उपयोग नहीं करना" थोड़ा भ्रामक है, हालांकि। इस बारे में क्या: "के माध्यम से गिर" के बारे में भूल जाओ और बस इसे दो के रूप में स्वीकार करते हैं if/elif/else?
एलोइस महदाल

7
यह भी ध्यान देने योग्य बात है x in 'bc', जैसे चीजों का उपयोग करते समय , ध्यान रखें कि "" in "bc"है True
लोहमर एएसएचआर

185

स्विच / केस के लिए मेरा पसंदीदा पायथन नुस्खा है:

choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')

सरल परिदृश्यों के लिए लघु और सरल।

C कोड की 11+ लाइनों की तुलना करें:

// C Language version of a simple 'switch/case'.
switch( key ) 
{
    case 'a' :
        result = 1;
        break;
    case 'b' :
        result = 2;
        break;
    default :
        result = -1;
}

तुम भी tuples का उपयोग करके कई चर असाइन कर सकते हैं:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))

16
मुझे लगता है कि यह स्वीकार किए जाते हैं की तुलना में अधिक मजबूत जवाब है।
CERD

3
@ सामान्य उपयोगकर्ता: C के लिए आवश्यक है कि रिटर्न वैल्यू सभी मामलों के लिए समान हो। अजगर नहीं करता है। मैं पाइथन के इस लचीलेपन को उजागर करना चाहता था जब किसी के पास ऐसी स्थिति थी जो इस तरह के उपयोग को रोकती थी।
चैमग

3
@ उपयोगकर्ता: व्यक्तिगत रूप से, मुझे {} .get (,) पढ़ने योग्य लगता है। अजगर शुरुआत के लिए अतिरिक्त पठनीयता के लिए आप उपयोग करना चाह सकते हैं default = -1; result = choices.get(key, default)
चैमग

4
सी ++ की 1 पंक्ति के साथ तुलना करेंresult=key=='a'?1:key==b?2:-1
जैसन

4
@ यासेन तर्क दे सकता है कि आप इसे पायथन की एक पंक्ति में भी कर सकते हैं result = 1 if key == 'a' else (2 if key == 'b' else 'default'):। लेकिन एक लाइनर पठनीय है?
ChaimG

101
class switch(object):
    value = None
    def __new__(class_, value):
        class_.value = value
        return True

def case(*args):
    return any((arg == switch.value for arg in args))

उपयोग:

while switch(n):
    if case(0):
        print "You typed zero."
        break
    if case(1, 4, 9):
        print "n is a perfect square."
        break
    if case(2):
        print "n is an even number."
    if case(2, 3, 5, 7):
        print "n is a prime number."
        break
    if case(6, 8):
        print "n is an even number."
        break
    print "Only single-digit numbers are allowed."
    break

टेस्ट:

n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.

64
यह खतरा सुरक्षित नहीं है। यदि एक ही समय में कई स्विच हिट हो जाते हैं, तो सभी स्विच अंतिम स्विच का मूल्य ले लेते हैं।
फ्रांसिसकोर्टिज़

48
जबकि @francescortiz की संभावना का मतलब थ्रेड सुरक्षित है, लेकिन यह सुरक्षित रूप से भी खतरा नहीं है। यह चर के मूल्यों को खतरा है!
Zizouz212

7
थ्रेड-लोकल स्टोरेज का उपयोग करके थ्रेड सुरक्षा समस्या के आसपास काम किया जा सकता है । या एक उदाहरण लौटाकर और केस तुलना के लिए उस उदाहरण का उपयोग करके इसे पूरी तरह से टाला जा सकता है।
ब्लबरडाइब्लूब

6
@blubberdiblub लेकिन फिर एक मानक ifकथन का उपयोग करना अधिक कुशल नहीं है ?
wizzwizz4

9
यह भी सुरक्षित नहीं है अगर कई कार्यों में उपयोग किया जाता है। दिए गए उदाहरण में, यदि case(2)ब्लॉक ने एक अन्य फ़ंक्शन को कॉल किया है जो स्विच का उपयोग करता है (), तो case(2, 3, 5, 7)निष्पादित करने के लिए अगले मामले को देखने के लिए आदि करते समय, यह अन्य फ़ंक्शन द्वारा सेट किए गए स्विच मान का उपयोग करेगा वर्तमान स्विच स्टेटमेंट द्वारा सेट नहीं। ।
user9876

52

मेरा पसंदीदा एक बहुत अच्छा नुस्खा है । आप वास्तव में इसे पसंद करेंगे। यह निकटतम है जिसे मैंने वास्तविक स्विच केस स्टेटमेंट में देखा है, विशेष रूप से सुविधाओं में।

class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration

    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args: # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False

यहाँ एक उदाहरण है:

# The following example is pretty much the exact use-case of a dictionary,
# but is included for its simplicity. Note that you can include statements
# in each suite.
v = 'ten'
for case in switch(v):
    if case('one'):
        print 1
        break
    if case('two'):
        print 2
        break
    if case('ten'):
        print 10
        break
    if case('eleven'):
        print 11
        break
    if case(): # default, could also just omit condition or 'if True'
        print "something else!"
        # No need to break here, it'll stop anyway

# break is used here to look as much like the real thing as possible, but
# elif is generally just as good and more concise.

# Empty suites are considered syntax errors, so intentional fall-throughs
# should contain 'pass'
c = 'z'
for case in switch(c):
    if case('a'): pass # only necessary if the rest of the suite is empty
    if case('b'): pass
    # ...
    if case('y'): pass
    if case('z'):
        print "c is lowercase!"
        break
    if case('A'): pass
    # ...
    if case('Z'):
        print "c is uppercase!"
        break
    if case(): # default
        print "I dunno what c was!"

# As suggested by Pierre Quentel, you can even expand upon the
# functionality of the classic 'case' statement by matching multiple
# cases in a single shot. This greatly benefits operations such as the
# uppercase/lowercase example above:
import string
c = 'A'
for case in switch(c):
    if case(*string.lowercase): # note the * for unpacking as arguments
        print "c is lowercase!"
        break
    if case(*string.uppercase):
        print "c is uppercase!"
        break
    if case('!', '?', '.'): # normal argument passing style also applies
        print "c is a sentence terminator!"
        break
    if case(): # default
        print "I dunno what c was!"

3
मैं इसके for case in switch()साथ विकल्प दूंगा with switch() as case, अधिक समझ में आता है, क्योंकि इसे केवल एक बार चलाने की आवश्यकता है।
स्की

4
@Skirmantas: ध्यान दें कि यद्यपि इसके withलिए अनुमति नहीं है break, इसलिए गिरावट विकल्प को हटा दिया जाता है।
जोनास श्फर

5
इसे स्वयं निर्धारित करने के लिए अधिक प्रयास न करने के लिए क्षमा याचना: ऊपर एक समान उत्तर थ्रेड सुरक्षित नहीं है। क्या इस?
बजे डेविड विनीकी

1
@DavidWiniecki ऊपर से गायब कोड घटक (और संभवतः सक्रिय द्वारा कॉपीराइट) थ्रेड सुरक्षित दिखाई देते हैं।
जैसन

इसका एक और संस्करण कुछ इस तरह होगा if c in set(range(0,9)): print "digit" elif c in set(map(chr, range(ord('a'), ord('z')))): print "lowercase"?
19

51
class Switch:
    def __init__(self, value):
        self.value = value

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        return False # Allows a traceback to occur

    def __call__(self, *values):
        return self.value in values


from datetime import datetime

with Switch(datetime.today().weekday()) as case:
    if case(0):
        # Basic usage of switch
        print("I hate mondays so much.")
        # Note there is no break needed here
    elif case(1,2):
        # This switch also supports multiple conditions (in one line)
        print("When is the weekend going to be here?")
    elif case(3,4):
        print("The weekend is near.")
    else:
        # Default would occur here
        print("Let's go have fun!") # Didn't use case for example purposes

9
संदर्भ प्रबंधकों का उपयोग करना एक अच्छा रचनात्मक समाधान है। ); मैं स्पष्टीकरण का एक सा जोड़ने की सलाह देते हैं और हो सकता है इस पोस्ट के कुछ, ठीक है, संदर्भ देने के लिए प्रसंग प्रबंधक बारे में कुछ जानकारी के लिए एक लिंक
विल

2
मुझे पसंद नहीं है अगर / elif जंजीर ज्यादा है, लेकिन यह सबसे रचनात्मक और उन सभी समाधानों में से सबसे व्यावहारिक है जो मैंने पायथन के मौजूदा सिंटैक्स का उपयोग करके देखा है।
इसका शानदार

2
यह वास्तव में अच्छा है। एक सुझाया गया सुधार valueस्विच क्लास में एक (सार्वजनिक) संपत्ति जोड़ने के लिए है ताकि आप case.valueबयान के भीतर संदर्भ दे सकें ।
पीटर

48

एक पैटर्न है जो मैंने ट्विस्टेड पायथन कोड से सीखा है।

class SMTP:
    def lookupMethod(self, command):
        return getattr(self, 'do_' + command.upper(), None)
    def do_HELO(self, rest):
        return 'Howdy ' + rest
    def do_QUIT(self, rest):
        return 'Bye'

SMTP().lookupMethod('HELO')('foo.bar.com') # => 'Howdy foo.bar.com'
SMTP().lookupMethod('QUIT')('') # => 'Bye'

आप इसे किसी भी समय उपयोग कर सकते हैं जब आपको टोकन पर भेजने और कोड के विस्तारित टुकड़े को निष्पादित करने की आवश्यकता होती है। एक राज्य मशीन में आपके पास state_तरीके होंगे, और भेजेंगे self.state। इस स्विच को बेस क्लास से विरासत में प्राप्त करके और अपने स्वयं के do_तरीकों को परिभाषित करके सफाई से बढ़ाया जा सकता है । अक्सर कई बार आपके पास do_बेस क्लास में भी तरीके नहीं होंगे ।

संपादित करें: यह वास्तव में कैसे उपयोग किया जाता है

SMTP के मामले में आप HELOतार से प्राप्त करेंगे । प्रासंगिक कोड ( twisted/mail/smtp.pyहमारे मामले के लिए संशोधित) इस तरह दिखता है

class SMTP:
    # ...

    def do_UNKNOWN(self, rest):
        raise NotImplementedError, 'received unknown command'

    def state_COMMAND(self, line):
        line = line.strip()
        parts = line.split(None, 1)
        if parts:
            method = self.lookupMethod(parts[0]) or self.do_UNKNOWN
            if len(parts) == 2:
                return method(parts[1])
            else:
                return method('')
        else:
            raise SyntaxError, 'bad syntax'

SMTP().state_COMMAND('   HELO   foo.bar.com  ') # => Howdy foo.bar.com

आप प्राप्त करेंगे ' HELO foo.bar.com '(या आपको मिल सकता है 'QUIT'या 'RCPT TO: foo')। यह के partsरूप में टोकन है ['HELO', 'foo.bar.com']। वास्तविक विधि लुकअप नाम से लिया गया हैparts[0]

(मूल विधि भी कहा जाता है state_COMMAND, क्योंकि यह राज्य मशीन को लागू करने के लिए एक ही पैटर्न का उपयोग करता है, अर्थात getattr(self, 'state_' + self.mode))


4
मैं सीधे तौर पर फोन करने के तरीकों पर इस पैटर्न से लाभ नहीं देखता: SMTP ()। Do_HELO ('foo.bar.com') ठीक है, लुकअप मेथोड में सामान्य कोड हो सकता है, लेकिन तब से इसे भी ओवरराइट किया जा सकता है उपवर्ग मैं यह नहीं देखता कि आप अप्रत्यक्ष रूप से क्या हासिल करते हैं।
श्री शार्क

1
आपको पहले से पता नहीं होगा कि किस विधि से कॉल करना है, यह कहना है कि 'हेलो' एक चर से आता है। मैंने मूल पोस्ट में उपयोग उदाहरण को जोड़ा है

मैं बस सुझाव दे सकता हूं: eval ('SMTP ()। Do_' + कमांड) ('foo.bar.com')
jbergberg

8
eval? गंभीरता से? और प्रति कॉल एक विधि को तत्काल करने के बजाय, हम एक बार बहुत अच्छी तरह से इंस्टेंट कर सकते हैं और सभी कॉल में इसका उपयोग कर सकते हैं बशर्ते इसकी कोई आंतरिक स्थिति न हो।
महेश

1
IMO असली कुंजी है जिसे प्रेषण करने के लिए फ़ंक्शन को निर्दिष्ट करने के लिए getattr का उपयोग करना है। यदि विधियाँ किसी मॉड्यूल में होती हैं, तो आप इसे प्राप्त करने के लिए getattr (लोकल (), func_name) कर सकते हैं। 'Do_' भाग सुरक्षा / त्रुटियों के लिए अच्छा है, इसलिए उपसर्ग के साथ केवल फ़न को बुलाया जा सकता है। SMTP स्वयं लुकअपमैथोड को कॉल करता है। आदर्श रूप से बाहरी को इसके बारे में कोई जानकारी नहीं है। यह वास्तव में SMTP करने के लिए समझ में नहीं आता है। लुकअप मैथोड (नाम) (डेटा)। चूंकि कमांड और डेटा एक स्ट्रिंग में हैं और SMTP इसे पार्स करता है, जिससे अधिक समझ में आता है। अंत में, एसएमटीपी में शायद अन्य साझा राज्य हैं जो इसे एक वर्ग होने के लिए उचित ठहराते हैं।
ShawnFumo

27

मान लें कि आप केवल एक मान वापस नहीं करना चाहते हैं, लेकिन उन तरीकों का उपयोग करना चाहते हैं जो किसी वस्तु पर कुछ बदलते हैं। यहां बताए गए दृष्टिकोण का उपयोग करना होगा:

result = {
  'a': obj.increment(x),
  'b': obj.decrement(x)
}.get(value, obj.default(x))

यहाँ क्या होता है कि अजगर शब्दकोश में सभी तरीकों का मूल्यांकन करता है। तो भले ही आपका मूल्य 'क' हो, वस्तु बढ़ जाएगी और एक्स द्वारा बढ़ाई ।

समाधान:

func, args = {
  'a' : (obj.increment, (x,)),
  'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))

result = func(*args)

तो आपको एक सूची मिलती है जिसमें एक फ़ंक्शन और उसके तर्क होते हैं। इस तरह, केवल फ़ंक्शन पॉइंटर और तर्क सूची वापस आ जाती है, मूल्यांकन नहीं किया जाता है। 'परिणाम' तब दिए गए फ़ंक्शन कॉल का मूल्यांकन करता है।


23

मैं बस यहाँ अपने दो सेंट छोड़ने जा रहा हूँ। पायथन में कोई केस / स्विच स्टेटमेंट नहीं होने का कारण यह है कि पायथन 'थेरेस के केवल एक सही तरीके से कुछ करने के सिद्धांत' का अनुसरण करता है। तो जाहिर है आप स्विच / केस कार्यक्षमता को फिर से बनाने के विभिन्न तरीकों के साथ आ सकते हैं, लेकिन इसे पूरा करने का पाइथोनिक तरीका इफ / एलिफ निर्माण है। अर्थात

if something:
    return "first thing"
elif somethingelse:
    return "second thing"
elif yetanotherthing:
    return "third thing"
else:
    return "default thing"

मुझे लगा कि पीईपी 8 यहां एक हकदार है। पायथन के बारे में सुंदर चीजों में से एक इसकी सादगी और सुंदरता है। यह काफी हद तक पीईपी 8 में रखे गए सिद्धांतों से लिया गया है, जिसमें "कुछ करने का केवल एक सही तरीका है" शामिल है


6
तो पायथन के पास छोरों के लिए और छोरों के लिए क्यों है? एक लूप के साथ आप जो कुछ भी कर सकते हैं वह आप थोड़ी देर के लूप के साथ लागू कर सकते हैं।
इसका कर्क

1
सच। प्रोग्रामर द्वारा शुरुआत में स्विच / केस का अक्सर दुरुपयोग किया जाता है। वे वास्तव में क्या चाहते हैं रणनीति पैटर्न है
user228395

पाइथन की तरह लगता है कि यह क्लोजर था
TWR कोल

1
@TWRCole मुझे नहीं लगता कि, पायथन पहले ऐसा कर रहा था। पायथन 1990 के बाद से और 2007 से क्लोजर के आसपास रहा है।
टेलर

कुछ करने का केवल एक सही तरीका है। पायथन 2.7 या पायथन 3? जबरदस्त हंसी।
TWR कोल

17

"स्विच के रूप में तानाशाही" विचार पर विस्तार। यदि आप अपने स्विच के लिए एक डिफ़ॉल्ट मान का उपयोग करना चाहते हैं:

def f(x):
    try:
        return {
            'a': 1,
            'b': 2,
        }[x]
    except KeyError:
        return 'default'

14
मुझे लगता है कि डिफ़ॉल्ट पर निर्दिष्ट। के साथ .get () का उपयोग करना स्पष्ट है। मैं असाधारण परिस्थितियों के लिए अपवाद छोड़ना पसंद करता हूं, और यह बिना अस्पष्ट हुए कोड की तीन पंक्तियों और इंडेंटेशन के स्तर में कटौती करता है।
क्रिस बी।

10
यह है एक असाधारण परिस्थिति। यह उपयोगी के आधार पर एक दुर्लभ परिस्थिति हो सकती है या नहीं भी हो सकती है, लेकिन यह निश्चित रूप से एक अपवाद है ( 'default'नियम से पीछे हटना ) (इस तानाशाही से कुछ प्राप्त करें)। डिजाइन द्वारा, पायथन कार्यक्रम एक टोपी की बूंद पर अपवादों का उपयोग करते हैं। कहा जा रहा है कि, getसंभावित रूप से कोड को थोड़ा अच्छा बनाया जा सकता है।
माइक ग्राहम

16

यदि आपके पास एक जटिल मामला है, तो आप एक फ़ंक्शन डिक्शनरी लुकअप टेबल का उपयोग करने पर विचार कर सकते हैं ...

यदि आपने अपने डिबगर में कदम रखने के लिए एक अच्छा विचार करने से पहले ऐसा नहीं किया है और यह देखें कि शब्दकोश प्रत्येक फ़ंक्शन को कैसे देखता है।

नोट: मामले / शब्दकोश लुकअप के अंदर "()" का उपयोग करें या यह आपके प्रत्येक कार्य को शब्दकोश / केस ब्लॉक के रूप में कॉल करेगा। इसे याद रखें क्योंकि आप केवल हैश स्टाइल लुकअप का उपयोग करके प्रत्येक फ़ंक्शन को कॉल करना चाहते हैं।

def first_case():
    print "first"

def second_case():
    print "second"

def third_case():
    print "third"

mycase = {
'first': first_case, #do not use ()
'second': second_case, #do not use ()
'third': third_case #do not use ()
}
myfunc = mycase['first']
myfunc()

मुझे आपका हल पसंद है। लेकिन, क्या होगा अगर मुझे बस कुछ चर या वस्तुओं को पारित करने की आवश्यकता है?
टेडो वृबनक

यदि विधि मापदंडों की अपेक्षा कर रही है तो यह काम नहीं करेगा।
कुलसंगर

16

यदि आप अतिरिक्त विवरण खोज रहे हैं, तो "स्विच" के रूप में, मैंने पायथन मॉड्यूल का निर्माण किया जो पायथन को विस्तारित करता है। इसे ESPY कहा जाता है को "पाइथन के लिए संवर्धित संरचना" के रूप में और यह पाइथन 2.x और पाइथन 3.10 दोनों के लिए उपलब्ध है।

उदाहरण के लिए, इस मामले में, निम्न कोड द्वारा एक स्विच स्टेटमेंट किया जा सकता है:

macro switch(arg1):
    while True:
        cont=False
        val=%arg1%
        socket case(arg2):
            if val==%arg2% or cont:
                cont=True
                socket
        socket else:
            socket
        break

इसका उपयोग इस तरह किया जा सकता है:

a=3
switch(a):
    case(0):
        print("Zero")
    case(1):
        print("Smaller than 2"):
        break
    else:
        print ("greater than 1")

तो यह पायथन में अनुवाद के रूप में अनुवाद:

a=3
while True:
    cont=False
    if a==0 or cont:
        cont=True
        print ("Zero")
    if a==1 or cont:
        cont=True
        print ("Smaller than 2")
        break
    print ("greater than 1")
    break

बहुत अच्छा है, लेकिन while True:उत्पन्न पायथन कोड के शीर्ष पर क्या है? यह अनिवार्य रूप से मारा जाएगा break, उत्पन्न अजगर कोड के तल पर तो मुझे लगता है कि दोनों while True:और breakहटाया जा सकता है। इसके अलावा, क्या ईएसपीवाई इतना स्मार्ट है कि वह नाम बदल सकता है contयदि उपयोगकर्ता अपने कोड में उसी नाम का उपयोग करता है? किसी भी घटना में, मैं वेनिला पायथन का उपयोग करना चाहता हूं, इसलिए मैं इसका उपयोग नहीं करूंगा, लेकिन यह अच्छा है-कोई भी कम नहीं है। सरासर ठंडक के लिए +1।
आर्टऑफवर्फ

@ArtOfWarfare एस while True:और breakएस के लिए कारण की अनुमति है, लेकिन गिर के माध्यम से की आवश्यकता नहीं है।
सोलोमन उको

क्या यह मॉड्यूल अभी भी उपलब्ध है?
सोलोमन उको

15

मैंने पाया कि एक सामान्य स्विच संरचना:

switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;

अजगर में व्यक्त किया जा सकता है इस प्रकार है:

(lambda x: v1 if p1(x) else v2 if p2(x) else v3)

या एक स्पष्ट तरीके से स्वरूपित:

(lambda x:
     v1 if p1(x) else
     v2 if p2(x) else
     v3)

एक बयान होने के बजाय, अजगर संस्करण एक अभिव्यक्ति है, जो एक मूल्य का मूल्यांकन करता है।


इसके अलावा ... पैरामीटर ... और p1 (x) कैसे के बारे में parameterऔरp1==parameter
Bob Stein

@ BobStein-VisiBone हाय, यहाँ एक उदाहरण है जो मेरे अजगर सत्र में चलता है f = lambda x: 'a' if x==0 else 'b' if x==1 else 'c':। जब मैंने बाद में फोन किया f(2), मुझे मिल गया 'c'; f(1), 'b'; और f(0), 'a'। P1 (x) के लिए, यह एक विधेय को दर्शाता है; जब तक यह लौटता है Trueया False, कोई फर्क नहीं पड़ता कि यह एक फ़ंक्शन कॉल या एक अभिव्यक्ति है, यह ठीक है।
leo

@ BobStein-VisiBone हाँ, आप सही हैं! धन्यवाद :) काम करने के लिए बहु-पंक्ति अभिव्यक्ति के लिए, कोष्ठक को आपके सुझाव के अनुसार या मेरे संशोधित उदाहरण में रखा जाना चाहिए।
leo

अति उत्कृष्ट। अब मैं अपनी सभी टिप्पणियों को परेंसियों के बारे में बताऊंगा।
बॉब स्टाइन

15

यहां अधिकांश उत्तर बहुत पुराने हैं, और विशेष रूप से स्वीकार किए गए हैं, इसलिए यह अपडेट करने लायक लगता है।

सबसे पहले, आधिकारिक पायथन एफएक्यू इसे कवर करता है, और elifसरल मामलों के dictलिए और बड़े या अधिक जटिल मामलों के लिए श्रृंखला की सिफारिश करता है । यह visit_कुछ मामलों के लिए तरीकों का एक सेट (कई सर्वर फ्रेमवर्क द्वारा उपयोग की जाने वाली शैली) भी सुझाता है :

def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()

एफएक्यू में पीईपी 275 का भी उल्लेख है , जिसे सी-स्टाइल स्विच स्टेटमेंट को जोड़ने के लिए आधिकारिक रूप से एक बार और सभी निर्णय लेने के लिए लिखा गया था। लेकिन उस PEP को वास्तव में Python 3 के लिए स्थगित कर दिया गया था, और इसे केवल एक अलग प्रस्ताव PEP 3103 के रूप में आधिकारिक तौर पर खारिज कर दिया गया था । उत्तर, निश्चित रूप से, नहीं- लेकिन दो पीईपी में अतिरिक्त जानकारी के लिए लिंक हैं यदि आप कारणों या इतिहास में रुचि रखते हैं।


एक बात जो कई बार सामने आई (और पीईपी 275 में देखी जा सकती है, भले ही इसे वास्तविक सिफारिश के रूप में काट दिया गया हो) यह है कि यदि आप 4 मामलों को संभालने के लिए कोड की 8 लाइनें होने से वास्तव में परेशान हैं, तो 6 बनाम। लाइनें आपके पास C या Bash में होंगी, आप इसे हमेशा लिख ​​सकते हैं:

if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')

यह पीईपी 8 द्वारा बिल्कुल प्रोत्साहित नहीं किया गया है, लेकिन यह पठनीय है और बहुत कम नहीं है।


PEP 3103 को अस्वीकार किए जाने के एक दशक से अधिक समय के बाद, C- स्टाइल केस स्टेटमेंट्स, या यहां तक ​​कि गो में थोड़ा अधिक शक्तिशाली संस्करण के मुद्दे को मृत माना गया है; जब भी कोई इसे अजगर-विचारों या -देव पर लाता है, तो उन्हें पुराने निर्णय के लिए भेजा जाता है।

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

पर्ल 6-शैली के मिलान के लिए कभी-कभी प्रस्ताव भी होते हैं, जो मूल रूप elifसे एकल-प्रेषण-स्विचिंग के लिए regex से सब कुछ का एक मश्मश है ।


15

कार्यों को चलाने का हल:

result = {
    'case1':     foo1, 
    'case2':     foo2,
    'case3':     foo3,
    'default':   default,
}.get(option)()

जहाँ foo1 (), foo2 (), foo3 () और डिफ़ॉल्ट () फ़ंक्शन हैं


1
हां, उदाहरण के लिए यदि आपका चर विकल्प == "case2" आपका परिणाम = foo2 ()
एलेजांद्रो

और तो और आगे।
एलेजांद्रो

हां, मैं इसका उद्देश्य समझता हूं। लेकिन मेरी चिंता यह है कि अगर आप केवल चाहते हैं foo2(), foo1(), foo3(), और default()कार्यों सब भी चलाने के लिए जा रहे हैं, बातें अर्थ में लंबा समय लग सकता है
ब्रायन अंडरवुड

1
शब्दकोश के अंदर () छोड़ दें। का उपयोग करें get(option)()। समस्या सुलझ गयी।
टाइमजैब

1
बहुत बढ़िया की () का उपयोग एक जाली हल है, मैं इसे परीक्षण करने के लिए एक सार बनाया gist.github.com/aquintanar/01e9920d8341c5c6252d507669758fe5
ऐलेजैंड्रो क़ुइंटनार

13

मुझे वह सरल उत्तर नहीं मिला जो मैं Google खोज पर कहीं भी ढूंढ रहा था। लेकिन मुझे यह समझ में आया। यह वास्तव में काफी सरल है। इसे पोस्ट करने का निर्णय लिया, और हो सकता है कि किसी और के सिर पर कुछ कम खरोंच को रोकें। कुंजी बस "इन" और टुपल्स है। यहाँ RANDOM फ़ॉल-थ्रू सहित फ़ॉल-थ्रू के साथ स्विच स्टेटमेंट व्यवहार है।

l = ['Dog', 'Cat', 'Bird', 'Bigfoot',
     'Dragonfly', 'Snake', 'Bat', 'Loch Ness Monster']

for x in l:
    if x in ('Dog', 'Cat'):
        x += " has four legs"
    elif x in ('Bat', 'Bird', 'Dragonfly'):
        x += " has wings."
    elif x in ('Snake',):
        x += " has a forked tongue."
    else:
        x += " is a big mystery by default."
    print(x)

print()

for x in range(10):
    if x in (0, 1):
        x = "Values 0 and 1 caught here."
    elif x in (2,):
        x = "Value 2 caught here."
    elif x in (3, 7, 8):
        x = "Values 3, 7, 8 caught here."
    elif x in (4, 6):
        x = "Values 4 and 6 caught here"
    else:
        x = "Values 5 and 9 caught in default."
    print(x)

प्रदान करता है:

Dog has four legs
Cat has four legs
Bird has wings.
Bigfoot is a big mystery by default.
Dragonfly has wings.
Snake has a forked tongue.
Bat has wings.
Loch Ness Monster is a big mystery by default.

Values 0 and 1 caught here.
Values 0 and 1 caught here.
Value 2 caught here.
Values 3, 7, 8 caught here.
Values 4 and 6 caught here
Values 5 and 9 caught in default.
Values 4 and 6 caught here
Values 3, 7, 8 caught here.
Values 3, 7, 8 caught here.
Values 5 and 9 caught in default.

कहाँ वास्तव में यहाँ है?
जोनास स्चफर

ऊप्स! वहाँ के माध्यम से गिर रहा है, लेकिन मैं अब स्टैक ओवरफ्लो में योगदान नहीं कर रहा हूं। उन्हें पसंद नहीं है। मुझे दूसरों द्वारा योगदान पसंद है, लेकिन सिर्फ स्टैकओवरफ्लो नहीं। यदि आप फंक्शनलिटी के लिए गिरावट का उपयोग कर रहे हैं, तो आप एक स्विच (एक कैच ऑल) में सभी मामलों में कुछ शर्तों को कैटच करना चाहते हैं, जब तक कि आप एक स्विच में ब्रेक स्टेटमेंट तक नहीं पहुंचते।
जेडी ग्राहम

2
यहाँ दोनों मूल्य "डॉग" और "कैट" FALL THROUGH हैं और इन्हें SAME कार्यक्षमता द्वारा नियंत्रित किया जाता है, जिसे वे "चार पैर" के रूप में परिभाषित करते हैं। यह एक ABSTRACT है जो एसएएमई केस स्टेटमेंट द्वारा नियंत्रित विभिन्न मूल्यों के माध्यम से गिरता है और जहां एक ब्रेक होता है।
JD ग्राहम

@JDGraham मुझे लगता है कि जोनास फालोथ का एक और पहलू था, जो तब होता है जब प्रोग्रामर कभी-कभार breakकोड के अंत में लिखना भूल जाता है case। लेकिन मुझे लगता है कि हमें इस तरह के "पतन" की आवश्यकता नहीं है :)
मिखाइल बैटसर

12

मेरे द्वारा उपयोग किए जाने वाले समाधान:

यहां पोस्ट किए गए समाधानों में से 2 का एक संयोजन, जिसे पढ़ना आसान है और चूक का समर्थन करता है।

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)

कहाँ पे

.get('c', lambda x: x - 22)(23)

"lambda x: x - 2"हुकुम में दिखता है और उसके साथ प्रयोग करता हैx=23

.get('xxx', lambda x: x - 22)(44)

dict में ढूंढ़कर डिफ़ॉल्ट का उपयोग करता है नहीं करता है "lambda x: x - 22"के साथ x=44


10
# simple case alternative

some_value = 5.0

# this while loop block simulates a case block

# case
while True:

    # case 1
    if some_value > 5:
        print ('Greater than five')
        break

    # case 2
    if some_value == 5:
        print ('Equal to five')
        break

    # else case 3
    print ( 'Must be less than 5')
    break

10
def f(x):
    dictionary = {'a':1, 'b':2, 'c':3}
    return dictionary.get(x,'Not Found') 
##Returns the value for the letter x;returns 'Not Found' if x isn't a key in the dictionary

अपने कोड के संक्षिप्त विवरण और यह पोस्ट किए गए प्रश्न को कैसे हल करता है, इस पर विचार करें
हेनरी वुडी

ठीक है, मैंने अभी इसके लिए एक टिप्पणी जोड़ी है।
विकीत अग्रवाल

8

मुझे मार्क बीज़ का जवाब पसंद आया

चूँकि xचर का उपयोग दो बार किया जाना चाहिए, इसलिए मैंने लैम्बडा फ़ंक्शन को पैरामीटरलेस में बदल दिया।

मुझे साथ चलना है results[value](value)

In [2]: result = {
    ...:   'a': lambda x: 'A',
    ...:   'b': lambda x: 'B',
    ...:   'c': lambda x: 'C'
    ...: }
    ...: result['a']('a')
    ...: 
Out[2]: 'A'

In [3]: result = {
    ...:   'a': lambda : 'A',
    ...:   'b': lambda : 'B',
    ...:   'c': lambda : 'C',
    ...:   None: lambda : 'Nothing else matters'

    ...: }
    ...: result['a']()
    ...: 
Out[3]: 'A'

संपादित करें: मैंने देखा कि मैं Noneशब्दकोशों के साथ टाइप का उपयोग कर सकता हूं । तो यह अनुकरण होगाswitch ; case else


क्या कोई भी मामला केवल अनुकरण नहीं करता है result[None]()?
बॉब स्टीन

हाँ बिल्कुल। मेरा मतलब हैresult = {'a': 100, None:5000}; result[None]
गनियस 15

4
बस यह जांचना कि कोई भी ऐसा नहीं सोच रहा None:है default:
बॉब स्टीन

7
def f(x):
     return 1 if x == 'a' else\
            2 if x in 'bcd' else\
            0 #default

लघु और पढ़ने में आसान, एक डिफ़ॉल्ट मूल्य है और दोनों स्थितियों और वापसी मूल्यों में अभिव्यक्ति का समर्थन करता है।

हालांकि, यह एक शब्दकोश के साथ समाधान की तुलना में कम कुशल है। उदाहरण के लिए, डिफ़ॉल्ट मान वापस करने से पहले पायथन को सभी शर्तों के माध्यम से स्कैन करना होगा।


6

आप एक प्रेषण तानाशाह का उपयोग कर सकते हैं:

#!/usr/bin/env python


def case1():
    print("This is case 1")

def case2():
    print("This is case 2")

def case3():
    print("This is case 3")


token_dict = {
    "case1" : case1,
    "case2" : case2,
    "case3" : case3,
}


def main():
    cases = ("case1", "case3", "case2", "case1")
    for case in cases:
        token_dict[case]()


if __name__ == '__main__':
    main()

आउटपुट:

This is case 1
This is case 3
This is case 2
This is case 1

6

सरल, परीक्षण नहीं; प्रत्येक स्थिति का स्वतंत्र रूप से मूल्यांकन किया जाता है: कोई गिरावट नहीं होती है, लेकिन सभी मामलों का मूल्यांकन किया जाता है (हालांकि स्विच करने के लिए अभिव्यक्ति का केवल एक बार मूल्यांकन किया जाता है), जब तक कि एक ब्रेक स्टेटमेंट न हो। उदाहरण के लिए,

for case in [expression]:
    if case == 1:
        print(end='Was 1. ')

    if case == 2:
        print(end='Was 2. ')
        break

    if case in (1, 2):
        print(end='Was 1 or 2. ')

    print(end='Was something. ')

प्रिंट Was 1. Was 1 or 2. Was something. (Dammit! मैं क्यों इनलाइन कोड ब्लॉक में खाली स्थान के पीछे चल कर सकते हैं नहीं किया है?) अगर expressionमूल्यांकन करने के लिए 1, Was 2.यदि expressionमूल्यांकन करने के लिए 2, या Was something.अगर expressionकुछ और करने के लिए मूल्यांकन करता है।


1
ठीक है, काम के माध्यम से गिरावट, लेकिन केवल do_default पर जाने के लिए।
syockit

5

निर्धारित करना:

def switch1(value, options):
  if value in options:
    options[value]()

आपको नक्शे में बंडल किए गए मामलों के साथ एक बहुत ही सरल वाक्यविन्यास का उपयोग करने की अनुमति देता है:

def sample1(x):
  local = 'betty'
  switch1(x, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye," + local),
      print("!")),
    })

मैं एक तरह से स्विच को फिर से परिभाषित करने की कोशिश कर रहा था जो मुझे "लैम्ब्डा:" से छुटकारा दिलाएगा, लेकिन हार मान ली। परिभाषा को मोड़ना:

def switch(value, *maps):
  options = {}
  for m in maps:
    options.update(m)
  if value in options:
    options[value]()
  elif None in options:
    options[None]()

मुझे एक ही कोड में कई मामलों को मैप करने की अनुमति दी, और एक डिफ़ॉल्ट विकल्प की आपूर्ति करने के लिए:

def sample(x):
  switch(x, {
    _: lambda: print("other") 
    for _ in 'cdef'
    }, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye,"),
      print("!")),
    None: lambda: print("I dunno")
    })

प्रत्येक दोहराया गया मामला अपने शब्दकोश में होना चाहिए; स्विच () मूल्य देखने से पहले शब्दकोशों को समेकित करता है। यह अब भी मुझे पसंद है की तुलना में बदसूरत है, लेकिन यह सभी कुंजियों के माध्यम से एक लूप के बजाय अभिव्यक्ति पर एक हैशड लुकअप का उपयोग करने की बुनियादी दक्षता है।


5

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

class ChoiceManager:

    def __init__(self):
        self.__choice_table = \
        {
            "CHOICE1" : self.my_func1,
            "CHOICE2" : self.my_func2,
        }

    def my_func1(self, data):
        pass

    def my_func2(self, data):
        pass

    def process(self, case, data):
        return self.__choice_table[case](data)

ChoiceManager().process("CHOICE1", my_data)

"__Choice_table" की कुंजी के रूप में भी कक्षाओं का उपयोग करके इस पद्धति का लाभ उठाना संभव है । इस तरह आप इनस्टेंस के दुरुपयोग से बच सकते हैं और सभी स्वच्छ और परीक्षण योग्य रख सकते हैं।

मान लीजिए आपको नेट या अपने MQ से बहुत सारे संदेश या पैकेट संसाधित करने हैं। हर पैकेट की अपनी संरचना और प्रबंधन कोड होता है (सामान्य तरीके से)। उपरोक्त कोड के साथ ऐसा कुछ करना संभव है:

class PacketManager:

    def __init__(self):
        self.__choice_table = \
        {
            ControlMessage : self.my_func1,
            DiagnosticMessage : self.my_func2,
        }

    def my_func1(self, data):
        # process the control message here
        pass

    def my_func2(self, data):
        # process the diagnostic message here
        pass

    def process(self, pkt):
        return self.__choice_table[pkt.__class__](pkt)

pkt = GetMyPacketFromNet()
PacketManager().process(pkt)


# isolated test or isolated usage example
def test_control_packet():
    p = ControlMessage()
    PacketManager().my_func1(p)

इसलिए कोड फ्लो में जटिलता नहीं फैली है लेकिन इसे कोड संरचना में प्रस्तुत किया गया है


वास्तव में बदसूरत ... पढ़ने के दौरान स्विच का मामला इतना साफ है। समझ नहीं पा रहा है कि इसे पायथन में क्यों लागू नहीं किया गया है।
jmcollin92

@AndyClifton: मुझे क्षमा करें ... एक उदाहरण है? हर बार सोचें कि आपको कई निर्णय लेने की आवश्यकता है और आप इस विधि को लागू कर सकते हैं।
J_Zar

@ jmcollin92: स्विच स्टेटमेंट कंफर्टेबल है, मैं सहमत हूं। हालांकि प्रोग्रामर बहुत लंबे बयान और कोड लिखने के लिए जाता है जो पुन: प्रयोज्य नहीं है। जिस तरह से मैंने बताया वह परीक्षण और अधिक पुन: प्रयोज्य, IMHO के लिए क्लीनर है।
J_Zar

@J_Zar: पुनः। एक उदाहरण के लिए मेरा अनुरोध: हां, मुझे वह मिल गया है, लेकिन मैं इसे कोड के एक बड़े टुकड़े के संदर्भ में रखने के लिए संघर्ष कर रहा हूं। क्या आप दिखा सकते हैं कि मैं वास्तविक दुनिया की स्थिति में इसका उपयोग कैसे कर सकता हूं?
एंडी क्लिफ्टन

1
@AndyClifton: मुझे क्षमा करें, मुझे देर हो गई है लेकिन मैंने कुछ उदाहरण मामले पोस्ट किए हैं।
J_Zar

5

ग्रेग हेगिल के उत्तर पर विस्तार - हम एक डेकोरेटर का उपयोग करके शब्दकोश-समाधान को संक्षिप्त कर सकते हैं:

def case(callable):
    """switch-case decorator"""
    class case_class(object):
        def __init__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

        def do_call(self):
            return callable(*self.args, **self.kwargs)

return case_class

def switch(key, cases, default=None):
    """switch-statement"""
    ret = None
    try:
        ret = case[key].do_call()
    except KeyError:
        if default:
            ret = default.do_call()
    finally:
        return ret

यह तब @case-decorator के साथ उपयोग किया जा सकता है

@case
def case_1(arg1):
    print 'case_1: ', arg1

@case
def case_2(arg1, arg2):
    print 'case_2'
    return arg1, arg2

@case
def default_case(arg1, arg2, arg3):
    print 'default_case: ', arg1, arg2, arg3

ret = switch(somearg, {
    1: case_1('somestring'),
    2: case_2(13, 42)
}, default_case(123, 'astring', 3.14))

print ret

अच्छी खबर यह है कि यह पहले ही NeoPySwitch -module में किया जा चुका है । बस पाइप का उपयोग कर स्थापित करें:

pip install NeoPySwitch

5

एक समाधान जिसका मैं उपयोग करता हूं वह भी शब्दकोशों का उपयोग करता है:

def decision_time( key, *args, **kwargs):
    def action1()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action2()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action3()
        """This function is a closure - and has access to all the arguments"""
        pass

   return {1:action1, 2:action2, 3:action3}.get(key,default)()

इसका यह फायदा है कि यह हर बार फ़ंक्शन का मूल्यांकन करने की कोशिश नहीं करता है, और आपको बस यह सुनिश्चित करना है कि बाहरी फ़ंक्शन को उन सभी जानकारी मिलती है जो आंतरिक कार्यों की आवश्यकता होती है।


5

अब तक बहुत सारे उत्तर मिल चुके हैं, जिनमें कहा गया है, "हमारे पास अजगर में कोई स्विच नहीं है, इसे इस तरह से करें"। हालाँकि, मैं यह बताना चाहूंगा कि स्विच स्टेटमेंट स्वयं एक आसानी से तैयार की जाने वाली रचना है जिसे ज्यादातर मामलों में टाला जा सकता है और इससे बचना चाहिए क्योंकि वे आलसी प्रोग्रामिंग को बढ़ावा देती हैं। इसका स्पष्ट उदाहरण:

def ToUpper(lcChar):
    if (lcChar == 'a' or lcChar == 'A'):
        return 'A'
    elif (lcChar == 'b' or lcChar == 'B'):
        return 'B'
    ...
    elif (lcChar == 'z' or lcChar == 'Z'):
        return 'Z'
    else:
        return None        # or something

अब, आप इसे एक स्विच-स्टेटमेंट (यदि पायथन ने एक की पेशकश की है) के साथ कर सकते हैं , लेकिन आप अपना समय बर्बाद कर रहे हैं क्योंकि ऐसे तरीके हैं जो यह ठीक करते हैं। या हो सकता है, आपके पास कुछ कम स्पष्ट हो:

def ConvertToReason(code):
    if (code == 200):
        return 'Okay'
    elif (code == 400):
        return 'Bad Request'
    elif (code == 404):
        return 'Not Found'
    else:
        return None

हालांकि, इस तरह के ऑपरेशन को एक शब्दकोश के साथ किया जा सकता है और इसे एक शब्दकोश के साथ संभाला जाना चाहिए क्योंकि यह तेज, कम जटिल, त्रुटि के लिए कम प्रवण और अधिक कॉम्पैक्ट होगा।

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

इसलिए, यह पूछने के बजाय "मैं पायथन में कैसे स्विच करूं?", शायद हमें पूछना चाहिए, "मैं पायथन में स्विच क्यों करना चाहता हूं?" क्योंकि यह अक्सर अधिक दिलचस्प सवाल है और अक्सर आप जो भी निर्माण कर रहे हैं उसके डिजाइन में खामियों को उजागर करेंगे।

अब, यह कहना नहीं है कि स्विच का उपयोग कभी भी नहीं किया जाना चाहिए। राज्य की मशीनें, लेसर, पार्सर और ऑटोमेटा सभी कुछ हद तक उनका उपयोग करते हैं और सामान्य तौर पर, जब आप एक सममित इनपुट से शुरू करते हैं और एक असममित आउटपुट पर जाते हैं तो वे उपयोगी हो सकते हैं; आपको केवल यह सुनिश्चित करने की आवश्यकता है कि आप स्विच को हथौड़ा के रूप में उपयोग नहीं करते हैं क्योंकि आपको अपने कोड में नाखूनों का एक गुच्छा दिखाई देता है।

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