software - python tutorial pdf




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

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

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

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

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


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

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

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

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("!")),
    })

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

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")
    })

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


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

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)

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


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

चूंकि 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 प्रकार का उपयोग None कर सकता। तो यह switch ; case else अनुकरण करेगा switch ; case else switch ; case else


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

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" की चाबियों के रूप में कक्षाओं का उपयोग करके इस विधि का लाभ उठाना संभव है। इस तरह आप इंस्टेंस दुरुपयोग से बच सकते हैं और सभी स्वच्छ और टेस्टेबल रख सकते हैं।

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

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)

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


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

यहां एक उदाहरण दिया गया है:

# 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!"

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

यहां पोस्ट किए गए 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)

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

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

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


मैंने इसके लिए एक (अपेक्षाकृत) लचीला और पुनः उपयोग करने योग्य समाधान बनाया है। यह गिटहब में इस जिस्ट के रूप में पाया जा सकता है। यदि स्विच फ़ंक्शन का परिणाम कॉल करने योग्य है, तो इसे स्वचालित रूप से कॉल किया जाता है।


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

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)

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


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

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

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

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

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

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

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

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

सरल परिदृश्यों के लिए छोटा और सरल।

सी कोड की 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'))

Expanding on Greg Hewgill's answer - We can encapsulate the dictionary-solution using a decorator:

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

This can then be used with the @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

The good news are that this has already been done in NeoPySwitch -module. Simply install using pip:

pip install NeoPySwitch

I was quite confused after reading the answer, but this cleared it all up:

def numbers_to_strings(argument):
    switcher = {
        0: "zero",
        1: "one",
        2: "two",
    }
    return switcher.get(argument, "nothing")

This code is analogous to:

function(argument){
    switch(argument) {
        case 0:
            return "zero";
        case 1:
            return "one";
        case 2:
            return "two";
        default:
            return "nothing";
    }
}

Check the Source for more about dictionary mapping to functions.


I would just use if/elif/else statements. I think that it's good enough to replace the switch statement.


Inspired by this awesome answer . Requires no other code. Not tested. Realized that fall through does not work properly.

for case in [expression]:
    if case == 1:
        do_stuff()
        # Fall through

    if case in range(2, 5):
        do_other_stuff()
        break

    do_default()

Just mapping some a key to some code is not really and issue as most people have shown using the dict. The real trick is trying to emulate the whole drop through and break thing. I don't think I've ever written a case statement where I used that "feature". Here's a go at drop through.

def case(list): reduce(lambda b, f: (b | f[0], {False:(lambda:None),True:f[1]}[b | f[0]]())[0], list, False)

case([
    (False, lambda:print(5)),
    (True, lambda:print(4))
])

I was really imagining it as a single statement. I hope you'll pardon the silly formatting.

reduce(
    initializer=False,
    function=(lambda b, f:
        ( b | f[0]
        , { False: (lambda:None)
          , True : f[1]
          }[b | f[0]]()
        )[0]
    ),
    iterable=[
        (False, lambda:print(5)),
        (True, lambda:print(4))
    ]
)

I hope that's valid python. It should give you drop through. of course the boolean checks could be expressions and if you wanted them to be evaluated lazily you could wrap them all in a lambda. I wouldn't be to hard to make it accept after executing some of the items in the list either. Just make the tuple (bool, bool, function) where the second bool indicates whether or not to break or drop through.


class Switch:
    def __init__(self, value): self._val = value
    def __enter__(self): return self
    def __exit__(self, type, value, traceback): return False # Allows traceback to occur
    def __call__(self, *mconds): return self._val in mconds

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

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.




python