Switch in Python

后端 未结 7 1070
孤独总比滥情好
孤独总比滥情好 2021-01-01 22:34

I have tried making a switch like statement in python, instead of having a lot of if statements.

The code looks like this:

def findStuff(cds):
    L         


        
相关标签:
7条回答
  • 2021-01-01 23:24

    With "get" method, you can have the same effect as "switch..case" in C.

    Marcin example :

    switch_dict = {
        Foo: self.doFoo,
        Bar: self.doBar,
    }
    
    func = switch_dict.get(switch_var, self.dodefault)
    result = func() # or if they take args, pass args
    
    0 讨论(0)
  • 2021-01-01 23:25

    While there is nothing wrong with if..else, I find "switch in Python" still an intriguing problem statement. On that, I think Marcin's (deprecated) option (c) and/or Snim2's second variant can be written in a more readable way.

    For this we can declare a switch class, and exploit the __init__() to declare the case we want to switch, while __call__() helps to hand over a dict listing the (case, function) pairs:

    class switch(object):
        def __init__(self, case):
            self._case = case
    
        def __call__(self, dict_):
            try:
                return dict_[self._case]()
            except KeyError:
                if 'else' in dict_:
                    return dict_['else']()
                raise Exception('Given case wasn\'t found.')
    

    Or, respectively, since a class with only two methods, of which one is __init__(), isn't really a class:

    def switch(case):
        def cases(dict_):
            try:
                return dict_[case]()
            except KeyError:
                if 'else' in dict_:
                    return dict_['else']()
                raise Exception('Given case wasn\'t found.')
        return cases
    

    (note: choose something smarter than Exception)

    With for example

    def case_a():
        print('hello world')
    
    def case_b():
        print('sth other than hello')
    
    def default():
        print('last resort')
    

    you can call

    switch('c') ({
        'a': case_a,
        'b': case_b,
        'else': default
    })
    

    which, for this particular example would print

    last resort

    This doesn't behave like a C switch in that there is no break for the different cases, because each case executes only the function declared for the particular case (i.e. break is implicitly always called). Secondly, each case can list exactly only one function that will be executed upon a found case.

    0 讨论(0)
  • 2021-01-01 23:27

    There's nothing wrong with a long if:

    if switch == 'case0':
       do_case0()
    elif switch == 'case1':
       do_case1()
    elif switch == 'case2':
       do_case2()
    ...
    

    If that's too long winded, or if you have a lot of cases, put them in a dictionary:

    switch = {'case0': do_case0, 'case1': do_case1, 'case2': do_case2, ...}
    switch[case_variable]()
    // Alternative:
    (switch[case_variable]).__call__()
    

    If your conditions are a bit more complex, you need to think a little about your data structures. e.g.:

    switch = {(0,21): 'never have a pension',
              (21,50): 'might have a pension',
              (50,65): 'definitely have a pension',
              (65, 200): 'already collecting pension'}
    for key, value in switch:
        if key[0] < case_var < key[1]:
            print(value)
    
    0 讨论(0)
  • 2021-01-01 23:32

    (a) I fail to see what is wrong with if...elif...else

    (b) I assume that python does not have a switch statement for the same reason that Smalltalk doesn't: it's almost completely redundant, and in the case where you want to switch on types, you can add an appropriate method to your classes; and likewise switching on values should be largely redundant.

    Note: I am informed in the comments that whatever Guido's reason for not creating a switch in the first place, PEPs to have it added were rejected on the basis that support for adding such a statement is extremely limited. See: http://www.python.org/dev/peps/pep-3103/

    (c) If you really need switching behaviour, use a hashtable (dict) to store callables. The structure is:

    switch_dict = {
        Foo: self.doFoo,
        Bar: self.doBar,
        }
    
    func = switch_dict[switch_var]
    result = func() # or if they take args, pass args
    
    0 讨论(0)
  • 2021-01-01 23:33

    You can do something like what you want, but you shouldn't. That said, here's how; you can see how it does not improve things.

    The biggest problem with the way you have it is that Python will evaluate your tests and results once, at the time you declare the dictionary. What you'd have to do instead is make all conditions and the resulting statements functions; this way, evaluation is deferred until you call them. Fortunately there is a way to do this inline for simple functions using the lambda keyword. Secondly, the assignment statement can't be used as a value in Python, so our action functions (which are executed if the corresponding condition function returns a truthy value) have to return a value that will be used to increment c; they can't assign to c themselves.

    Also, the items in a dictionary aren't ordered, so your tests won't necessarily be performed in the order you define them, meaning you probably should use something other than a dictionary that preserves order, such as a tuple or a list. I am assuming you want only ever one case to execute.

    So, here we go:

    def findStuff(cds):
    
        cases = [ (lambda: a[2][0] == 1, lambda: i + 1),
                  (lambda: a[2][1] == 1, lambda: i + 2),
                  (lambda: a[2][2] == 1, lambda: i + 3),
                  (lambda: a[1] == 1,    lambda: L.append(cds[i:i+3], a[0], c) or 0)
                ]
    
        L=[]
        c=0
        for i in range(0, len(cds), 3):
            a=differencesTo(cds[i:i+3])
            for condition, action in cases:
                if condition():
                    c += action()
                    break
        return L
    

    Is this more readable than a sequence of if/elif statements? Nooooooooooooo. In particular, the fourth case is far less comprehensible than it should be because we are having to rely on a function that returns the increment for c to modify a completely different variable, and then we have to figure out how to get it to return a 0 so that c won't actually be modified. Uuuuuugly.

    Don't do this. In fact this code probably won't even run as-is, as I deemed it too ugly to test.

    0 讨论(0)
  • 2021-01-01 23:34

    I don't know which article you've found to do something like this, but this is really messy: the whole result diction will be always evaluated, and instead of doing only part of the work (as a switch / if do), you'll do the whole work everytime. (even if you use only a part of the result).

    Really, a fast switch statement in Python is using "if":

    if case == 1:
      pass
    elif case == 2:
      pass
    elif case == 3:
      pass
    else:
      # default case
      pass
    
    0 讨论(0)
提交回复
热议问题