while - python2 switch case




替代Python中的switch語句? (20)

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

我想在Python中編寫一個函數,它根據輸入索引的值返回不同的固定值。

在其他語言中,我會使用switchcase語句,但Python似乎沒有switch語句。 在這種情況下推薦的Python解決方案是什麼?



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


If you don't worry losing syntax highlight inside the case suites, you can do the following:

exec {
    1: """
print ('one')
""", 
    2: """
print ('two')
""", 
    3: """
print ('three')
""",
}.get(value, """
print ('None')
""")

Where value is the value. In C, this would be:

switch (value) {
    case 1:
        printf("one");
        break;
    case 2:
        printf("two");
        break;
    case 3:
        printf("three");
        break;
    default:
        printf("None");
        break;
}

We can also create a helper function to do this:

def switch(value, cases, default):
    exec cases.get(value, default)

So we can use it like this for the example with one, two and three:

switch(value, {
    1: """
print ('one')
    """, 
    2: """
print ('two')
    """, 
    3: """
print ('three')
    """,
}, """
print ('None')
""")

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.


你可以使用字典:

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

如果你想使用默認值,你可以使用字典get(key[, default])方法:

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

如果你有一個複雜的case塊,你可以考慮使用函數字典查找表...

如果你還沒有完成這個任務,那麼先進入你的調試器並仔細查看字典是如何查找每個函數的。

注意:不要在case / dictionary查找中使用“()”,或者在字典/大小寫塊被創建時調用每個函數。 請記住這一點,因為您只想使用哈希樣式查找來調用每個函數。

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

定義:

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

我一直試圖重新定義開關,以便讓我擺脫“lambda:”,但放棄了。 調整定義:

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

每個複制的案例都必須在自己的字典中; switch()在查找值之前合併字典。 它仍然比我想要的更醜,但它具有在表達式上使用散列查找的基本效率,而不是遍歷所有鍵的循環。


我一直喜歡這樣做

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

從這裡


我只是在這裡放下我的兩分錢。 在Python中沒有case / switch語句的原因是因為Python遵循'Theres只有一個正確的方式來做事'的原則。 所以顯然你可以想出各種重新創建開關/外殼功能的方式,但實現這一點的Pythonic方法是if / elif結構。 即

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

我只是覺得PEP 8值得在這裡點頭。 Python的優點之一就是其簡單和優雅。 這大部分來自於PEP 8中的原則,包括“只有一個正確的方法去做某件事”


我喜歡Mark Bies的回答

由於x變量必須使用兩次,所以我將lambda函數修改為無參數。

我必須運行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 switch ; case else


我最喜歡的是一個非常好的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!"

我最喜歡的開關/案例Python配方是:

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

簡單和簡單的簡單方案。

與11行以上的C代碼比較:

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

你甚至可以通過使用元組來分配多個變量:

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

我為此做了一個(相對)靈活和可重用的解決方案。 可以在GitHub上找到它作為這個要點 。 如果開關函數的結果是可調用的,它會自動調用。


我發現一個普通的開關結構:

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

可以用Python表示如下:

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

python版本不是一個聲明,而是一個表達式,它的值是一個值。


擴大“字典作為切換”的想法。 如果您想為交換機使用默認值:

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

除了字典方法(我真的很喜歡,BTW)之外,還可以使用if-elif-else獲取開關/大小寫/默認功能:

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

這當然不同於開關/情況 - 你不能像脫離休息一樣容易地發生翻身事故; 聲明,但您可以進行更複雜的測試。 它的格式比一系列嵌套的ifs更好,儘管功能上更接近它。


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