# while 替代Python中的switch語句?

## python2 switch case (24)

# 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

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.

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

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)

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)

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'

class SMTP:
# ...

def do_UNKNOWN(self, rest):

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:

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

（原始方法也稱為state_COMMAND ，因為它使用相同的模式來實現狀態機，即getattr(self, 'state_' + self.mode)

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

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.

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

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

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)

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

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.

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.

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

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

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)

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

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

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

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'

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

For the sake of completeness, here are some of my attempts back in stone-age:

I especially enjoy the use of "3. Select values with 'range comparisons'"

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

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